mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #20755 - CYBAI:unhandled-rejection, r=jdm
Implement unhandledrejection event --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #15412 - [x] There are tests for these changes <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20755) <!-- Reviewable:end -->
This commit is contained in:
commit
30d9962b70
71 changed files with 518 additions and 308 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -2026,7 +2026,7 @@ dependencies = [
|
|||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.20.0",
|
||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2227,20 +2227,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mozjs"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs_sys 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs_sys 0.61.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mozjs_sys"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bindgen 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3004,7 +3004,7 @@ dependencies = [
|
|||
"mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
"net_traits 0.0.1",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -4505,8 +4505,8 @@ dependencies = [
|
|||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f"
|
||||
"checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7"
|
||||
"checksum mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f85c1120b07d7a2acc9d1d62df1fe16f64162399448fb5307bf2bc3bd066c9"
|
||||
"checksum mozjs_sys 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff07b0f0a2371dc08d75d55371ca311be67e1fdfa6c146fc8ad154c340f70c9"
|
||||
"checksum mozjs 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bd0bdded611cb03c8ca638e0b663befe67eb7fbcb1fe2dfd25061656ee4ff365"
|
||||
"checksum mozjs_sys 0.61.1 (registry+https://github.com/rust-lang/crates.io-index)" = "070dd9dcd0be8b524fe4f6fcc791d56d630518652f98c2b152fdebe28eb71a5b"
|
||||
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
|
||||
"checksum muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "451a9a05d2a32c566c897835e0ea95cf79ed2fdfe957924045a1721a36c9980f"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
|
|
|
@ -86,6 +86,7 @@ time
|
|||
timeupdate
|
||||
toggle
|
||||
transitionend
|
||||
unhandledrejection
|
||||
unload
|
||||
url
|
||||
waiting
|
||||
|
|
|
@ -32,7 +32,7 @@ hashglobe = { path = "../hashglobe" }
|
|||
hyper = { version = "0.10", optional = true }
|
||||
hyper_serde = { version = "0.8", optional = true }
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"], optional = true}
|
||||
mozjs = { version = "0.9.0", optional = true }
|
||||
mozjs = { version = "0.9.3", optional = true }
|
||||
selectors = { path = "../selectors" }
|
||||
serde = { version = "1.0.27", optional = true }
|
||||
serde_bytes = { version = "0.10", optional = true }
|
||||
|
|
|
@ -68,7 +68,7 @@ metrics = {path = "../metrics"}
|
|||
mitochondria = "1.1.2"
|
||||
mime = "0.2.1"
|
||||
mime_guess = "1.8.0"
|
||||
mozjs = "0.9.0"
|
||||
mozjs = "0.9.3"
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
num-traits = "0.2"
|
||||
|
|
|
@ -6207,7 +6207,7 @@ class CGDictionary(CGThing):
|
|||
descriptorProvider,
|
||||
isMember="Dictionary",
|
||||
defaultValue=member.defaultValue,
|
||||
exceptionCode="return Err(());"))
|
||||
exceptionCode="return Err(());\n"))
|
||||
for member in dictionary.members]
|
||||
|
||||
def define(self):
|
||||
|
|
|
@ -30,6 +30,7 @@ use ipc_channel::ipc::IpcSender;
|
|||
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
|
||||
use js::glue::{IsWrapper, UnwrapObject};
|
||||
use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment};
|
||||
use js::jsapi::{Heap, HandleObject};
|
||||
use js::jsapi::{JSAutoCompartment, JSContext};
|
||||
use js::jsapi::JSObject;
|
||||
use js::panic::maybe_resume_unwind;
|
||||
|
@ -55,6 +56,7 @@ use std::sync::Arc;
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use task::TaskCanceller;
|
||||
use task_source::TaskSourceName;
|
||||
use task_source::dom_manipulation::DOMManipulationTaskSource;
|
||||
use task_source::file_reading::FileReadingTaskSource;
|
||||
use task_source::networking::NetworkingTaskSource;
|
||||
use task_source::performance_timeline::PerformanceTimelineTaskSource;
|
||||
|
@ -135,6 +137,23 @@ pub struct GlobalScope {
|
|||
|
||||
/// Vector storing references of all eventsources.
|
||||
event_source_tracker: DOMTracker<EventSource>,
|
||||
|
||||
/// Storage for watching rejected promises waiting for some client to
|
||||
/// consume their rejection.
|
||||
/// Promises in this list have been rejected in the last turn of the
|
||||
/// event loop without the rejection being handled.
|
||||
/// Note that this can contain nullptrs in place of promises removed because
|
||||
/// they're consumed before it'd be reported.
|
||||
///
|
||||
/// <https://html.spec.whatwg.org/multipage/#about-to-be-notified-rejected-promises-list>
|
||||
uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
|
||||
|
||||
/// Promises in this list have previously been reported as rejected
|
||||
/// (because they were in the above list), but the rejection was handled
|
||||
/// in the last turn of the event loop.
|
||||
///
|
||||
/// <https://html.spec.whatwg.org/multipage/#outstanding-rejected-promises-weak-set>
|
||||
consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
|
||||
}
|
||||
|
||||
impl GlobalScope {
|
||||
|
@ -169,6 +188,8 @@ impl GlobalScope {
|
|||
microtask_queue,
|
||||
list_auto_close_worker: Default::default(),
|
||||
event_source_tracker: DOMTracker::new(),
|
||||
uncaught_rejections: Default::default(),
|
||||
consumed_rejections: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,6 +251,39 @@ impl GlobalScope {
|
|||
GlobalScope::from_object(obj)
|
||||
}
|
||||
|
||||
pub fn add_uncaught_rejection(&self, rejection: HandleObject) {
|
||||
self.uncaught_rejections.borrow_mut().push(Heap::boxed(rejection.get()));
|
||||
}
|
||||
|
||||
pub fn remove_uncaught_rejection(&self, rejection: HandleObject) {
|
||||
let mut uncaught_rejections = self.uncaught_rejections.borrow_mut();
|
||||
|
||||
if let Some(index) = uncaught_rejections.iter().position(|promise| *promise == Heap::boxed(rejection.get())) {
|
||||
uncaught_rejections.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
|
||||
&self.uncaught_rejections
|
||||
}
|
||||
|
||||
pub fn add_consumed_rejection(&self, rejection: HandleObject) {
|
||||
self.consumed_rejections.borrow_mut().push(Heap::boxed(rejection.get()));
|
||||
}
|
||||
|
||||
pub fn remove_consumed_rejection(&self, rejection: HandleObject) {
|
||||
let mut consumed_rejections = self.consumed_rejections.borrow_mut();
|
||||
|
||||
if let Some(index) = consumed_rejections.iter().position(|promise| *promise == Heap::boxed(rejection.get())) {
|
||||
consumed_rejections.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
|
||||
&self.consumed_rejections
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn get_cx(&self) -> *mut JSContext {
|
||||
Runtime::get()
|
||||
}
|
||||
|
@ -586,7 +640,10 @@ impl GlobalScope {
|
|||
/// Perform a microtask checkpoint.
|
||||
pub fn perform_a_microtask_checkpoint(&self) {
|
||||
self.microtask_queue
|
||||
.checkpoint(|_| Some(DomRoot::from_ref(self)));
|
||||
.checkpoint(
|
||||
|_| Some(DomRoot::from_ref(self)),
|
||||
vec![DomRoot::from_ref(self)]
|
||||
);
|
||||
}
|
||||
|
||||
/// Enqueue a microtask for subsequent execution.
|
||||
|
@ -624,6 +681,16 @@ impl GlobalScope {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
|
||||
if let Some(window) = self.downcast::<Window>() {
|
||||
return window.dom_manipulation_task_source();
|
||||
}
|
||||
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
|
||||
return worker.dom_manipulation_task_source();
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// Channel to send messages to the file reading task source of
|
||||
/// this of this global scope.
|
||||
pub fn file_reading_task_source(&self) -> FileReadingTaskSource {
|
||||
|
|
|
@ -428,6 +428,7 @@ pub mod processinginstruction;
|
|||
pub mod progressevent;
|
||||
pub mod promise;
|
||||
pub mod promisenativehandler;
|
||||
pub mod promiserejectionevent;
|
||||
pub mod radionodelist;
|
||||
pub mod range;
|
||||
pub mod request;
|
||||
|
|
|
@ -93,7 +93,7 @@ impl Promise {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code, unrooted_must_root)]
|
||||
unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
|
||||
pub unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
|
||||
assert!(IsPromiseObject(obj));
|
||||
let promise = Promise {
|
||||
reflector: Reflector::new(),
|
||||
|
|
114
components/script/dom/promiserejectionevent.rs
Normal file
114
components/script/dom/promiserejectionevent.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use dom::bindings::codegen::Bindings::PromiseRejectionEventBinding;
|
||||
use dom::bindings::codegen::Bindings::PromiseRejectionEventBinding::PromiseRejectionEventMethods;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::bindings::root::DomRoot;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::bindings::trace::RootedTraceableBox;
|
||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::promise::Promise;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSContext};
|
||||
use js::jsval::JSVal;
|
||||
use js::rust::HandleValue;
|
||||
use servo_atoms::Atom;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct PromiseRejectionEvent {
|
||||
event: Event,
|
||||
#[ignore_malloc_size_of = "Rc"]
|
||||
promise: Rc<Promise>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-mozjs"]
|
||||
reason: Heap<JSVal>,
|
||||
}
|
||||
|
||||
impl PromiseRejectionEvent {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(promise: Rc<Promise>) -> Self {
|
||||
PromiseRejectionEvent {
|
||||
event: Event::new_inherited(),
|
||||
promise,
|
||||
reason: Heap::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
promise: Rc<Promise>,
|
||||
reason: HandleValue
|
||||
) -> DomRoot<Self> {
|
||||
let ev = reflect_dom_object(
|
||||
Box::new(PromiseRejectionEvent::new_inherited(promise)),
|
||||
global,
|
||||
PromiseRejectionEventBinding::Wrap
|
||||
);
|
||||
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(
|
||||
type_,
|
||||
bool::from(bubbles),
|
||||
bool::from(cancelable)
|
||||
);
|
||||
|
||||
ev.reason.set(reason.get());
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
type_: DOMString,
|
||||
init: RootedTraceableBox<PromiseRejectionEventBinding::PromiseRejectionEventInit>
|
||||
) -> Fallible<DomRoot<Self>> {
|
||||
let reason = init.reason.handle();
|
||||
let promise = match init.promise.as_ref() {
|
||||
Some(promise) => promise.clone(),
|
||||
None => Promise::new(global)
|
||||
};
|
||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||
|
||||
let event = PromiseRejectionEvent::new(
|
||||
global,
|
||||
Atom::from(type_),
|
||||
bubbles,
|
||||
cancelable,
|
||||
promise,
|
||||
reason
|
||||
);
|
||||
Ok(event)
|
||||
}
|
||||
}
|
||||
|
||||
impl PromiseRejectionEventMethods for PromiseRejectionEvent {
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-promise
|
||||
fn Promise(&self) -> Rc<Promise> {
|
||||
self.promise.clone()
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason
|
||||
unsafe fn Reason(&self, _cx: *mut JSContext) -> JSVal {
|
||||
self.reason.get()
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
16
components/script/dom/webidls/PromiseRejectionEvent.webidl
Normal file
16
components/script/dom/webidls/PromiseRejectionEvent.webidl
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#the-promiserejectionevent-interface
|
||||
|
||||
[Constructor(DOMString type, optional PromiseRejectionEventInit eventInitDict), Exposed=(Window,Worker)]
|
||||
interface PromiseRejectionEvent : Event {
|
||||
readonly attribute Promise<any> promise;
|
||||
readonly attribute any reason;
|
||||
};
|
||||
|
||||
dictionary PromiseRejectionEventInit : EventInit {
|
||||
/* required */ Promise<any> promise;
|
||||
any reason;
|
||||
};
|
|
@ -43,6 +43,7 @@ use std::rc::Rc;
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use task::TaskCanceller;
|
||||
use task_source::dom_manipulation::DOMManipulationTaskSource;
|
||||
use task_source::file_reading::FileReadingTaskSource;
|
||||
use task_source::networking::NetworkingTaskSource;
|
||||
use task_source::performance_timeline::PerformanceTimelineTaskSource;
|
||||
|
@ -419,6 +420,10 @@ impl WorkerGlobalScope {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
|
||||
DOMManipulationTaskSource(self.script_chan(), self.pipeline_id())
|
||||
}
|
||||
|
||||
pub fn file_reading_task_source(&self) -> FileReadingTaskSource {
|
||||
FileReadingTaskSource(self.script_chan(), self.pipeline_id())
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ use dom::htmlimageelement::ImageElementMicrotask;
|
|||
use dom::htmlmediaelement::MediaElementMicrotask;
|
||||
use dom::mutationobserver::MutationObserver;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use script_runtime::notify_about_rejected_promises;
|
||||
use script_thread::ScriptThread;
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
|
@ -59,7 +60,7 @@ impl MicrotaskQueue {
|
|||
|
||||
/// <https://html.spec.whatwg.org/multipage/#perform-a-microtask-checkpoint>
|
||||
/// Perform a microtask checkpoint, executing all queued microtasks until the queue is empty.
|
||||
pub fn checkpoint<F>(&self, target_provider: F)
|
||||
pub fn checkpoint<F>(&self, target_provider: F, globalscopes: Vec<DomRoot<GlobalScope>>)
|
||||
where
|
||||
F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>,
|
||||
{
|
||||
|
@ -70,7 +71,7 @@ impl MicrotaskQueue {
|
|||
// Step 1
|
||||
self.performing_a_microtask_checkpoint.set(true);
|
||||
|
||||
// Steps 2-7
|
||||
// Steps 2
|
||||
while !self.microtask_queue.borrow().is_empty() {
|
||||
rooted_vec!(let mut pending_queue);
|
||||
mem::swap(&mut *pending_queue, &mut *self.microtask_queue.borrow_mut());
|
||||
|
@ -98,9 +99,14 @@ impl MicrotaskQueue {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: Step 8 - notify about rejected promises
|
||||
// Step 3
|
||||
for global in globalscopes.into_iter() {
|
||||
notify_about_rejected_promises(&global);
|
||||
}
|
||||
|
||||
// Step 9
|
||||
// TODO: Step 4 - Cleanup Indexed Database transactions.
|
||||
|
||||
// Step 5
|
||||
self.performing_a_microtask_checkpoint.set(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,34 @@
|
|||
use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
|
||||
use dom::bindings::conversions::get_dom_class;
|
||||
use dom::bindings::conversions::private_from_object;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::refcounted::{LiveDOMReferences, trace_refcounted_objects};
|
||||
use dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use dom::bindings::reflector::DomObject;
|
||||
use dom::bindings::root::trace_roots;
|
||||
use dom::bindings::settings_stack;
|
||||
use dom::bindings::trace::{JSTraceable, trace_traceables};
|
||||
use dom::bindings::utils::DOM_CALLBACKS;
|
||||
use dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::promise::Promise;
|
||||
use dom::promiserejectionevent::PromiseRejectionEvent;
|
||||
use js::glue::CollectServoSizes;
|
||||
use js::glue::SetBuildId;
|
||||
use js::jsapi::{DisableIncrementalGC, GCDescription, GCProgress, HandleObject};
|
||||
use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress};
|
||||
use js::jsapi::{Heap, HandleObject};
|
||||
use js::jsapi::{JSContext, JSTracer, SetDOMCallbacks, SetGCSliceCallback};
|
||||
use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_SetGCCallback};
|
||||
use js::jsapi::{JSGCMode, JSGCParamKey, JS_SetGCParameter, JS_SetGlobalJitCompilerOption};
|
||||
use js::jsapi::{JSJitCompilerOption, JS_SetOffthreadIonCompilationEnabled, JS_SetParallelParsingEnabled};
|
||||
use js::jsapi::{JSObject, SetPreserveWrapperCallback, SetEnqueuePromiseJobCallback};
|
||||
use js::jsapi::{SetBuildIdOp, BuildIdCharVector};
|
||||
use js::jsapi::{JSObject, PromiseRejectionHandlingState, SetPreserveWrapperCallback};
|
||||
use js::jsapi::{SetBuildIdOp, SetEnqueuePromiseJobCallback, SetPromiseRejectionTrackerCallback};
|
||||
use js::jsapi::ContextOptionsRef;
|
||||
use js::panic::wrap_panic;
|
||||
use js::rust::Handle;
|
||||
use js::rust::Runtime as RustRuntime;
|
||||
use js::rust::wrappers::{GetPromiseIsHandled, GetPromiseResult};
|
||||
use malloc_size_of::MallocSizeOfOps;
|
||||
use microtask::{EnqueuedPromiseCallback, Microtask};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
|
@ -43,7 +53,7 @@ use std::panic::AssertUnwindSafe;
|
|||
use std::ptr;
|
||||
use style::thread_state::{self, ThreadState};
|
||||
use task::TaskBox;
|
||||
use task_source::TaskSourceName;
|
||||
use task_source::{TaskSource, TaskSourceName};
|
||||
use time::{Tm, now};
|
||||
|
||||
/// Common messages used to control the event loops in both the script and the worker
|
||||
|
@ -140,6 +150,122 @@ unsafe extern "C" fn enqueue_job(
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
/// https://html.spec.whatwg.org/multipage/#the-hostpromiserejectiontracker-implementation
|
||||
unsafe extern "C" fn promise_rejection_tracker(
|
||||
cx: *mut JSContext,
|
||||
promise: HandleObject,
|
||||
state: PromiseRejectionHandlingState,
|
||||
_data: *mut c_void
|
||||
) {
|
||||
// TODO: Step 2 - If script's muted errors is true, terminate these steps.
|
||||
|
||||
// Step 3.
|
||||
let global = GlobalScope::from_context(cx);
|
||||
|
||||
wrap_panic(AssertUnwindSafe(|| {
|
||||
match state {
|
||||
// Step 4.
|
||||
PromiseRejectionHandlingState::Unhandled => {
|
||||
global.add_uncaught_rejection(promise);
|
||||
},
|
||||
// Step 5.
|
||||
PromiseRejectionHandlingState::Handled => {
|
||||
// Step 5-1.
|
||||
if global.get_uncaught_rejections().borrow().contains(&Heap::boxed(promise.get())) {
|
||||
global.remove_uncaught_rejection(promise);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 5-2.
|
||||
if !global.get_consumed_rejections().borrow().contains(&Heap::boxed(promise.get())) {
|
||||
global.add_consumed_rejection(promise);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 5-3.
|
||||
global.remove_consumed_rejection(promise);
|
||||
|
||||
// TODO: Step 5-4 - Queue a task to fire `rejectionhandled` event
|
||||
}
|
||||
};
|
||||
}), ());
|
||||
}
|
||||
|
||||
#[allow(unsafe_code, unrooted_must_root)]
|
||||
/// https://html.spec.whatwg.org/multipage/#notify-about-rejected-promises
|
||||
pub fn notify_about_rejected_promises(global: &GlobalScope) {
|
||||
unsafe {
|
||||
let cx = global.get_cx();
|
||||
|
||||
// Step 2.
|
||||
if global.get_uncaught_rejections().borrow().len() > 0 {
|
||||
// Step 1.
|
||||
let uncaught_rejections: Vec<TrustedPromise> = global.get_uncaught_rejections()
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|promise| {
|
||||
let promise = Promise::new_with_js_promise(Handle::from_raw(promise.handle()), cx);
|
||||
|
||||
TrustedPromise::new(promise)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Step 3.
|
||||
global.get_uncaught_rejections().borrow_mut().clear();
|
||||
|
||||
let target = Trusted::new(global.upcast::<EventTarget>());
|
||||
|
||||
// Step 4.
|
||||
global.dom_manipulation_task_source().queue(
|
||||
task!(unhandled_rejection_event: move || {
|
||||
let target = target.root();
|
||||
let cx = target.global().get_cx();
|
||||
|
||||
for promise in uncaught_rejections {
|
||||
let promise = promise.root();
|
||||
|
||||
// Step 4-1.
|
||||
let promise_is_handled = GetPromiseIsHandled(promise.reflector().get_jsobject());
|
||||
if promise_is_handled {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 4-2.
|
||||
rooted!(in(cx) let reason = GetPromiseResult(promise.reflector().get_jsobject()));
|
||||
|
||||
let event = PromiseRejectionEvent::new(
|
||||
&target.global(),
|
||||
atom!("unhandledrejection"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::Cancelable,
|
||||
promise,
|
||||
reason.handle()
|
||||
);
|
||||
|
||||
let event_status = event.upcast::<Event>().fire(&target);
|
||||
|
||||
// Step 4-3.
|
||||
if event_status == EventStatus::Canceled {
|
||||
// TODO: The promise rejection is not handled; we need to add it back to the list.
|
||||
}
|
||||
|
||||
// TODO: Step 4-4 - If [[PromiseIsHandled]] is false, add promise to consumed_rejections
|
||||
}
|
||||
}),
|
||||
global.upcast(),
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
if global.get_consumed_rejections().borrow().len() > 0 {
|
||||
// FIXME(cybai): Implement `rejectionhandled` event instead of clearing the whole
|
||||
// consumed rejections
|
||||
// https://html.spec.whatwg.org/multipage/#the-hostpromiserejectiontracker-implementation
|
||||
global.get_consumed_rejections().borrow_mut().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
pub struct Runtime(RustRuntime);
|
||||
|
||||
|
@ -182,6 +308,7 @@ pub unsafe fn new_rt_and_cx() -> Runtime {
|
|||
DisableIncrementalGC(cx);
|
||||
|
||||
SetEnqueuePromiseJobCallback(cx, Some(enqueue_job), ptr::null_mut());
|
||||
SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut());
|
||||
|
||||
set_gc_zeal_options(cx);
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ pub struct ScriptThread {
|
|||
/// events in the event queue.
|
||||
chan: MainThreadScriptChan,
|
||||
|
||||
dom_manipulation_task_sender: Sender<MainThreadScriptMsg>,
|
||||
dom_manipulation_task_sender: Box<ScriptChan>,
|
||||
|
||||
media_element_task_sender: Sender<MainThreadScriptMsg>,
|
||||
|
||||
|
@ -1020,7 +1020,7 @@ impl ScriptThread {
|
|||
task_queue,
|
||||
|
||||
chan: MainThreadScriptChan(chan.clone()),
|
||||
dom_manipulation_task_sender: chan.clone(),
|
||||
dom_manipulation_task_sender: boxed_script_sender.clone(),
|
||||
media_element_task_sender: chan.clone(),
|
||||
user_interaction_task_sender: chan.clone(),
|
||||
networking_task_sender: boxed_script_sender.clone(),
|
||||
|
@ -3200,8 +3200,16 @@ impl ScriptThread {
|
|||
}
|
||||
|
||||
fn perform_a_microtask_checkpoint(&self) {
|
||||
let globals = self.documents.borrow()
|
||||
.iter()
|
||||
.map(|(_id, document)| document.global())
|
||||
.collect();
|
||||
|
||||
self.microtask_queue
|
||||
.checkpoint(|id| self.documents.borrow().find_global(id))
|
||||
.checkpoint(
|
||||
|id| self.documents.borrow().find_global(id),
|
||||
globals
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,17 +8,21 @@ use dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask};
|
|||
use dom::eventtarget::EventTarget;
|
||||
use dom::window::Window;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
|
||||
use script_thread::MainThreadScriptMsg;
|
||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
|
||||
use servo_atoms::Atom;
|
||||
use servo_channel::Sender;
|
||||
use std::fmt;
|
||||
use std::result::Result;
|
||||
use task::{TaskCanceller, TaskOnce};
|
||||
use task_source::{TaskSource, TaskSourceName};
|
||||
|
||||
#[derive(Clone, JSTraceable)]
|
||||
pub struct DOMManipulationTaskSource(pub Sender<MainThreadScriptMsg>, pub PipelineId);
|
||||
#[derive(JSTraceable)]
|
||||
pub struct DOMManipulationTaskSource(pub Box<ScriptChan + Send>, pub PipelineId);
|
||||
|
||||
impl Clone for DOMManipulationTaskSource {
|
||||
fn clone(&self) -> DOMManipulationTaskSource {
|
||||
DOMManipulationTaskSource(self.0.clone(), self.1.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DOMManipulationTaskSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -33,13 +37,14 @@ impl TaskSource for DOMManipulationTaskSource {
|
|||
where
|
||||
T: TaskOnce + 'static,
|
||||
{
|
||||
let msg = MainThreadScriptMsg::Common(CommonScriptMsg::Task(
|
||||
let msg_task = CommonScriptMsg::Task(
|
||||
ScriptThreadEventCategory::ScriptEvent,
|
||||
Box::new(canceller.wrap_task(task)),
|
||||
Some(self.1),
|
||||
DOMManipulationTaskSource::NAME,
|
||||
));
|
||||
self.0.send(msg).map_err(|_| ())
|
||||
);
|
||||
|
||||
self.0.send(msg_task).map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[createImageBitmap-transfer.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
||||
[Transfer ImageBitmap created from an HTMLCanvasElement]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -613377,7 +613377,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/event_pause_noautoplay.html": [
|
||||
"55482348387de77def1c1be10d3dbe174fa3cb58",
|
||||
"8b985a65fe372346370075e3e9e992548e9b8abb",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/event_play.html": [
|
||||
|
@ -613385,7 +613385,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/event_play_noautoplay.html": [
|
||||
"67285a95abdca01fd7bc6dc95f4ad8c94b7f8536",
|
||||
"94fcb837d04c0f82da1660d95465b53bc8a052a6",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/event_playing.html": [
|
||||
|
@ -613685,7 +613685,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-set-src-networkState.html": [
|
||||
"e195dedb044e4040b5191538b753fe6d77bbefc1",
|
||||
"ed86dbe0c570f272f03d1e956b62ac7132830898",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-set-src-not-in-document.html": [
|
||||
|
@ -613785,7 +613785,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/paused_true_during_pause.html": [
|
||||
"6c4eb7c0c09fd2f048c96eff66d58b05ab3e4952",
|
||||
"2a9335bd4e6026ff1c029fb140c3b146474e3523",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html": [
|
||||
|
@ -613805,7 +613805,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html": [
|
||||
"9c6fd5fabc3d48e7f5a7220dfc5684471bd4c992",
|
||||
"8e9a7843b734f5e2296593f50daa76f98abacaad",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/playing-the-media-resource/playbackRate.html": [
|
||||
|
@ -664305,7 +664305,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html": [
|
||||
"01ba3b122d8c9b5e8107cfc1226bb697e2929645",
|
||||
"b7e6b93ac42f6dc8b9435447b2b4f78e70c2b597",
|
||||
"testharness"
|
||||
],
|
||||
"webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-one-sample-loop.html": [
|
||||
|
|
|
@ -6,15 +6,6 @@
|
|||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.https.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
@ -152,7 +143,6 @@
|
|||
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[backpressure.any.serviceworker.html]
|
||||
[backpressure]
|
||||
expected: FAIL
|
||||
|
||||
[backpressure.any.sharedworker.html]
|
||||
[backpressure]
|
||||
expected: FAIL
|
||||
|
@ -7,10 +11,6 @@
|
|||
[backpressure]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[backpressure.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
||||
[backpressure.any.worker.html]
|
||||
[backpressure]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[decode-attributes.any.serviceworker.html]
|
||||
[decode-attributes]
|
||||
expected: FAIL
|
||||
|
||||
[decode-attributes.any.worker.html]
|
||||
[a throwing fatal member should cause the constructor to throw]
|
||||
expected: FAIL
|
||||
|
@ -173,7 +177,3 @@
|
|||
|
||||
[encoding attribute should have correct value for 'ascii']
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[decode-attributes.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
[decode-bad-chunks]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[decode-bad-chunks.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-bad-chunks]
|
||||
expected: FAIL
|
||||
|
||||
[decode-bad-chunks.any.sharedworker.html]
|
||||
[decode-bad-chunks]
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
[ignoreBOM should work for encoding utf-16le, split at character 0]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[decode-ignore-bom.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-ignore-bom]
|
||||
expected: FAIL
|
||||
|
||||
[decode-ignore-bom.any.sharedworker.html]
|
||||
[decode-ignore-bom]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[decode-incomplete-input.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-incomplete-input]
|
||||
expected: FAIL
|
||||
|
||||
[decode-incomplete-input.any.sharedworker.html]
|
||||
[decode-incomplete-input]
|
||||
|
|
|
@ -68,4 +68,5 @@
|
|||
|
||||
|
||||
[decode-non-utf8.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-non-utf8]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[decode-split-character.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-split-character]
|
||||
expected: FAIL
|
||||
|
||||
[decode-split-character.any.sharedworker.html]
|
||||
[decode-split-character]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[decode-utf8.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[decode-utf8]
|
||||
expected: FAIL
|
||||
|
||||
[decode-utf8.any.sharedworker.html]
|
||||
[decode-utf8]
|
||||
|
|
|
@ -42,6 +42,6 @@
|
|||
[encode-bad-chunks]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[encode-bad-chunks.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[encode-bad-chunks]
|
||||
expected: FAIL
|
||||
|
|
|
@ -120,6 +120,6 @@
|
|||
[encode-utf8]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[encode-utf8.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[encode-utf8]
|
||||
expected: FAIL
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
expected: FAIL
|
||||
|
||||
|
||||
[readable-writable-properties.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
||||
[readable-writable-properties.any.worker.html]
|
||||
[TextDecoderStream readable and writable properties must pass brand checks]
|
||||
expected: FAIL
|
||||
|
@ -16,6 +13,9 @@
|
|||
[TextEncoderStream readable and writable properties must pass brand checks]
|
||||
expected: FAIL
|
||||
|
||||
[readable-writable-properties.any.serviceworker.html]
|
||||
[readable-writable-properties]
|
||||
expected: FAIL
|
||||
|
||||
[readable-writable-properties.any.sharedworker.html]
|
||||
[readable-writable-properties]
|
||||
|
|
|
@ -203,6 +203,9 @@
|
|||
[Clone aborts with original controller]
|
||||
expected: FAIL
|
||||
|
||||
[general.any.serviceworker.html]
|
||||
[general]
|
||||
expected: FAIL
|
||||
|
||||
[general.https.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
@ -221,8 +224,3 @@
|
|||
expected: FAIL
|
||||
|
||||
|
||||
[general.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[general]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
|
||||
[header-value-combining.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[header-value-combining]
|
||||
expected: FAIL
|
||||
|
||||
[header-value-combining.any.sharedworker.html]
|
||||
[header-value-combining]
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
[header-value-null-byte.any.worker.html]
|
||||
|
||||
[header-value-null-byte.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[header-value-null-byte]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[stream-safe-creation.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[stream-safe-creation]
|
||||
expected: FAIL
|
||||
|
||||
[stream-safe-creation.any.sharedworker.html]
|
||||
[stream-safe-creation]
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
|
||||
|
||||
[idl.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[idl]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -44,4 +44,5 @@
|
|||
|
||||
|
||||
[request-init-stream.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[request-init-stream]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[response-consume.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
||||
[Consume response's body as arrayBuffer]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -27,3 +27,6 @@
|
|||
[Constructing a Response with a stream on which read() is called]
|
||||
expected: FAIL
|
||||
|
||||
[response-from-stream.any.serviceworker.html]
|
||||
[response-from-stream]
|
||||
expected: FAIL
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
[WorkerGlobalScope interface: self must inherit property "addressSpace" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[idlharness.tentative.any.serviceworker.html]
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
[idlharness.tentative.https.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
@ -26,10 +29,3 @@
|
|||
[idlharness.tentative.any.sharedworker.html]
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.tentative.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[fetch.any.serviceworker.html]
|
||||
[fetch]
|
||||
expected: FAIL
|
||||
|
||||
[fetch.any.html]
|
||||
[fetch]
|
||||
expected: FAIL
|
||||
|
@ -44,9 +48,6 @@
|
|||
expected: FAIL
|
||||
|
||||
|
||||
[fetch.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
||||
[fetch.any.sharedworker.html]
|
||||
[fetch]
|
||||
expected: FAIL
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
[Test default toJSON operation of Performance]
|
||||
expected: FAIL
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
[idlharness.any.sharedworker.html]
|
||||
[idlharness]
|
||||
|
@ -60,9 +63,3 @@
|
|||
[Test default toJSON operation of Performance]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[idlharness]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -5234,30 +5234,12 @@
|
|||
[ApplicationCache interface: window.applicationCache must inherit property "onobsolete" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface object length]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: attribute promise]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: attribute reason]
|
||||
expected: FAIL
|
||||
|
||||
[Navigator interface: attribute productSub]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -11045,30 +11027,12 @@
|
|||
[ApplicationCache interface: window.applicationCache must inherit property "onobsolete" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface object length]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: attribute promise]
|
||||
expected: FAIL
|
||||
|
||||
[PromiseRejectionEvent interface: attribute reason]
|
||||
expected: FAIL
|
||||
|
||||
[Navigator interface: attribute productSub]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -12,15 +12,9 @@
|
|||
[document.open() and tasks (marquee start)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[tasks without document.open() (Promise rejection)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[tasks without document.open() (marquee start)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[tasks without document.open() (canvas.toBlob())]
|
||||
expected: FAIL
|
||||
|
||||
[document.open() and tasks (Promise rejection)]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
[It rethrows exceptions]
|
||||
expected: FAIL
|
||||
|
||||
[queue-microtask-exceptions.any.serviceworker.html]
|
||||
[queue-microtask-exceptions]
|
||||
expected: FAIL
|
||||
|
||||
[queue-microtask-exceptions.https.any.serviceworker.html]
|
||||
[queue-microtask-exceptions]
|
||||
|
@ -17,9 +20,3 @@
|
|||
[It rethrows exceptions]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[queue-microtask-exceptions.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[queue-microtask-exceptions]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
[It interleaves with promises as expected]
|
||||
expected: FAIL
|
||||
|
||||
[queue-microtask.any.serviceworker.html]
|
||||
[queue-microtask]
|
||||
expected: FAIL
|
||||
|
||||
[queue-microtask.any.sharedworker.html]
|
||||
[queue-microtask]
|
||||
|
@ -41,10 +44,3 @@
|
|||
|
||||
[It interleaves with promises as expected]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[queue-microtask.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[queue-microtask]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +1,2 @@
|
|||
[allow-crossorigin.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Promise rejection event should be received for the cross-origin CORS script]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[disallow-crossorigin.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
||||
[Promise rejection event should be muted for cross-origin non-CORS script]
|
||||
expected: FAIL
|
|
@ -1,6 +1,2 @@
|
|||
[promise-rejection-events-attached-in-event.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Attaching a handler in unhandledrejection should not trigger rejectionhandled.]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,38 +1,7 @@
|
|||
[promise-rejection-events.dedicatedworker.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[unhandledrejection: from Promise.reject]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a synchronous rejection in new Promise]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a task-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler chained off of Promise.reject]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler chained off of a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler attached one microtask after a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from returning a Promise.reject-created rejection in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from returning a setTimeout-delayed rejection in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from Promise.reject, indirected through Promise.all]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
[no unhandledrejection/rejectionhandled: all inside a queued task, a rejection handler attached synchronously to a promise created from returning a Promise.reject-created promise in a fulfillment handler]
|
||||
expected: FAIL
|
||||
|
@ -55,6 +24,3 @@
|
|||
[delayed handling: a nested-postMessageTask after promise creation/rejection, plus many promise microtasks, is too late to attach a rejection handler]
|
||||
expected: FAIL
|
||||
|
||||
[mutationObserverMicrotask vs. postMessageTask ordering is not disturbed inside unhandledrejection events]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,60 +1,6 @@
|
|||
[promise-rejection-events.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[unhandledrejection: from Promise.reject]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a synchronous rejection in new Promise]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a task-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler chained off of Promise.reject]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler chained off of a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a rejection handler attached one microtask after a setTimeout-delayed rejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from returning a Promise.reject-created rejection in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from a throw in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from returning a setTimeout-delayed rejection in a fulfillment handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[unhandledrejection: from Promise.reject, indirected through Promise.all]
|
||||
expected: TIMEOUT
|
||||
|
||||
[delayed handling: a nested-task delay before attaching a handler causes unhandledrejection]
|
||||
expected: TIMEOUT
|
||||
|
||||
[delayed handling: a nested-postMessageTask after promise creation/rejection, plus promise microtasks, is too late to attach a rejection handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[delayed handling: a nested-postMessageTask before promise creation/rejection, plus many promise microtasks, is too late to attach a rejection handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[delayed handling: a nested-postMessageTask after promise creation/rejection, plus many promise microtasks, is too late to attach a rejection handler]
|
||||
expected: TIMEOUT
|
||||
|
||||
[mutationObserverMicrotask vs. postMessageTask ordering is not disturbed inside unhandledrejection events]
|
||||
expected: TIMEOUT
|
||||
|
||||
[postMessageTask ordering vs. the task queued for unhandled rejection notification (1)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[postMessageTask ordering vs. the task queued for unhandled rejection notification (2)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[rejectionhandled is dispatched from a queued task, and not immediately]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[identity-not-preserved.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[postMessaging to this window does not give back the same WebAssembly.Module]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -92,4 +92,5 @@
|
|||
|
||||
|
||||
[contenttype.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[contenttype]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[audiobuffersource-multi-channels.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[note-grain-on-play.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[X Number of start frames is not equal to 100. Got 1.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[note-grain-on-timing.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[X Number of start frames is not equal to 100. Got 1.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[audionode-disconnect.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
[audioworkletnode-output-channel-count.https.html]
|
||||
expected: TIMEOUT
|
||||
[\n Test the construction of AudioWorkletNode with real-time context\n ]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[panner-equalpower.html]
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[X Number of impulses found is not equal to 100. Got 0.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
[basic-auth]
|
||||
expected: FAIL
|
||||
|
||||
[basic-auth.any.serviceworker.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[basic-auth]
|
||||
expected: FAIL
|
||||
|
||||
[basic-auth.any.sharedworker.html]
|
||||
[Untitled]
|
||||
|
@ -24,9 +30,3 @@
|
|||
[HTTP basic authentication should work with WebSockets]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[basic-auth.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
[basic-auth]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[importscripts_mime.tentative.any.serviceworker.html]
|
||||
[importscripts_mime]
|
||||
expected: FAIL
|
||||
|
||||
[importscripts_mime.tentative.any.sharedworker.html]
|
||||
[importscripts_mime]
|
||||
expected: FAIL
|
||||
|
@ -39,7 +43,3 @@
|
|||
|
||||
[importScripts() requires scripty MIME types: text/plain is blocked.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[importscripts_mime.tentative.any.serviceworker.html]
|
||||
expected: TIMEOUT
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[name-property.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[Test the name property of shared and dedicated workers via the name constructor option]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
[The Path2D interface object should be exposed.]
|
||||
expected: FAIL
|
||||
|
||||
[The PromiseRejectionEvent interface object should be exposed.]
|
||||
expected: FAIL
|
||||
|
||||
[The BroadcastChannel interface object should be exposed.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -27038,7 +27038,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"mozilla/interfaces.html": [
|
||||
"8bbde3b46a8e9d5ead6f9a2bf372d9647ad059be",
|
||||
"9d262c595c6cbb624bc8acb9ef2ae26622154004",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/interfaces.js": [
|
||||
|
@ -27046,7 +27046,7 @@
|
|||
"support"
|
||||
],
|
||||
"mozilla/interfaces.worker.js": [
|
||||
"926ae2e1792ead1e4635688c3f65b21e8efdcfb2",
|
||||
"fbd6e92c097dea4f99924de219c9f6aa07a45282",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/invalid-this.html": [
|
||||
|
|
|
@ -189,6 +189,7 @@ test_interfaces([
|
|||
"PopStateEvent",
|
||||
"ProcessingInstruction",
|
||||
"ProgressEvent",
|
||||
"PromiseRejectionEvent",
|
||||
"RadioNodeList",
|
||||
"Range",
|
||||
"Request",
|
||||
|
|
|
@ -40,6 +40,7 @@ test_interfaces([
|
|||
"PerformanceObserverEntryList",
|
||||
"PerformancePaintTiming",
|
||||
"ProgressEvent",
|
||||
"PromiseRejectionEvent",
|
||||
"Request",
|
||||
"Response",
|
||||
"TextDecoder",
|
||||
|
|
|
@ -14,26 +14,28 @@
|
|||
</video>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var t = async_test("calling play() then pause() on non-autoplay audio should trigger pause event", {timeout:5000});
|
||||
promise_test(function(t) {
|
||||
var async_t = async_test("calling play() then pause() on non-autoplay audio should trigger pause event", {timeout:5000});
|
||||
var a = document.getElementById("a");
|
||||
a.addEventListener("pause", function() {
|
||||
t.done();
|
||||
async_t.done();
|
||||
}, false);
|
||||
a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
|
||||
a.play();
|
||||
var play_promise = a.play();
|
||||
a.pause();
|
||||
return promise_rejects(t, "AbortError", play_promise, "pause() should reject all pending play Promises");
|
||||
}, "audio events - pause");
|
||||
|
||||
test(function() {
|
||||
var t = async_test("calling play() then pause() on non-autoplay video should trigger pause event", {timeout:5000});
|
||||
promise_test(function(t) {
|
||||
var async_t = async_test("calling play() then pause() on non-autoplay video should trigger pause event", {timeout:5000});
|
||||
var v = document.getElementById("v");
|
||||
v.addEventListener("pause", function() {
|
||||
t.done();
|
||||
async_t.done();
|
||||
}, false);
|
||||
v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
|
||||
v.play();
|
||||
var play_promise = v.play()
|
||||
v.pause();
|
||||
return promise_rejects(t, "AbortError", play_promise, "pause() should reject all pending play Promises");
|
||||
}, "video events - pause");
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -14,26 +14,26 @@
|
|||
</video>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var t = async_test("calling play() on audio should trigger play event", {timeout:5000});
|
||||
promise_test(function(t) {
|
||||
var async_t = async_test("calling play() on audio should trigger play event", {timeout:5000});
|
||||
var a = document.getElementById("a");
|
||||
a.addEventListener("play", function() {
|
||||
t.done();
|
||||
a.addEventListener("play", async_t.step_func(function() {
|
||||
a.pause();
|
||||
}, false);
|
||||
async_t.done();
|
||||
}), false);
|
||||
a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
|
||||
a.play();
|
||||
return promise_rejects(t, "AbortError", a.play(), "pause() should reject all pending play Promises");
|
||||
}, "audio events - play");
|
||||
|
||||
test(function() {
|
||||
var t = async_test("calling play() on video should trigger play event", {timeout:5000});
|
||||
promise_test(function(t) {
|
||||
var async_t = async_test("calling play() on video should trigger play event", {timeout:5000});
|
||||
var v = document.getElementById("v");
|
||||
v.addEventListener("play", function() {
|
||||
t.done();
|
||||
v.addEventListener("play", async_t.step_func(function() {
|
||||
v.pause();
|
||||
}, false);
|
||||
async_t.done();
|
||||
}), false);
|
||||
v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
|
||||
v.play();
|
||||
return promise_rejects(t, "AbortError", v.play(), "pause() should reject all pending play Promises");
|
||||
}, "video events - play");
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<script>
|
||||
test(function(t) {
|
||||
var v = document.createElement('video');
|
||||
v.play(); // invokes resource selection and sets .paused to false
|
||||
v.play().catch(() => {}); // invokes resource selection and sets .paused to false
|
||||
assert_equals(v.networkState, v.NETWORK_NO_SOURCE, 'networkState');
|
||||
assert_false(v.paused, 'paused');
|
||||
v.setAttribute('src', ''); // invokes media load which sets .paused to true
|
||||
|
|
|
@ -21,10 +21,11 @@ test(function() {
|
|||
t.step(function() {
|
||||
assert_true(a.paused);
|
||||
});
|
||||
|
||||
t.done();
|
||||
}, false);
|
||||
a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
|
||||
a.play();
|
||||
a.play().catch(() => {});
|
||||
a.pause();
|
||||
}, "audio events - paused property");
|
||||
|
||||
|
@ -35,10 +36,11 @@ test(function() {
|
|||
t.step(function() {
|
||||
assert_true(v.paused);
|
||||
});
|
||||
|
||||
t.done();
|
||||
}, false);
|
||||
v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
|
||||
v.play();
|
||||
v.play().catch(() => {});
|
||||
v.pause();
|
||||
}, "video events - paused property");
|
||||
</script>
|
||||
|
|
|
@ -12,7 +12,8 @@ async_test(function(t)
|
|||
var v = doc.createElement("video");
|
||||
doc.body.appendChild(v);
|
||||
v.src = getVideoURI("/media/movie_5");
|
||||
v.play();
|
||||
v.play().catch(() => {});
|
||||
|
||||
v.addEventListener("timeupdate", t.step_func(function() {
|
||||
assert_false(v.paused);
|
||||
if (v.currentTime > 0) {
|
||||
|
|
|
@ -27,17 +27,17 @@ Test AudioBufferSourceNode supports 5.1 channel.
|
|||
6, sampleRate * toneLengthSeconds, sampleRate);
|
||||
}, 'Creating context for testing').notThrow();
|
||||
should(
|
||||
Audit
|
||||
.loadFileFromUrl(
|
||||
'audiobuffersource-multi-channels-expected.wav')
|
||||
.then(arrayBuffer => {
|
||||
context.decodeAudioData(arrayBuffer).then(audioBuffer => {
|
||||
expectedAudio = audioBuffer;
|
||||
task.done();
|
||||
});
|
||||
}),
|
||||
'Fetching expected audio')
|
||||
.beResolved();
|
||||
Audit
|
||||
.loadFileFromUrl('audiobuffersource-multi-channels-expected.wav')
|
||||
.then(arrayBuffer => {
|
||||
context.decodeAudioData(arrayBuffer).then(audioBuffer => {
|
||||
expectedAudio = audioBuffer;
|
||||
task.done();
|
||||
}).catch(error => {
|
||||
assert_unreached("Could not decode audio data due to " + error.message);
|
||||
})
|
||||
})
|
||||
, 'Fetching expected audio').beResolved();
|
||||
});
|
||||
|
||||
audit.define(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue