diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index bcf7a551cf7..a728ab4f364 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -6,8 +6,7 @@ use dom::bindings::error::{report_pending_exception, throw_dom_exception}; use dom::bindings::js::Root; use dom::bindings::reflector::DomObject; use dom::document::Document; -use dom::element::Element; -use dom::element::ElementCreator; +use dom::element::{CustomElementCreationMode, Element, ElementCreator}; use dom::globalscope::GlobalScope; use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlappletelement::HTMLAppletElement; @@ -116,7 +115,8 @@ fn create_html_element(name: QualName, prefix: Option, is: Option, document: &Document, - creator: ElementCreator) + creator: ElementCreator, + mode: CustomElementCreationMode) -> Root { assert!(name.ns == ns!(html)); @@ -125,24 +125,31 @@ fn create_html_element(name: QualName, if let Some(definition) = definition { if definition.is_autonomous() { - let local_name = name.local.clone(); - return match definition.create_element(document) { - Ok(element) => element, - Err(error) => { - // Step 6. Recovering from exception. - let global = GlobalScope::current().unwrap_or_else(|| document.global()); + match mode { + // TODO: Handle asynchronous CE creation. Relies on CE upgrades. + CustomElementCreationMode::Asynchronous => {}, + CustomElementCreationMode::Synchronous => { + let local_name = name.local.clone(); + return match definition.create_element(document) { + Ok(element) => element, + Err(error) => { + // Step 6. Recovering from exception. + let global = GlobalScope::current().unwrap_or_else(|| document.global()); + let cx = global.get_cx(); - // Step 6.1.1 - unsafe { - let _ac = JSAutoCompartment::new(global.get_cx(), global.reflector().get_jsobject().get()); - throw_dom_exception(global.get_cx(), &global, error); - report_pending_exception(global.get_cx(), true); - } + // Step 6.1.1 + unsafe { + let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get()); + throw_dom_exception(cx, &global, error); + report_pending_exception(cx, true); + } - // Step 6.1.2 - Root::upcast(HTMLUnknownElement::new(local_name, prefix, document)) + // Step 6.1.2 + Root::upcast(HTMLUnknownElement::new(local_name, prefix, document)) + }, + }; }, - }; + } } else { let element = create_native_html_element(name, prefix, document, creator); element.set_is(definition.name.clone()); @@ -323,11 +330,12 @@ pub fn create_native_html_element(name: QualName, pub fn create_element(name: QualName, is: Option, document: &Document, - creator: ElementCreator) + creator: ElementCreator, + mode: CustomElementCreationMode) -> Root { let prefix = name.prefix.clone(); match name.ns { - ns!(html) => create_html_element(name, prefix, is, document, creator), + ns!(html) => create_html_element(name, prefix, is, document, creator, mode), ns!(svg) => create_svg_element(name, prefix, document), _ => Element::new(name.local, name.ns, prefix, document) } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 74189c13bbd..60d4f52ef6b 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -42,6 +42,7 @@ use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::domimplementation::DOMImplementation; use dom::element::{Element, ElementCreator, ElementPerformFullscreenEnter, ElementPerformFullscreenExit}; +use dom::element::CustomElementCreationMode; use dom::errorevent::ErrorEvent; use dom::event::{Event, EventBubbles, EventCancelable, EventDefault, EventStatus}; use dom::eventtarget::EventTarget; @@ -2854,7 +2855,7 @@ impl DocumentMethods for Document { let name = QualName::new(None, ns, LocalName::from(local_name)); let is = options.is.as_ref().map(|is| LocalName::from(&**is)); - Ok(Element::create(name, is, self, ElementCreator::ScriptCreated)) + Ok(Element::create(name, is, self, ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous)) } // https://dom.spec.whatwg.org/#dom-document-createelementns @@ -2867,7 +2868,7 @@ impl DocumentMethods for Document { &qualified_name)?; let name = QualName::new(prefix, namespace, local_name); let is = options.is.as_ref().map(|is| LocalName::from(&**is)); - Ok(Element::create(name, is, self, ElementCreator::ScriptCreated)) + Ok(Element::create(name, is, self, ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous)) } // https://dom.spec.whatwg.org/#dom-document-createattribute @@ -3121,7 +3122,11 @@ impl DocumentMethods for Document { Some(elem) => Root::upcast::(elem), None => { let name = QualName::new(None, ns!(svg), local_name!("title")); - let elem = Element::create(name, None, self, ElementCreator::ScriptCreated); + let elem = Element::create(name, + None, + self, + ElementCreator::ScriptCreated, + CustomElementCreationMode::Synchronous); let parent = root.upcast::(); let child = elem.upcast::(); parent.InsertBefore(child, parent.GetFirstChild().r()) @@ -3141,7 +3146,8 @@ impl DocumentMethods for Document { let elem = Element::create(name, None, self, - ElementCreator::ScriptCreated); + ElementCreator::ScriptCreated, + CustomElementCreationMode::Synchronous); head.upcast::() .AppendChild(elem.upcast()) .unwrap() diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 858f17c002b..be54c3e5119 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -165,6 +165,11 @@ pub enum ElementCreator { ScriptCreated, } +pub enum CustomElementCreationMode { + Synchronous, + Asynchronous, +} + impl ElementCreator { pub fn is_parser_created(&self) -> bool { match *self { @@ -208,9 +213,10 @@ impl Element { pub fn create(name: QualName, is: Option, document: &Document, - creator: ElementCreator) + creator: ElementCreator, + mode: CustomElementCreationMode) -> Root { - create_element(name, is, document, creator) + create_element(name, is, document, creator, mode) } pub fn new_inherited(local_name: LocalName, @@ -1984,7 +1990,8 @@ impl ElementMethods for Element { let body_elem = Element::create(QualName::new(None, ns!(html), local_name!("body")), None, &context_document, - ElementCreator::ScriptCreated); + ElementCreator::ScriptCreated, + CustomElementCreationMode::Synchronous); Root::upcast(body_elem) }, _ => context_node.GetParentElement().unwrap() diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ec4573f7960..ab2e3be9f86 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -33,7 +33,7 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument}; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementCreator}; +use dom::element::{CustomElementCreationMode, Element, ElementCreator}; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; use dom::htmlbodyelement::HTMLBodyElement; @@ -1827,8 +1827,11 @@ impl Node { ns: element.namespace().clone(), local: element.local_name().clone() }; - let element = Element::create(name, element.get_is(), - &document, ElementCreator::ScriptCreated); + let element = Element::create(name, + element.get_is(), + &document, + ElementCreator::ScriptCreated, + CustomElementCreationMode::Asynchronous); Root::upcast::(element) }, }; diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs index 899229be8f8..a7ac04aa6de 100644 --- a/components/script/dom/servoparser/async_html.rs +++ b/components/script/dom/servoparser/async_html.rs @@ -13,7 +13,7 @@ use dom::bindings::trace::JSTraceable; use dom::comment::Comment; use dom::document::Document; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementCreator}; +use dom::element::{CustomElementCreationMode, Element, ElementCreator}; use dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement}; use dom::htmlscriptelement::HTMLScriptElement; use dom::htmltemplateelement::HTMLTemplateElement; @@ -252,7 +252,8 @@ impl Sink { let elem = Element::create(name, is, &*self.document, - ElementCreator::ParserCreated(self.current_line)); + ElementCreator::ParserCreated(self.current_line), + CustomElementCreationMode::Synchronous); for attr in attrs { elem.set_attribute_from_parser(attr.name, DOMString::from(String::from(attr.value)), None); } diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 8e003e44040..6fc611b0108 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -18,7 +18,7 @@ use dom::characterdata::CharacterData; use dom::comment::Comment; use dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument}; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementCreator}; +use dom::element::{Element, ElementCreator, CustomElementCreationMode}; use dom::globalscope::GlobalScope; use dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement}; use dom::htmlimageelement::HTMLImageElement; @@ -786,8 +786,11 @@ impl TreeSink for Sink { .find(|attr| attr.name.local.eq_str_ignore_ascii_case("is")) .map(|attr| LocalName::from(&*attr.value)); - let elem = Element::create(name, is, &*self.document, - ElementCreator::ParserCreated(self.current_line)); + let elem = Element::create(name, + is, + &*self.document, + ElementCreator::ParserCreated(self.current_line), + CustomElementCreationMode::Synchronous); for attr in attrs { elem.set_attribute_from_parser(attr.name, DOMString::from(String::from(attr.value)), None); diff --git a/tests/wpt/metadata/custom-elements/reaction-timing.html.ini b/tests/wpt/metadata/custom-elements/reaction-timing.html.ini index 9abe37eb4e5..14219a014a4 100644 --- a/tests/wpt/metadata/custom-elements/reaction-timing.html.ini +++ b/tests/wpt/metadata/custom-elements/reaction-timing.html.ini @@ -6,3 +6,6 @@ [Custom Elements: Custom element reactions must be invoked before returning to author scripts] expected: FAIL + [Calling Node.prototype.cloneNode(false) must push a new element queue to the processing stack] + expected: FAIL + diff --git a/tests/wpt/metadata/custom-elements/reactions/Document.html.ini b/tests/wpt/metadata/custom-elements/reactions/Document.html.ini index ec21b3a7030..07e68da69b7 100644 --- a/tests/wpt/metadata/custom-elements/reactions/Document.html.ini +++ b/tests/wpt/metadata/custom-elements/reactions/Document.html.ini @@ -30,3 +30,6 @@ [writeln on Document must enqueue connectedCallback after constructing a custom element] expected: FAIL + [importNode on Document must construct a new custom element when importing a custom element from a template] + expected: FAIL + diff --git a/tests/wpt/metadata/custom-elements/upgrading/Node-cloneNode.html.ini b/tests/wpt/metadata/custom-elements/upgrading/Node-cloneNode.html.ini index 548258e0e22..36527742adc 100644 --- a/tests/wpt/metadata/custom-elements/upgrading/Node-cloneNode.html.ini +++ b/tests/wpt/metadata/custom-elements/upgrading/Node-cloneNode.html.ini @@ -15,3 +15,12 @@ [Inserting an element must not try to upgrade a custom element when it had already failed to upgrade once] expected: FAIL + [Node.prototype.cloneNode(false) must be able to clone a custom element] + expected: FAIL + + [Node.prototype.cloneNode(false) must be able to clone a custom element inside an iframe] + expected: FAIL + + [Node.prototype.cloneNode(true) must be able to clone a descendent custom element] + expected: FAIL +