Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions Libraries/LibWeb/Bindings/MainThreadVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ void queue_mutation_observer_microtask(DOM::Document const& document)
}
}

// 4. If records is not empty, then invoke mo’s callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception.
// 4. If records is not empty, then invoke mo’s callback with « records, mo » and "report", and with callback this value mo.
if (!records.is_empty()) {
auto& callback = mutation_observer->callback();
auto& realm = callback.callback_context;
Expand All @@ -751,9 +751,7 @@ void queue_mutation_observer_microtask(DOM::Document const& document)
MUST(wrapped_records->create_data_property(property_index, record.ptr()));
}

auto result = WebIDL::invoke_callback(callback, mutation_observer, wrapped_records, mutation_observer);
if (result.is_abrupt())
HTML::report_exception(result, realm);
(void)WebIDL::invoke_callback(callback, mutation_observer, WebIDL::ExceptionBehavior::Report, wrapped_records, mutation_observer);
}
}

Expand Down Expand Up @@ -827,12 +825,8 @@ void invoke_custom_element_reactions(Vector<GC::Root<DOM::Element>>& element_que
},
[&](DOM::CustomElementCallbackReaction& custom_element_callback_reaction) -> void {
// -> callback reaction
// Invoke reaction's callback function with reaction's arguments, and with element as the callback this value.
auto result = WebIDL::invoke_callback(*custom_element_callback_reaction.callback, element.ptr(), custom_element_callback_reaction.arguments);
// FIXME: The error from CustomElementCallbackReaction is supposed
// to use the new steps for IDL callback error reporting
if (result.is_abrupt())
HTML::report_exception(result, element->realm());
// Invoke reaction's callback function with reaction's arguments and "report", and callback this value set to element.
(void)WebIDL::invoke_callback(*custom_element_callback_reaction.callback, element.ptr(), WebIDL::ExceptionBehavior::Report, custom_element_callback_reaction.arguments);
});
}
}
Expand Down
5 changes: 2 additions & 3 deletions Libraries/LibWeb/DOM/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3983,9 +3983,8 @@ void Document::queue_intersection_observer_task()
auto& callback = observer->callback();

// 5. Invoke callback with queue as the first argument, observer as the second argument, and observer as the callback this value. If this throws an exception, report the exception.
auto completion = WebIDL::invoke_callback(callback, observer.ptr(), wrapped_queue, observer.ptr());
if (completion.is_abrupt())
HTML::report_exception(completion, realm);
// NOTE: This does not follow the spec as written precisely, but this is the same thing we do elsewhere and there is a WPT test that relies on this.
(void)WebIDL::invoke_callback(callback, observer.ptr(), WebIDL::ExceptionBehavior::Report, wrapped_queue, observer.ptr());
}
}));
}
Expand Down
4 changes: 2 additions & 2 deletions Libraries/LibWeb/HTML/HTMLCanvasElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ WebIDL::ExceptionOr<void> HTMLCanvasElement::to_blob(GC::Ref<WebIDL::CallbackTyp
if (file_result.has_value())
blob_result = FileAPI::Blob::create(realm(), file_result->buffer, TRY_OR_THROW_OOM(vm(), String::from_utf8(file_result->mime_type)));

// 2. Invoke callback with « result ».
TRY(WebIDL::invoke_callback(*callback, {}, move(blob_result)));
// 2. Invoke callback with « result » and "report".
TRY(WebIDL::invoke_callback(*callback, {}, WebIDL::ExceptionBehavior::Report, move(blob_result)));
return {};
});
if (maybe_error.is_throw_completion())
Expand Down
8 changes: 3 additions & 5 deletions Libraries/LibWeb/HTML/UniversalGlobalScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,9 @@ void UniversalGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callback)
if (is<Window>(this_impl()))
document = &static_cast<Window&>(this_impl()).associated_document();

