Add flag for sync/async CE creation

This commit is contained in:
Connor Brewster 2017-06-16 15:30:13 -06:00
parent 2f36d3544f
commit 062b128688
9 changed files with 78 additions and 35 deletions

View file

@ -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<Prefix>,
is: Option<LocalName>,
document: &Document,
creator: ElementCreator)
creator: ElementCreator,
mode: CustomElementCreationMode)
-> Root<Element> {
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<LocalName>,
document: &Document,
creator: ElementCreator)
creator: ElementCreator,
mode: CustomElementCreationMode)
-> Root<Element> {
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)
}

View file

@ -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::<Node>(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::<Node>();
let child = elem.upcast::<Node>();
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::<Node>()
.AppendChild(elem.upcast())
.unwrap()

View file

@ -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<LocalName>,
document: &Document,
creator: ElementCreator)
creator: ElementCreator,
mode: CustomElementCreationMode)
-> Root<Element> {
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()

View file

@ -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::<Node>(element)
},
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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