Auto merge of #25755 - pshaughn:insertqueue, r=nox

Use CE reaction queue when inserting an element from non-fragment parser

<!-- Please describe your changes on the following line: -->
Changed async_html Tokenizer so it can remember whether it's for a fragment and changed servoparser node insertion to respect the CE queue requirements of https://html.spec.whatwg.org/multipage/parsing.html#insert-a-foreign-element; it passes a WPT test.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25746

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-02-14 06:51:47 -05:00 committed by GitHub
commit 38adec64e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 9 deletions

View file

@ -206,6 +206,7 @@ pub struct Tokenizer {
#[ignore_malloc_size_of = "Defined in std"] #[ignore_malloc_size_of = "Defined in std"]
nodes: HashMap<ParseNodeId, Dom<Node>>, nodes: HashMap<ParseNodeId, Dom<Node>>,
url: ServoUrl, url: ServoUrl,
parsing_algorithm: ParsingAlgorithm,
} }
impl Tokenizer { impl Tokenizer {
@ -219,12 +220,18 @@ impl Tokenizer {
// Messages from HtmlTokenizer and Sink (parser thread) to Tokenizer (main thread) // Messages from HtmlTokenizer and Sink (parser thread) to Tokenizer (main thread)
let (to_tokenizer_sender, tokenizer_receiver) = unbounded(); let (to_tokenizer_sender, tokenizer_receiver) = unbounded();
let algorithm = match fragment_context {
Some(_) => ParsingAlgorithm::Fragment,
None => ParsingAlgorithm::Normal,
};
let mut tokenizer = Tokenizer { let mut tokenizer = Tokenizer {
document: Dom::from_ref(document), document: Dom::from_ref(document),
receiver: tokenizer_receiver, receiver: tokenizer_receiver,
html_tokenizer_sender: to_html_tokenizer_sender, html_tokenizer_sender: to_html_tokenizer_sender,
nodes: HashMap::new(), nodes: HashMap::new(),
url: url, url: url,
parsing_algorithm: algorithm,
}; };
tokenizer.insert_node(0, Dom::from_ref(document.upcast())); tokenizer.insert_node(0, Dom::from_ref(document.upcast()));
@ -352,7 +359,7 @@ impl Tokenizer {
.GetParentNode() .GetParentNode()
.expect("append_before_sibling called on node without parent"); .expect("append_before_sibling called on node without parent");
super::insert(parent, Some(sibling), node); super::insert(parent, Some(sibling), node, self.parsing_algorithm);
} }
fn append(&mut self, parent: ParseNodeId, node: NodeOrText) { fn append(&mut self, parent: ParseNodeId, node: NodeOrText) {
@ -364,7 +371,7 @@ impl Tokenizer {
}; };
let parent = &**self.get_node(&parent); let parent = &**self.get_node(&parent);
super::insert(parent, None, node); super::insert(parent, None, node, self.parsing_algorithm);
} }
fn has_parent_node(&self, node: ParseNodeId) -> bool { fn has_parent_node(&self, node: ParseNodeId) -> bool {

View file

@ -950,12 +950,29 @@ pub struct FragmentContext<'a> {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn insert(parent: &Node, reference_child: Option<&Node>, child: NodeOrText<Dom<Node>>) { fn insert(
parent: &Node,
reference_child: Option<&Node>,
child: NodeOrText<Dom<Node>>,
parsing_algorithm: ParsingAlgorithm,
) {
match child { match child {
NodeOrText::AppendNode(n) => { NodeOrText::AppendNode(n) => {
// https://html.spec.whatwg.org/multipage/#insert-a-foreign-element
// applies if this is an element; if not, it may be
// https://html.spec.whatwg.org/multipage/#insert-a-comment
let element_in_non_fragment =
parsing_algorithm != ParsingAlgorithm::Fragment && n.is::<Element>();
if element_in_non_fragment {
ScriptThread::push_new_element_queue();
}
parent.InsertBefore(&n, reference_child).unwrap(); parent.InsertBefore(&n, reference_child).unwrap();
if element_in_non_fragment {
ScriptThread::pop_current_element_queue();
}
}, },
NodeOrText::AppendText(t) => { NodeOrText::AppendText(t) => {
// https://html.spec.whatwg.org/multipage/#insert-a-character
let text = reference_child let text = reference_child
.and_then(Node::GetPreviousSibling) .and_then(Node::GetPreviousSibling)
.or_else(|| parent.GetLastChild()) .or_else(|| parent.GetLastChild())
@ -1105,7 +1122,7 @@ impl TreeSink for Sink {
.GetParentNode() .GetParentNode()
.expect("append_before_sibling called on node without parent"); .expect("append_before_sibling called on node without parent");
insert(&parent, Some(&*sibling), new_node); insert(&parent, Some(&*sibling), new_node, self.parsing_algorithm);
} }
fn parse_error(&mut self, msg: Cow<'static, str>) { fn parse_error(&mut self, msg: Cow<'static, str>) {
@ -1122,7 +1139,7 @@ impl TreeSink for Sink {
} }
fn append(&mut self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) { fn append(&mut self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
insert(&parent, None, child); insert(&parent, None, child, self.parsing_algorithm);
} }
fn append_based_on_parent_node( fn append_based_on_parent_node(

View file

@ -1,4 +0,0 @@
[parser-sets-attributes-and-children.html]
[HTML parser should call connectedCallback before appending child nodes.]
expected: FAIL