// The queueMicrotask(callback) method must queue a microtask to invoke callback, and if callback throws an exception, report the exception.
HTML::queue_a_microtask(document, GC::create_function(realm.heap(), [&callback, &realm] {
auto result = WebIDL::invoke_callback(callback, {});
if (result.is_error())
HTML::report_exception(result, realm);
// The queueMicrotask(callback) method must queue a microtask to invoke callback with « » and "report".
HTML::queue_a_microtask(document, GC::create_function(realm.heap(), [&callback] {
(void)WebIDL::invoke_callback(callback, {}, WebIDL::ExceptionBehavior::Report);
}));
}

Expand Down
77 changes: 50 additions & 27 deletions Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
{
// 1. Let thisArg be global if that is a WorkerGlobalScope object; otherwise let thisArg be the WindowProxy that corresponds to global.

// 2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of active timers.
// 2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of setTimeout and setInterval IDs.
auto id = previous_id.has_value() ? previous_id.value() : m_timer_id_allocator.allocate();

// FIXME: 3. If the surrounding agent's event loop's currently running task is a task that was created by this algorithm, then let nesting level be the task's timer nesting level. Otherwise, let nesting level be zero.
Expand All @@ -268,42 +268,60 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
timeout = 0;

// FIXME: 5. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.

// 6. Let callerRealm be the current Realm Record, and calleeRealm be global's relevant Realm.
// FIXME: Implement this when step 9.3.2 is implemented.
// FIXME: 6. Let realm be global's relevant realm.

// 7. Let initiating script be the active script.
auto const* initiating_script = Web::Bindings::active_script();

auto& vm = this_impl().vm();

// 8. Let task be a task that runs the following substeps:
auto task = GC::create_function(vm.heap(), Function<void()>([this, handler = move(handler), timeout, arguments = move(arguments), repeat, id, initiating_script]() {
// 1. If id does not exist in global's map of active timers, then abort these steps.
// FIXME 8. Let uniqueHandle be null.

// 9. Let task be a task that runs the following substeps:
auto task = GC::create_function(vm.heap(), Function<void()>([this, handler = move(handler), timeout, arguments = move(arguments), repeat, id, initiating_script, previous_id]() {
// FIXME: 1. Assert: uniqueHandle is a unique internal value, not null.

// 2. If id does not exist in global's map of setTimeout and setInterval IDs, then abort these steps.
if (!m_timers.contains(id))
return;

// FIXME: 3. If global's map of setTimeout and setInterval IDs[id] does not equal uniqueHandle, then abort these steps.
// FIXME: 4. Record timing info for timer handler given handler, global's relevant settings object, and repeat.

handler.visit(
// 2. If handler is a Function, then invoke handler given arguments with the callback this value set to thisArg. If this throws an exception, catch it, and report the exception.
// 5. If handler is a Function, then invoke handler given arguments and "report", and with callback this value set to thisArg.
[&](GC::Root<WebIDL::CallbackType> const& callback) {
if (auto result = WebIDL::invoke_callback(*callback, &this_impl(), arguments); result.is_error())
report_exception(result, this_impl().realm());
(void)WebIDL::invoke_callback(*callback, &this_impl(), WebIDL::ExceptionBehavior::Report, arguments);
},
// 3. Otherwise:
// 6. Otherwise:
[&](String const& source) {
// 1. Assert: handler is a string.
// FIXME: 2. Perform HostEnsureCanCompileStrings(callerRealm, calleeRealm). If this throws an exception, catch it, report the exception, and abort these steps.
// 1. If previousId was not given:
if (!previous_id.has_value()) {
// 1. Let globalName be "Window" if global is a Window object; "Worker" otherwise.
auto global_name = is<Window>(this_impl()) ? "Window"sv : "Worker"sv;

// 2. Let methodName be "setInterval" if repeat is true; "setTimeout" otherwise.
auto method_name = repeat == Repeat::Yes ? "setInterval"sv : "setTimeout"sv;

// 3. Let sink be a concatenation of globalName, U+0020 SPACE, and methodName.
[[maybe_unused]] auto sink = String::formatted("{} {}", global_name, method_name);

// 3. Let settings object be global's relevant settings object.
// FIXME: 4. Set handler to the result of invoking the Get Trusted Type compliant string algorithm with TrustedScript, global, handler, sink, and "script".
}

// FIXME: 2. Assert: handler is a string.
// FIXME: 3. Perform EnsureCSPDoesNotBlockStringCompilation(realm, « », handler, handler, timer, « », handler). If this throws an exception, catch it, report it for global, and abort these steps.

// 4. Let settings object be global's relevant settings object.
auto& settings_object = relevant_settings_object(this_impl());

// 4. Let fetch options be the default classic script fetch options.
// 5. Let fetch options be the default classic script fetch options.
ScriptFetchOptions options {};

// 5. Let base URL be settings object's API base URL.
// 6. Let base URL be settings object's API base URL.
auto base_url = settings_object.api_base_url();

// 6. If initiating script is not null, then:
// 7. If initiating script is not null, then:
if (initiating_script) {
// FIXME: 1. Set fetch options to a script fetch options whose cryptographic nonce is initiating script's fetch options's cryptographic nonce,
// integrity metadata is the empty string, parser metadata is "not-parser-inserted", credentials mode is initiating script's fetch
Expand All @@ -316,47 +334,52 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
// done by eval(). That is, module script fetches via import() will behave the same in both contexts.
}

// 7. Let script be the result of creating a classic script given handler, realm, base URL, and fetch options.
// 8. Let script be the result of creating a classic script given handler, realm, base URL, and fetch options.
// FIXME: Pass fetch options.
auto basename = base_url.basename();
auto script = ClassicScript::create(basename, source, this_impl().realm(), move(base_url));

// 8. Run the classic script script.
// 9. Run the classic script script.
(void)script->run();
});

// 4. If id does not exist in global's map of active timers, then abort these steps.
// 7. If id does not exist in global's map of setTimeout and setInterval IDs, then abort these steps.
if (!m_timers.contains(id))
return;

// FIXME: 8. If global's map of setTimeout and setInterval IDs[id] does not equal uniqueHandle, then abort these steps.

switch (repeat) {
// 5. If repeat is true, then perform the timer initialization steps again, given global, handler, timeout, arguments, true, and id.
// 9. If repeat is true, then perform the timer initialization steps again, given global, handler, timeout, arguments, true, and id.
case Repeat::Yes:
run_timer_initialization_steps(handler, timeout, move(arguments), repeat, id);
break;

// 6. Otherwise, remove global's map of active timers[id].
// 10. Otherwise, remove global's map of active timers[id].
case Repeat::No:
m_timers.remove(id);
break;
}
}));

// FIXME: 9. Increment nesting level by one.
// FIXME: 10. Set task's timer nesting level to nesting level.
// FIXME: 10. Increment nesting level by one.
// FIXME: 11. Set task's timer nesting level to nesting level.

// 11. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
// 12. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
Function<void()> completion_step = [this, task = move(task)]() mutable {
queue_global_task(Task::Source::TimerTask, this_impl(), GC::create_function(this_impl().heap(), [this, task] {
HTML::TemporaryExecutionContext execution_context { this_impl().realm(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
task->function()();
}));
};

// 12. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id.
// 13. Set uniqueHandle to the result of running steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep.
// FIXME: run_steps_after_a_timeout() needs to be updated to return a unique internal value that can be used here.
run_steps_after_a_timeout_impl(timeout, move(completion_step), id);

// 13. Return id.
// FIXME: 14. Set global's map of setTimeout and setInterval IDs[id] to uniqueHandle.

// 15. Return id.
return id;
}

Expand Down
4 changes: 1 addition & 3 deletions Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,7 @@ void ResizeObserver::invoke_callback(ReadonlySpan<GC::Ref<ResizeObserverEntry>>
MUST(wrapped_records->create_data_property(property_index, record.ptr()));
}

auto result = WebIDL::invoke_callback(callback, JS::js_undefined(), wrapped_records);
if (result.is_abrupt())
HTML::report_exception(result, realm);
(void)WebIDL::invoke_callback(callback, JS::js_undefined(), WebIDL::ExceptionBehavior::Report, wrapped_records);
}

}
Loading