Skip to content

Commit

Permalink
Support is option when creating elements
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrewster committed Jun 24, 2017
1 parent 6697f54 commit 2f36d35
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 25 deletions.
14 changes: 10 additions & 4 deletions components/script/dom/create.rs
Expand Up @@ -79,7 +79,7 @@ use dom::htmlulistelement::HTMLUListElement;
use dom::htmlunknownelement::HTMLUnknownElement;
use dom::htmlvideoelement::HTMLVideoElement;
use dom::svgsvgelement::SVGSVGElement;
use html5ever::{QualName, Prefix};
use html5ever::{LocalName, Prefix, QualName};
use js::jsapi::JSAutoCompartment;
use servo_config::prefs::PREFS;

Expand Down Expand Up @@ -114,16 +114,16 @@ fn create_svg_element(name: QualName,
#[allow(unsafe_code)]
fn create_html_element(name: QualName,
prefix: Option<Prefix>,
is: Option<LocalName>,
document: &Document,
creator: ElementCreator)
-> Root<Element> {
assert!(name.ns == ns!(html));

// Step 4
let definition = document.lookup_custom_element_definition(name.local.clone(), None);
let definition = document.lookup_custom_element_definition(name.local.clone(), is);

if let Some(definition) = definition {
// TODO: Handle customized built-in elements. Relies on CE upgrades.
if definition.is_autonomous() {
let local_name = name.local.clone();
return match definition.create_element(document) {
Expand All @@ -143,6 +143,11 @@ fn create_html_element(name: QualName,
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());
// TODO: Enqueue custom element upgrade
return element;
}
}

Expand Down Expand Up @@ -316,12 +321,13 @@ pub fn create_native_html_element(name: QualName,
}

pub fn create_element(name: QualName,
is: Option<LocalName>,
document: &Document,
creator: ElementCreator)
-> Root<Element> {
let prefix = name.prefix.clone();
match name.ns {
ns!(html) => create_html_element(name, prefix, document, creator),
ns!(html) => create_html_element(name, prefix, is, document, creator),
ns!(svg) => create_svg_element(name, prefix, document),
_ => Element::new(name.local, name.ns, prefix, document)
}
Expand Down
19 changes: 13 additions & 6 deletions components/script/dom/document.rs
Expand Up @@ -13,7 +13,7 @@ use dom::bindings::callback::ExceptionHandling;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
use dom::bindings::codegen::Bindings::DocumentBinding;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState, ElementCreationOptions};
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
Expand Down Expand Up @@ -2834,7 +2834,10 @@ impl DocumentMethods for Document {
}

// https://dom.spec.whatwg.org/#dom-document-createelement
fn CreateElement(&self, mut local_name: DOMString) -> Fallible<Root<Element>> {
fn CreateElement(&self,
mut local_name: DOMString,
options: &ElementCreationOptions)
-> Fallible<Root<Element>> {
if xml_name_type(&local_name) == InvalidXMLName {
debug!("Not a valid element name");
return Err(Error::InvalidCharacter);
Expand All @@ -2850,18 +2853,21 @@ impl DocumentMethods for Document {
};

let name = QualName::new(None, ns, LocalName::from(local_name));
Ok(Element::create(name, self, ElementCreator::ScriptCreated))
let is = options.is.as_ref().map(|is| LocalName::from(&**is));
Ok(Element::create(name, is, self, ElementCreator::ScriptCreated))
}

// https://dom.spec.whatwg.org/#dom-document-createelementns
fn CreateElementNS(&self,
namespace: Option<DOMString>,
qualified_name: DOMString)
qualified_name: DOMString,
options: &ElementCreationOptions)
-> Fallible<Root<Element>> {
let (namespace, prefix, local_name) = validate_and_extract(namespace,
&qualified_name)?;
let name = QualName::new(prefix, namespace, local_name);
Ok(Element::create(name, self, ElementCreator::ScriptCreated))
let is = options.is.as_ref().map(|is| LocalName::from(&**is));
Ok(Element::create(name, is, self, ElementCreator::ScriptCreated))
}

// https://dom.spec.whatwg.org/#dom-document-createattribute
Expand Down Expand Up @@ -3115,7 +3121,7 @@ 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, self, ElementCreator::ScriptCreated);
let elem = Element::create(name, None, self, ElementCreator::ScriptCreated);
let parent = root.upcast::<Node>();
let child = elem.upcast::<Node>();
parent.InsertBefore(child, parent.GetFirstChild().r())
Expand All @@ -3133,6 +3139,7 @@ impl DocumentMethods for Document {
Some(head) => {
let name = QualName::new(None, ns!(html), local_name!("title"));
let elem = Element::create(name,
None,
self,
ElementCreator::ScriptCreated);
head.upcast::<Node>()
Expand Down
5 changes: 3 additions & 2 deletions components/script/dom/domimplementation.rs
Expand Up @@ -5,7 +5,7 @@
use document_loader::DocumentLoader;
use dom::bindings::codegen::Bindings::DOMImplementationBinding;
use dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, ElementCreationOptions};
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::error::Fallible;
use dom::bindings::inheritance::Castable;
Expand Down Expand Up @@ -92,7 +92,8 @@ impl DOMImplementationMethods for DOMImplementation {
let maybe_elem = if qname.is_empty() {
None
} else {
match doc.upcast::<Document>().CreateElementNS(maybe_namespace, qname) {
let options = ElementCreationOptions { is: None };
match doc.upcast::<Document>().CreateElementNS(maybe_namespace, qname, &options) {
Err(error) => return Err(error),
Ok(elem) => Some(elem),
}
Expand Down
17 changes: 15 additions & 2 deletions components/script/dom/element.rs
Expand Up @@ -129,6 +129,7 @@ pub struct Element {
prefix: Option<Prefix>,
attrs: DOMRefCell<Vec<JS<Attr>>>,
id_attribute: DOMRefCell<Option<Atom>>,
is: DOMRefCell<Option<LocalName>>,
#[ignore_heap_size_of = "Arc"]
style_attribute: DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
attr_list: MutNullableJS<NamedNodeMap>,
Expand Down Expand Up @@ -205,9 +206,11 @@ impl<'a> TryFrom<&'a str> for AdjacentPosition {
//
impl Element {
pub fn create(name: QualName,
document: &Document, creator: ElementCreator)
is: Option<LocalName>,
document: &Document,
creator: ElementCreator)
-> Root<Element> {
create_element(name, document, creator)
create_element(name, is, document, creator)
}

pub fn new_inherited(local_name: LocalName,
Expand All @@ -229,6 +232,7 @@ impl Element {
prefix: prefix,
attrs: DOMRefCell::new(vec![]),
id_attribute: DOMRefCell::new(None),
is: DOMRefCell::new(None),
style_attribute: DOMRefCell::new(None),
attr_list: Default::default(),
class_list: Default::default(),
Expand Down Expand Up @@ -260,6 +264,14 @@ impl Element {
}
}

pub fn set_is(&self, is: LocalName) {
*self.is.borrow_mut() = Some(is);
}

pub fn get_is(&self) -> Option<LocalName> {
self.is.borrow().clone()
}

// https://drafts.csswg.org/cssom-view/#css-layout-box
// Elements that have a computed value of the display property
// that is table-column or table-column-group
Expand Down Expand Up @@ -1970,6 +1982,7 @@ impl ElementMethods for Element {
// Step 4.
NodeTypeId::DocumentFragment => {
let body_elem = Element::create(QualName::new(None, ns!(html), local_name!("body")),
None,
&context_document,
ElementCreator::ScriptCreated);
Root::upcast(body_elem)
Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/node.rs
Expand Up @@ -1827,7 +1827,7 @@ impl Node {
ns: element.namespace().clone(),
local: element.local_name().clone()
};
let element = Element::create(name,
let element = Element::create(name, element.get_is(),
&document, ElementCreator::ScriptCreated);
Root::upcast::<Node>(element)
},
Expand Down
10 changes: 8 additions & 2 deletions components/script/dom/servoparser/async_html.rs
Expand Up @@ -20,7 +20,7 @@ use dom::htmltemplateelement::HTMLTemplateElement;
use dom::node::Node;
use dom::processinginstruction::ProcessingInstruction;
use dom::virtualmethods::vtable_for;
use html5ever::{Attribute, QualName, ExpandedName};
use html5ever::{Attribute, LocalName, QualName, ExpandedName};
use html5ever::buffer_queue::BufferQueue;
use html5ever::tendril::StrTendril;
use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts, TokenizerResult};
Expand Down Expand Up @@ -245,7 +245,13 @@ impl Sink {
self.insert_node(contents, JS::from_ref(template.Content().upcast()));
}
ParseOperation::CreateElement(id, name, attrs) => {
let elem = Element::create(name, &*self.document,
let is = attrs.iter()
.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));
for attr in attrs {
elem.set_attribute_from_parser(attr.name, DOMString::from(String::from(attr.value)), None);
Expand Down
8 changes: 6 additions & 2 deletions components/script/dom/servoparser/mod.rs
Expand Up @@ -29,7 +29,7 @@ use dom::processinginstruction::ProcessingInstruction;
use dom::text::Text;
use dom::virtualmethods::vtable_for;
use dom_struct::dom_struct;
use html5ever::{Attribute, QualName, ExpandedName};
use html5ever::{Attribute, ExpandedName, LocalName, QualName};
use html5ever::buffer_queue::BufferQueue;
use html5ever::tendril::{StrTendril, ByteTendril, IncompleteUtf8};
use html5ever::tree_builder::{NodeOrText, TreeSink, NextParserState, QuirksMode, ElementFlags};
Expand Down Expand Up @@ -782,7 +782,11 @@ impl TreeSink for Sink {

fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>, _flags: ElementFlags)
-> JS<Node> {
let elem = Element::create(name, &*self.document,
let is = attrs.iter()
.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));

for attr in attrs {
Expand Down
8 changes: 6 additions & 2 deletions components/script/dom/webidls/Document.webidl
Expand Up @@ -33,9 +33,9 @@ interface Document : Node {
HTMLCollection getElementsByClassName(DOMString classNames);

[NewObject, Throws]
Element createElement(DOMString localName);
Element createElement(DOMString localName, optional ElementCreationOptions options);
[NewObject, Throws]
Element createElementNS(DOMString? namespace, DOMString qualifiedName);
Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional ElementCreationOptions options);
[NewObject]
DocumentFragment createDocumentFragment();
[NewObject]
Expand Down Expand Up @@ -75,6 +75,10 @@ Document implements ParentNode;

enum DocumentReadyState { "loading", "interactive", "complete" };

dictionary ElementCreationOptions {
DOMString is;
};

// https://html.spec.whatwg.org/multipage/#the-document-object
// [OverrideBuiltins]
partial /*sealed*/ interface Document {
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/script/size_of.rs
Expand Up @@ -31,10 +31,10 @@ macro_rules! sizeof_checker (
// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 184);
sizeof_checker!(size_element, Element, 344);
sizeof_checker!(size_htmlelement, HTMLElement, 360);
sizeof_checker!(size_div, HTMLDivElement, 360);
sizeof_checker!(size_span, HTMLSpanElement, 360);
sizeof_checker!(size_element, Element, 368);
sizeof_checker!(size_htmlelement, HTMLElement, 384);
sizeof_checker!(size_div, HTMLDivElement, 384);
sizeof_checker!(size_span, HTMLSpanElement, 384);
sizeof_checker!(size_text, Text, 216);
sizeof_checker!(size_characterdata, CharacterData, 216);
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
Expand Down

0 comments on commit 2f36d35

Please sign in to comment.