Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the create an element for token algorithm #19397

Merged
merged 4 commits into from Jan 17, 2018
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Implement the create an element for token algorithm

  • Loading branch information
cbrewster authored and jdm committed Jan 11, 2018
commit 87475b11d344c2bfdfbed4d48495ecedec34bac8
@@ -12,14 +12,15 @@ use dom::bindings::str::DOMString;
use dom::comment::Comment;
use dom::document::Document;
use dom::documenttype::DocumentType;
use dom::element::{CustomElementCreationMode, Element, ElementCreator};
use dom::element::{Element, ElementCreator};
use dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmltemplateelement::HTMLTemplateElement;
use dom::node::Node;
use dom::processinginstruction::ProcessingInstruction;
use dom::servoparser::{ElementAttribute, create_element_for_token, ParsingAlgorithm};
use dom::virtualmethods::vtable_for;
use html5ever::{Attribute as HtmlAttribute, ExpandedName, LocalName, QualName};
use html5ever::{Attribute as HtmlAttribute, ExpandedName, QualName};
use html5ever::buffer_queue::BufferQueue;
use html5ever::tendril::{SendTendril, StrTendril, Tendril};
use html5ever::tendril::fmt::UTF8;
@@ -335,20 +336,18 @@ impl Tokenizer {
self.insert_node(contents, Dom::from_ref(template.Content().upcast()));
}
ParseOperation::CreateElement { node, name, attrs, current_line } => {
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(current_line),
CustomElementCreationMode::Synchronous);
for attr in attrs {
elem.set_attribute_from_parser(attr.name, DOMString::from(attr.value), None);
}

