diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 2507f7bee35..97fd6591de8 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -36,6 +36,7 @@ pub struct HTMLStyleElement { cssom_stylesheet: MutNullableJS, /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts parser_inserted: Cell, + in_stack_of_open_elements: Cell, pending_loads: Cell, any_failed_load: Cell, } @@ -50,6 +51,7 @@ impl HTMLStyleElement { stylesheet: DOMRefCell::new(None), cssom_stylesheet: MutNullableJS::new(None), parser_inserted: Cell::new(creator == ElementCreator::ParserCreated), + in_stack_of_open_elements: Cell::new(creator == ElementCreator::ParserCreated), pending_loads: Cell::new(0), any_failed_load: Cell::new(false), } @@ -124,20 +126,38 @@ impl VirtualMethods for HTMLStyleElement { } fn children_changed(&self, mutation: &ChildrenMutation) { - if let Some(ref s) = self.super_type() { - s.children_changed(mutation); - } - if self.upcast::().is_in_doc() { + self.super_type().unwrap().children_changed(mutation); + + // https://html.spec.whatwg.org/multipage/#update-a-style-block + // Handles the case when: + // "The element is not on the stack of open elements of an HTML parser or XML parser, + // and one of its child nodes is modified by a script." + // TODO: Handle Text child contents being mutated. + if self.upcast::().is_in_doc() && !self.in_stack_of_open_elements.get() { self.parse_own_css(); } } fn bind_to_tree(&self, tree_in_doc: bool) { - if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); - } + self.super_type().unwrap().bind_to_tree(tree_in_doc); - if tree_in_doc { + // https://html.spec.whatwg.org/multipage/#update-a-style-block + // Handles the case when: + // "The element is not on the stack of open elements of an HTML parser or XML parser, + // and it becomes connected or disconnected." + if tree_in_doc && !self.in_stack_of_open_elements.get() { + self.parse_own_css(); + } + } + + fn pop(&self) { + self.super_type().unwrap().pop(); + + // https://html.spec.whatwg.org/multipage/#update-a-style-block + // Handles the case when: + // "The element is popped off the stack of open elements of an HTML parser or XML parser." + self.in_stack_of_open_elements.set(false); + if self.upcast::().is_in_doc() { self.parse_own_css(); } } diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 2582b13514a..c6fd4d6b170 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -425,6 +425,13 @@ impl VirtualMethods for HTMLTextAreaElement { } } } + + fn pop(&self) { + self.super_type().unwrap().pop(); + + // https://html.spec.whatwg.org/multipage/#the-textarea-element:stack-of-open-elements + self.reset(); + } } impl FormControl for HTMLTextAreaElement {} diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 28f8735891e..4a8f01d639e 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -20,6 +20,7 @@ use dom::htmltemplateelement::HTMLTemplateElement; use dom::node::Node; use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; +use dom::virtualmethods::vtable_for; use html5ever::Attribute; use html5ever::serialize::{AttrRef, Serializable, Serializer}; use html5ever::serialize::TraversalScope; @@ -124,7 +125,7 @@ struct Sink { document: JS, } -impl<'a> TreeSink for Sink { +impl TreeSink for Sink { type Output = Self; fn finish(self) -> Self { self } @@ -233,7 +234,11 @@ impl<'a> TreeSink for Sink { while let Some(ref child) = node.GetFirstChild() { new_parent.AppendChild(&child).unwrap(); } + } + fn pop(&mut self, node: JS) { + let node = Root::from_ref(&*node); + vtable_for(&node).pop(); } } @@ -243,10 +248,13 @@ fn insert(parent: &Node, reference_child: Option<&Node>, child: NodeOrText { - // FIXME(ajeffrey): convert directly from tendrils to DOMStrings - let s: String = t.into(); - let text = Text::new(DOMString::from(s), &parent.owner_doc()); - assert!(parent.InsertBefore(text.upcast(), reference_child).is_ok()); + if let Some(text) = parent.GetLastChild().and_then(Root::downcast::) { + text.upcast::().append_data(&t); + } else { + let s: String = t.into(); + let text = Text::new(DOMString::from(s), &parent.owner_doc()); + parent.InsertBefore(text.upcast(), reference_child).unwrap(); + } } } } diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs index 74b49fedd1c..6bab196d7ee 100644 --- a/components/script/dom/servoparser/xml.rs +++ b/components/script/dom/servoparser/xml.rs @@ -17,6 +17,7 @@ use dom::htmlscriptelement::HTMLScriptElement; use dom::node::Node; use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; +use dom::virtualmethods::vtable_for; use html5ever::tokenizer::buffer_queue::BufferQueue; use html5ever_atoms::{Prefix, QualName}; use js::jsapi::JSTracer; @@ -196,4 +197,9 @@ impl TreeSink for Sink { NextParserState::Continue } } + + fn pop(&mut self, node: Self::Handle) { + let node = Root::from_ref(&*node); + vtable_for(&node).pop(); + } } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index e10e48e8ab8..d6b77b31256 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -124,6 +124,14 @@ pub trait VirtualMethods { s.cloning_steps(copy, maybe_doc, clone_children); } } + + /// Called on an element when it is popped off the stack of open elements + /// of a parser. + fn pop(&self) { + if let Some(ref s) = self.super_type() { + s.pop(); + } + } } /// Obtain a VirtualMethods instance for a given Node-derived object. Any diff --git a/tests/wpt/metadata/XMLHttpRequest/open-url-javascript-window-2.htm.ini b/tests/wpt/metadata/XMLHttpRequest/open-url-javascript-window-2.htm.ini index f48486261eb..8f9dc0ea819 100644 --- a/tests/wpt/metadata/XMLHttpRequest/open-url-javascript-window-2.htm.ini +++ b/tests/wpt/metadata/XMLHttpRequest/open-url-javascript-window-2.htm.ini @@ -1,6 +1,6 @@ [open-url-javascript-window-2.htm] type: testharness expected: TIMEOUT - [XMLHttpRequest: open() - resolving URLs (javascript: ] + [XMLHttpRequest: open() - resolving URLs (javascript: