aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/attr.rs8
-rw-r--r--components/script/dom/element.rs18
-rw-r--r--components/script/dom/mutationobserver.rs218
-rw-r--r--components/script/dom/mutationrecord.rs83
-rw-r--r--components/script/dom/node.rs14
-rw-r--r--components/script/dom/webidls/MutationObserver.webidl3
-rw-r--r--components/script/dom/webidls/MutationRecord.webidl18
-rw-r--r--components/script/microtask.rs5
-rw-r--r--components/script/script_thread.rs26
-rw-r--r--tests/unit/script/size_of.rs14
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini95
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini39
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini65
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini5
-rw-r--r--tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini1
15 files changed, 432 insertions, 180 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 3c775ffdf57..af5f0107ae4 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -10,6 +10,8 @@ use dom::bindings::js::{LayoutJS, MutNullableJS, Root, RootedReference};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::element::{AttributeMutation, Element};
+use dom::mutationobserver::{Mutation, MutationObserver};
+use dom::node::Node;
use dom::virtualmethods::vtable_for;
use dom::window::Window;
use dom_struct::dom_struct;
@@ -170,6 +172,12 @@ impl AttrMethods for Attr {
impl Attr {
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
+ let name = self.local_name().clone();
+ let namespace = self.namespace().clone();
+ let old_value = DOMString::from(&**self.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value };
+ MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
+
assert!(Some(owner) == self.owner().r());
owner.will_mutate_attr(self);
self.swap_value(&mut value);
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index aa32370127c..f38792a45b6 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -63,6 +63,7 @@ use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementLayoutHel
use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers};
use dom::htmltemplateelement::HTMLTemplateElement;
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
+use dom::mutationobserver::{Mutation, MutationObserver};
use dom::namednodemap::NamedNodeMap;
use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
@@ -1003,6 +1004,12 @@ impl Element {
}
pub fn push_attribute(&self, attr: &Attr) {
+ let name = attr.local_name().clone();
+ let namespace = attr.namespace().clone();
+ let old_value = DOMString::from(&**attr.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value };
+ MutationObserver::queue_a_mutation_record(&self.node, mutation);
+
assert!(attr.GetOwnerElement().r() == Some(self));
self.will_mutate_attr(attr);
self.attrs.borrow_mut().push(JS::from_ref(attr));
@@ -1125,13 +1132,18 @@ impl Element {
}
fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>>
- where F: Fn(&Attr) -> bool
- {
+ where F: Fn(&Attr) -> bool {
let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
-
idx.map(|idx| {
let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]);
self.will_mutate_attr(&attr);
+
+ let name = attr.local_name().clone();
+ let namespace = attr.namespace().clone();
+ let old_value = DOMString::from(&**attr.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value, };
+ MutationObserver::queue_a_mutation_record(&self.node, mutation);
+
self.attrs.borrow_mut().remove(idx);
attr.set_owner(None);
if attr.namespace() == &ns!() {
diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs
index 4dc745c1ce8..b174ae4d11f 100644
--- a/components/script/dom/mutationobserver.rs
+++ b/components/script/dom/mutationobserver.rs
@@ -2,13 +2,22 @@
* 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::callback::ExceptionHandling;
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::MutationObserverBinding;
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationCallback;
-use dom::bindings::error::Fallible;
-use dom::bindings::js::Root;
+use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverBinding::MutationObserverMethods;
+use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverInit;
+use dom::bindings::error::{Error, Fallible};
+use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::mutationrecord::MutationRecord;
+use dom::node::Node;
use dom::window::Window;
use dom_struct::dom_struct;
+use html5ever::{Namespace, LocalName};
+use microtask::Microtask;
use script_thread::ScriptThread;
use std::rc::Rc;
@@ -17,6 +26,29 @@ pub struct MutationObserver {
reflector_: Reflector,
#[ignore_heap_size_of = "can't measure Rc values"]
callback: Rc<MutationCallback>,
+ record_queue: DOMRefCell<Vec<Root<MutationRecord>>>,
+}
+
+#[derive(Clone)]
+pub enum Mutation {
+ Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }
+}
+
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct RegisteredObserver {
+ observer: Root<MutationObserver>,
+ options: ObserverOptions,
+}
+
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct ObserverOptions {
+ attribute_old_value: bool,
+ attributes: bool,
+ character_data: bool,
+ character_data_old_value: bool,
+ child_list: bool,
+ subtree: bool,
+ attribute_filter: Vec<DOMString>,
}
impl MutationObserver {
@@ -29,6 +61,7 @@ impl MutationObserver {
MutationObserver {
reflector_: Reflector::new(),
callback: callback,
+ record_queue: DOMRefCell::new(vec![]),
}
}
@@ -37,4 +70,185 @@ impl MutationObserver {
ScriptThread::add_mutation_observer(&*observer);
Ok(observer)
}
+
+ /// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
+ pub fn queue_mutation_observer_compound_microtask() {
+ // Step 1
+ if ScriptThread::is_mutation_observer_compound_microtask_queued() {
+ return;
+ }
+ // Step 2
+ ScriptThread::set_mutation_observer_compound_microtask_queued(true);
+ // Step 3
+ ScriptThread::enqueue_microtask(Microtask::NotifyMutationObservers);
+ }
+
+ /// https://dom.spec.whatwg.org/#notify-mutation-observers
+ pub fn notify_mutation_observers() {
+ // Step 1
+ ScriptThread::set_mutation_observer_compound_microtask_queued(false);
+ // Step 2
+ let notify_list = ScriptThread::get_mutation_observers();
+ // TODO: steps 3-4 (slots)
+ // Step 5
+ for mo in &notify_list {
+ let queue: Vec<Root<MutationRecord>> = mo.record_queue.borrow().clone();
+ mo.record_queue.borrow_mut().clear();
+ // TODO: Step 5.3 Remove all transient registered observers whose observer is mo.
+ if !queue.is_empty() {
+ let _ = mo.callback.Call_(&**mo, queue, &**mo, ExceptionHandling::Report);
+ }
+ }
+ // TODO: Step 6 (slot signals)
+ }
+
+ /// https://dom.spec.whatwg.org/#queueing-a-mutation-record
+ pub fn queue_a_mutation_record(target: &Node, attr_type: Mutation) {
+ // Step 1
+ let mut interestedObservers: Vec<(Root<MutationObserver>, Option<DOMString>)> = vec![];
+ // Step 2 & 3
+ for node in target.inclusive_ancestors() {
+ for registered in &*node.registered_mutation_observers() {
+ if &*node != target && !registered.options.subtree {
+ continue;
+ }
+
+ match attr_type {
+ Mutation::Attribute { ref name, ref namespace, ref old_value } => {
+ // Step 3.1
+ if !registered.options.attributes {
+ continue;
+ }
+ if !registered.options.attribute_filter.is_empty() {
+ if *namespace != ns!() {
+ continue;
+ }
+ if registered.options.attribute_filter.iter()
+ .find(|s| &**s == &**name).is_some() {
+ continue;
+ }
+ }
+ // Step 3.1.2
+ let paired_string = if registered.options.attribute_old_value {
+ Some(old_value.clone())
+ } else {
+ None
+ };
+ // Step 3.1.1
+ let idx = interestedObservers.iter().position(|&(ref o, _)|
+ &**o as *const _ == &*registered.observer as *const _);
+ if let Some(idx) = idx {
+ interestedObservers[idx].1 = paired_string;
+ } else {
+ interestedObservers.push((Root::from_ref(&*registered.observer),
+ paired_string));
+ }
+ }
+ }
+ }
+ }
+
+ // Step 4
+ for &(ref observer, ref paired_string) in &interestedObservers {
+ // Steps 4.1-4.7
+ let record = match attr_type {
+ Mutation::Attribute { ref name, ref namespace, .. } => {
+ let namespace = if *namespace != ns!() {
+ Some(namespace)
+ } else {
+ None
+ };
+ MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone())
+ }
+ };
+ // Step 4.8
+ observer.record_queue.borrow_mut().push(record);
+ }
+
+ // Step 5
+ MutationObserver::queue_mutation_observer_compound_microtask();
+ }
+
+}
+
+impl MutationObserverMethods for MutationObserver {
+ /// https://dom.spec.whatwg.org/#dom-mutationobserver-observe
+ fn Observe(&self, target: &Node, options: &MutationObserverInit) -> Fallible<()> {
+ let attribute_filter = options.attributeFilter.clone().unwrap_or(vec![]);
+ let attribute_old_value = options.attributeOldValue.unwrap_or(false);
+ let mut attributes = options.attributes.unwrap_or(false);
+ let mut character_data = options.characterData.unwrap_or(false);
+ let character_data_old_value = options.characterDataOldValue.unwrap_or(false);
+ let child_list = options.childList;
+ let subtree = options.subtree;
+
+ // Step 1
+ if (options.attributeOldValue.is_some() || options.attributeFilter.is_some()) &&
+ options.attributes.is_none() {
+ attributes = true;
+ }
+
+ // Step 2
+ if options.characterDataOldValue.is_some() && options.characterData.is_none() {
+ character_data = true;
+ }
+
+ // Step 3
+ if !child_list && !attributes && !character_data {
+ return Err(Error::Type("One of childList, attributes, or characterData must be true".into()));
+ }
+
+ // Step 4
+ if attribute_old_value && !attributes {
+ return Err(Error::Type("attributeOldValue is true but attributes is false".into()));
+ }
+
+ // Step 5
+ if options.attributeFilter.is_some() && !attributes {
+ return Err(Error::Type("attributeFilter is present but attributes is false".into()));
+ }
+
+ // Step 6
+ if character_data_old_value && !character_data {
+ return Err(Error::Type("characterDataOldValue is true but characterData is false".into()));
+ }
+
+ // Step 7
+ let add_new_observer = {
+ let mut replaced = false;
+ for registered in &mut *target.registered_mutation_observers() {
+ if &*registered.observer as *const MutationObserver != self as *const MutationObserver {
+ continue;
+ }
+ // TODO: remove matching transient registered observers
+ registered.options.attribute_old_value = attribute_old_value;
+ registered.options.attributes = attributes;
+ registered.options.character_data = character_data;
+ registered.options.character_data_old_value = character_data_old_value;
+ registered.options.child_list = child_list;
+ registered.options.subtree = subtree;
+ registered.options.attribute_filter = attribute_filter.clone();
+ replaced = true;
+ }
+ !replaced
+ };
+
+ // Step 8
+ if add_new_observer {
+ target.registered_mutation_observers().push(RegisteredObserver {
+ observer: Root::from_ref(self),
+ options: ObserverOptions {
+ attributes,
+ attribute_old_value,
+ character_data,
+ character_data_old_value,
+ subtree,
+ attribute_filter,
+ child_list
+ },
+ });
+ }
+
+ Ok(())
+ }
}
diff --git a/components/script/dom/mutationrecord.rs b/components/script/dom/mutationrecord.rs
index c39d61ef18a..439f4ae02b5 100644
--- a/components/script/dom/mutationrecord.rs
+++ b/components/script/dom/mutationrecord.rs
@@ -2,22 +2,54 @@
* 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::MutationRecordBinding::MutationRecordBinding;
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
use dom::bindings::js::{JS, Root};
-use dom::bindings::reflector::Reflector;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
-use dom::node::Node;
+use dom::node::{Node, window_from_node};
+use dom::nodelist::NodeList;
use dom_struct::dom_struct;
+use html5ever::{LocalName, Namespace};
#[dom_struct]
pub struct MutationRecord {
reflector_: Reflector,
-
- //property for record type
record_type: DOMString,
-
- //property for target node
target: JS<Node>,
+ attribute_name: Option<DOMString>,
+ attribute_namespace: Option<DOMString>,
+ old_value: Option<DOMString>,
+}
+
+impl MutationRecord {
+ #[allow(unrooted_must_root)]
+ pub fn attribute_mutated(target: &Node,
+ attribute_name: &LocalName,
+ attribute_namespace: Option<&Namespace>,
+ old_value: Option<DOMString>) -> Root<MutationRecord> {
+ let record = box MutationRecord::new_inherited("attributes",
+ target,
+ Some(DOMString::from(&**attribute_name)),
+ attribute_namespace.map(|n| DOMString::from(&**n)),
+ old_value);
+ reflect_dom_object(record, &*window_from_node(target), MutationRecordBinding::Wrap)
+ }
+
+ fn new_inherited(record_type: &str,
+ target: &Node,
+ attribute_name: Option<DOMString>,
+ attribute_namespace: Option<DOMString>,
+ old_value: Option<DOMString>) -> MutationRecord {
+ MutationRecord {
+ reflector_: Reflector::new(),
+ record_type: DOMString::from(record_type),
+ target: JS::from_ref(target),
+ attribute_name: attribute_name,
+ attribute_namespace: attribute_namespace,
+ old_value: old_value,
+ }
+ }
}
impl MutationRecordMethods for MutationRecord {
@@ -28,7 +60,44 @@ impl MutationRecordMethods for MutationRecord {
// https://dom.spec.whatwg.org/#dom-mutationrecord-target
fn Target(&self) -> Root<Node> {
- return Root::from_ref(&*self.target);
+ Root::from_ref(&*self.target)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-attributename
+ fn GetAttributeName(&self) -> Option<DOMString> {
+ self.attribute_name.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-attributenamespace
+ fn GetAttributeNamespace(&self) -> Option<DOMString> {
+ self.attribute_namespace.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-oldvalue
+ fn GetOldValue(&self) -> Option<DOMString> {
+ self.old_value.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
+ fn AddedNodes(&self) -> Root<NodeList> {
+ let window = window_from_node(&*self.target);
+ NodeList::empty(&window)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-removednodes
+ fn RemovedNodes(&self) -> Root<NodeList> {
+ let window = window_from_node(&*self.target);
+ NodeList::empty(&window)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
+ fn GetPreviousSibling(&self) -> Option<Root<Node>> {
+ None
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
+ fn GetNextSibling(&self) -> Option<Root<Node>> {
+ None
}
}
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 6d16cac6731..9d697bdcccf 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -7,6 +7,7 @@
use app_units::Au;
use devtools_traits::NodeInfo;
use document_loader::DocumentLoader;
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@@ -46,6 +47,7 @@ use dom::htmllinkelement::HTMLLinkElement;
use dom::htmlmetaelement::HTMLMetaElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
+use dom::mutationobserver::RegisteredObserver;
use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction;
use dom::range::WeakRangeVec;
@@ -72,7 +74,7 @@ use selectors::matching::matches_selector_list;
use selectors::parser::SelectorList;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
-use std::cell::{Cell, UnsafeCell};
+use std::cell::{Cell, UnsafeCell, RefMut};
use std::cmp::max;
use std::default::Default;
use std::iter;
@@ -138,6 +140,9 @@ pub struct Node {
/// node is finalized.
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
+ /// Registered observers for this node.
+ mutation_observers: DOMRefCell<Vec<RegisteredObserver>>,
+
unique_id: UniqueId,
}
@@ -363,6 +368,11 @@ impl Node {
}
}
+ /// Return all registered mutation observers for this node.
+ pub fn registered_mutation_observers(&self) -> RefMut<Vec<RegisteredObserver>> {
+ self.mutation_observers.borrow_mut()
+ }
+
/// Dumps the subtree rooted at this node, for debugging.
pub fn dump(&self) {
self.dump_indent(0);
@@ -1411,6 +1421,8 @@ impl Node {
style_and_layout_data: Cell::new(None),
+ mutation_observers: Default::default(),
+
unique_id: UniqueId::new(),
}
}
diff --git a/components/script/dom/webidls/MutationObserver.webidl b/components/script/dom/webidls/MutationObserver.webidl
index dbcfa945d4a..738c711d8e7 100644
--- a/components/script/dom/webidls/MutationObserver.webidl
+++ b/components/script/dom/webidls/MutationObserver.webidl
@@ -9,7 +9,8 @@
// https://dom.spec.whatwg.org/#mutationobserver
[Pref="dom.mutation_observer.enabled", Constructor(MutationCallback callback)]
interface MutationObserver {
- //void observe(Node target, optional MutationObserverInit options);
+ [Throws]
+ void observe(Node target, optional MutationObserverInit options);
//void disconnect();
//sequence<MutationRecord> takeRecords();
};
diff --git a/components/script/dom/webidls/MutationRecord.webidl b/components/script/dom/webidls/MutationRecord.webidl
index 286801bf2ab..1cd364091fc 100644
--- a/components/script/dom/webidls/MutationRecord.webidl
+++ b/components/script/dom/webidls/MutationRecord.webidl
@@ -12,13 +12,13 @@ interface MutationRecord {
readonly attribute DOMString type;
[SameObject]
readonly attribute Node target;
- //[SameObject]
- //readonly attribute NodeList addedNodes;
- //[SameObject]
- //readonly attribute NodeList removedNodes;
- //readonly attribute Node? previousSibling;
- //readonly attribute Node? nextSibling;
- //readonly attribute DOMString? attributeName;
- //readonly attribute DOMString? attributeNamespace;
- //readonly attribute DOMString? oldValue;
+ [SameObject]
+ readonly attribute NodeList addedNodes;
+ [SameObject]
+ readonly attribute NodeList removedNodes;
+ readonly attribute Node? previousSibling;
+ readonly attribute Node? nextSibling;
+ readonly attribute DOMString? attributeName;
+ readonly attribute DOMString? attributeNamespace;
+ readonly attribute DOMString? oldValue;
};
diff --git a/components/script/microtask.rs b/components/script/microtask.rs
index da04d1ed6ab..7fadf111ddb 100644
--- a/components/script/microtask.rs
+++ b/components/script/microtask.rs
@@ -11,6 +11,7 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
use dom::bindings::js::Root;
use dom::globalscope::GlobalScope;
+use dom::mutationobserver::MutationObserver;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::mem;
@@ -28,6 +29,7 @@ pub struct MicrotaskQueue {
#[derive(JSTraceable, HeapSizeOf)]
pub enum Microtask {
Promise(EnqueuedPromiseCallback),
+ NotifyMutationObservers,
}
/// A promise callback scheduled to run during the next microtask checkpoint (#4283).
@@ -71,6 +73,9 @@ impl MicrotaskQueue {
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
}
}
+ Microtask::NotifyMutationObservers => {
+ MutationObserver::notify_mutation_observers();
+ }
}
}
}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index b817fc77d1d..811fc67d212 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -479,6 +479,9 @@ pub struct ScriptThread {
microtask_queue: MicrotaskQueue,
+ /// Microtask Queue for adding support for mutation observer microtasks
+ mutation_observer_compound_microtask_queued: Cell<bool>,
+
/// The unit of related similar-origin browsing contexts' list of MutationObserver objects
mutation_observers: DOMRefCell<Vec<JS<MutationObserver>>>,
@@ -587,6 +590,20 @@ impl ScriptThread {
})
}
+ pub fn set_mutation_observer_compound_microtask_queued(value: bool) {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread.mutation_observer_compound_microtask_queued.set(value);
+ })
+ }
+
+ pub fn is_mutation_observer_compound_microtask_queued() -> bool {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ return script_thread.mutation_observer_compound_microtask_queued.get();
+ })
+ }
+
pub fn add_mutation_observer(observer: &MutationObserver) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
@@ -596,6 +613,13 @@ impl ScriptThread {
})
}
+ pub fn get_mutation_observers() -> Vec<Root<MutationObserver>> {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread.mutation_observers.borrow().iter().map(|o| Root::from_ref(&**o)).collect()
+ })
+ }
+
pub fn mark_document_with_no_blocked_loads(doc: &Document) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
@@ -748,6 +772,8 @@ impl ScriptThread {
microtask_queue: MicrotaskQueue::default(),
+ mutation_observer_compound_microtask_queued: Default::default(),
+
mutation_observers: Default::default(),
layout_to_constellation_chan: state.layout_to_constellation_chan,
diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs
index a328bcbf6f5..3368271d8e1 100644
--- a/tests/unit/script/size_of.rs
+++ b/tests/unit/script/size_of.rs
@@ -30,13 +30,13 @@ macro_rules! sizeof_checker (
// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
-sizeof_checker!(size_node, Node, 152);
-sizeof_checker!(size_element, Element, 320);
-sizeof_checker!(size_htmlelement, HTMLElement, 336);
-sizeof_checker!(size_div, HTMLDivElement, 336);
-sizeof_checker!(size_span, HTMLSpanElement, 336);
-sizeof_checker!(size_text, Text, 184);
-sizeof_checker!(size_characterdata, CharacterData, 184);
+sizeof_checker!(size_node, Node, 184);
+sizeof_checker!(size_element, Element, 352);
+sizeof_checker!(size_htmlelement, HTMLElement, 368);
+sizeof_checker!(size_div, HTMLDivElement, 368);
+sizeof_checker!(size_span, HTMLSpanElement, 368);
+sizeof_checker!(size_text, Text, 216);
+sizeof_checker!(size_characterdata, CharacterData, 216);
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
// We use these types in the parallel traversal. They should stay pointer-sized.
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
index 66e97c704e6..52a6a920412 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
@@ -1,114 +1,27 @@
[MutationObserver-attributes.html]
type: testharness
- [attributes Element.id: update, no oldValue, mutation]
- expected: FAIL
-
- [attributes Element.id: update mutation]
- expected: FAIL
-
- [attributes Element.id: empty string update mutation]
- expected: FAIL
-
[attributes Element.id: same value mutation]
expected: FAIL
- [attributes Element.unknown: IDL attribute no mutation]
- expected: FAIL
-
- [attributes HTMLInputElement.type: type update mutation]
- expected: FAIL
-
[attributes Element.className: new value mutation]
expected: FAIL
- [attributes Element.className: empty string update mutation]
- expected: FAIL
-
- [attributes Element.className: same value mutation]
- expected: FAIL
-
- [attributes Element.className: same multiple values mutation]
- expected: FAIL
-
[attributes Element.classList.add: single token addition mutation]
expected: FAIL
[attributes Element.classList.add: multiple tokens addition mutation]
expected: FAIL
- [attributes Element.classList.add: syntax err/no mutation]
- expected: FAIL
-
- [attributes Element.classList.add: invalid character/no mutation]
- expected: FAIL
-
- [attributes Element.classList.add: same value mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: single token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: multiple tokens removal mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: missing token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: token addition mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced missing token removal no mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced existing token addition no mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced token addition mutation]
- expected: FAIL
-
- [attributes Element.attributes.value: update mutation]
- expected: FAIL
-
- [attributes Element.attributes.value: same id mutation]
- expected: FAIL
-
- [attributes Element.setAttribute: id mutation]
- expected: FAIL
-
- [attributes Element.setAttribute: same class mutation]
- expected: FAIL
-
[attributes Element.setAttribute: classname mutation]
expected: FAIL
- [attributes Element.removeAttribute: removal mutation]
- expected: FAIL
-
- [attributes Element.removeAttribute: removal no mutation]
- expected: FAIL
-
- [childList HTMLInputElement.removeAttribute: type removal mutation]
- expected: FAIL
-
[attributes Element.setAttributeNS: creation mutation]
expected: FAIL
[attributes Element.setAttributeNS: prefixed attribute creation mutation]
expected: FAIL
- [attributes Element.removeAttributeNS: removal mutation]
- expected: FAIL
-
- [attributes Element.removeAttributeNS: removal no mutation]
- expected: FAIL
-
- [attributes Element.removeAttributeNS: prefixed attribute removal no mutation]
+ [attributes Element.className: empty string update mutation]
expected: FAIL
[attributes/attributeFilter Element.id/Element.className: update mutation]
@@ -117,12 +30,6 @@
[attributes/attributeFilter Element.id/Element.className: multiple filter update mutation]
expected: FAIL
- [attributeOldValue alone Element.id: update mutation]
- expected: FAIL
-
[attributeFilter alone Element.id/Element.className: multiple filter update mutation]
expected: FAIL
- [childList false: no childList mutation]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
index 37abce874dc..6e8512d76d9 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
@@ -1,59 +1,60 @@
[MutationObserver-characterData.html]
type: testharness
+ expected: TIMEOUT
[characterData Text.data: simple mutation without oldValue]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.data: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: null string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: null string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.deleteData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.deleteData: empty mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.replaceData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.replaceData: empty mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData ProcessingInstruction: data mutations]
- expected: FAIL
+ expected: TIMEOUT
[characterData Comment: data mutations]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.deleteContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.deleteContents: child and data removal mutation (2)]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.extractContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.extractContents: child and data removal mutation (2)]
- expected: FAIL
+ expected: TIMEOUT
[characterData/characterDataOldValue alone Text.data: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
index 7d5ce7fb070..91a99722ec5 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
@@ -1,95 +1,90 @@
[MutationObserver-childList.html]
type: testharness
- [childList Node.nodeValue: no mutation]
- expected: FAIL
-
+ expected: TIMEOUT
[childList Node.textContent: replace content mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.textContent: no previous content mutation]
- expected: FAIL
-
- [childList Node.textContent: textContent no mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.textContent: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.normalize mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.normalize mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: removal and addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: fragment addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: fragment removal mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: last child addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: removal and addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: fragment addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: fragment removal mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: addition outside document tree mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: internal replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.removeChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.deleteContents: child removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.deleteContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.extractContents: child removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.extractContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.insertNode: child insertion mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.insertNode: children insertion mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.surroundContents: children removal and addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: self internal replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
index cc46ef272e3..5c86ae99f38 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
@@ -1,11 +1,12 @@
[MutationObserver-inner-outer.html]
type: testharness
+ expected: TIMEOUT
[innerHTML mutation]
expected: FAIL
[innerHTML with 2 children mutation]
- expected: FAIL
+ expected: TIMEOUT
[outerHTML mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini b/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
index 3c4d9edc50f..829514a8656 100644
--- a/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
+++ b/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
@@ -2,3 +2,4 @@
type: testharness
[Adopting a node should make it same-origin-domain.]
expected: FAIL
+