self.insert_node(node, Dom::from_ref(elem.upcast()));
let attrs = attrs
.into_iter()
.map(|attr| ElementAttribute::new(attr.name, DOMString::from(attr.value)))
.collect();
let element = create_element_for_token(
name,
attrs,
&*self.document,
ElementCreator::ParserCreated(current_line),
ParsingAlgorithm::Normal
);
self.insert_node(node, Dom::from_ref(element.upcast()));
}
ParseOperation::CreateComment { text, node } => {
let comment = Comment::new(DOMString::from(text), document);
@@ -16,7 +16,7 @@ use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmltemplateelement::HTMLTemplateElement;
use dom::node::Node;
use dom::processinginstruction::ProcessingInstruction;
use dom::servoparser::Sink;
use dom::servoparser::{ParsingAlgorithm, Sink};
use html5ever::QualName;
use html5ever::buffer_queue::BufferQueue;
use html5ever::serialize::{AttrRef, Serialize, Serializer};
@@ -39,13 +39,15 @@ impl Tokenizer {
pub fn new(
document: &Document,
url: ServoUrl,
fragment_context: Option<super::FragmentContext>)
fragment_context: Option<super::FragmentContext>,
parsing_algorithm: ParsingAlgorithm)
-> Self {
let sink = Sink {
base_url: url,
document: Dom::from_ref(document),
current_line: 1,
script: Default::default(),
parsing_algorithm: parsing_algorithm,
};

let options = TreeBuilderOpts {
@@ -101,6 +101,26 @@ enum LastChunkState {
NotReceived,
}

pub struct ElementAttribute {
name: QualName,
value: DOMString
}

#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub enum ParsingAlgorithm {
Normal,
Fragment,
}

impl ElementAttribute {
pub fn new(name: QualName, value: DOMString) -> ElementAttribute {
ElementAttribute {
name: name,
value: value
}
}
}

impl ServoParser {
pub fn parser_is_not_active(&self) -> bool {
self.can_write() || self.tokenizer.try_borrow_mut().is_ok()
@@ -114,7 +134,7 @@ impl ServoParser {
ParserKind::Normal)
} else {
ServoParser::new(document,
Tokenizer::Html(self::html::Tokenizer::new(document, url, None)),
Tokenizer::Html(self::html::Tokenizer::new(document, url, None, ParsingAlgorithm::Normal)),
LastChunkState::NotReceived,
ParserKind::Normal)
};
@@ -160,7 +180,8 @@ impl ServoParser {
let parser = ServoParser::new(&document,
Tokenizer::Html(self::html::Tokenizer::new(&document,
url,
Some(fragment_context))),
Some(fragment_context),
ParsingAlgorithm::Fragment)),
LastChunkState::Received,
ParserKind::Normal);
parser.parse_string_chunk(String::from(input));
@@ -173,10 +194,17 @@ impl ServoParser {
}

pub fn parse_html_script_input(document: &Document, url: ServoUrl, type_: &str) {
let parser = ServoParser::new(document,
Tokenizer::Html(self::html::Tokenizer::new(document, url, None)),
LastChunkState::NotReceived,
ParserKind::ScriptCreated);
let parser = ServoParser::new(
document,
Tokenizer::Html(self::html::Tokenizer::new(
document,
url,
None,
ParsingAlgorithm::Normal,
)),
LastChunkState::NotReceived,
ParserKind::ScriptCreated,
);
document.set_current_parser(Some(&parser));
if !type_.eq_ignore_ascii_case("text/html") {
parser.parse_string_chunk("<pre>\n".to_owned());
@@ -748,6 +776,7 @@ pub struct Sink {
document: Dom<Document>,
current_line: u64,
script: MutNullableDom<HTMLScriptElement>,
parsing_algorithm: ParsingAlgorithm,
}

impl Sink {
@@ -795,21 +824,18 @@ impl TreeSink for Sink {

fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>, _flags: ElementFlags)
-> Dom<Node> {
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),
CustomElementCreationMode::Synchronous);

for attr in attrs {
elem.set_attribute_from_parser(attr.name, DOMString::from(String::from(attr.value)), None);
}

Dom::from_ref(elem.upcast())
let attrs = attrs
.into_iter()
.map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
.collect();
let element = create_element_for_token(
name,
attrs,
&*self.document,
ElementCreator::ParserCreated(self.current_line),
self.parsing_algorithm,
);
Dom::from_ref(element.upcast())
}

fn create_comment(&mut self, text: StrTendril) -> Dom<Node> {
@@ -950,3 +976,62 @@ impl TreeSink for Sink {
vtable_for(&node).pop();
}
}

/// https://html.spec.whatwg.org/multipage/#create-an-element-for-the-token
fn create_element_for_token(
name: QualName,
attrs: Vec<ElementAttribute>,
document: &Document,
creator: ElementCreator,
parsing_algorithm: ParsingAlgorithm,
) -> DomRoot<Element> {
// Step 3.
let is = attrs.iter()
.find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
.map(|attr| LocalName::from(&*attr.value));

// Step 4.
let definition = document.lookup_custom_element_definition(&name.ns, &name.local, is.as_ref());

// Step 5.
let will_execute_script = definition.is_some() && parsing_algorithm != ParsingAlgorithm::Fragment;

// Step 6.
if will_execute_script {
// Step 6.1.
// TODO: handle throw-on-dynamic-markup-insertion counter.
// Step 6.2
// TODO: If the JavaScript execution context stack is empty, then perform a microtask checkpoint.

This comment has been minimized.

// Step 6.3
ScriptThread::push_new_element_queue()
}

// Step 7.
let creation_mode = if will_execute_script {
CustomElementCreationMode::Synchronous
} else {
CustomElementCreationMode::Asynchronous
};
let element = Element::create(name, is, document, creator, creation_mode);

// Step 8.
for attr in attrs {
element.set_attribute_from_parser(attr.name, attr.value, None);
}

// Step 9.
if will_execute_script {
// Steps 9.1 - 9.2.
ScriptThread::pop_current_element_queue()
// Step 9.3.
// TODO: handle throw-on-dynamic-markup-insertion counter.
}

// TODO: Step 10.
// TODO: Step 11.

// Step 12 is handled in `associate_with_form`.

// Step 13.
element
}
@@ -9,7 +9,7 @@ use dom::bindings::trace::JSTraceable;
use dom::document::Document;
use dom::htmlscriptelement::HTMLScriptElement;
use dom::node::Node;
use dom::servoparser::Sink;
use dom::servoparser::{ParsingAlgorithm, Sink};
use js::jsapi::JSTracer;
use servo_url::ServoUrl;
use xml5ever::buffer_queue::BufferQueue;
@@ -30,6 +30,7 @@ impl Tokenizer {
document: Dom::from_ref(document),
current_line: 1,
script: Default::default(),
parsing_algorithm: ParsingAlgorithm::Normal,
};

let tb = XmlTreeBuilder::new(sink, Default::default());
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.