script/dom/servoparser/
async_html.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5#![cfg_attr(crown, allow(crown::unrooted_must_root))]
6
7use std::borrow::Cow;
8use std::cell::{Cell, Ref, RefCell, RefMut};
9use std::collections::vec_deque::VecDeque;
10use std::rc::Rc;
11use std::thread;
12
13use crossbeam_channel::{Receiver, Sender, unbounded};
14use html5ever::buffer_queue::BufferQueue;
15use html5ever::tendril::fmt::UTF8;
16use html5ever::tendril::{SendTendril, StrTendril, Tendril};
17use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts};
18use html5ever::tree_builder::{
19    ElementFlags, NodeOrText as HtmlNodeOrText, QuirksMode, TreeBuilder, TreeBuilderOpts, TreeSink,
20};
21use html5ever::{Attribute as HtmlAttribute, ExpandedName, QualName, local_name, ns};
22use markup5ever::TokenizerResult;
23use rustc_hash::FxHashMap;
24use servo_url::ServoUrl;
25use style::context::QuirksMode as ServoQuirksMode;
26
27use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
28use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
29use crate::dom::bindings::inheritance::Castable;
30use crate::dom::bindings::root::{Dom, DomRoot};
31use crate::dom::bindings::str::DOMString;
32use crate::dom::comment::Comment;
33use crate::dom::customelementregistry::CustomElementReactionStack;
34use crate::dom::document::Document;
35use crate::dom::documenttype::DocumentType;
36use crate::dom::element::{Element, ElementCreator};
37use crate::dom::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
38use crate::dom::html::htmlscriptelement::HTMLScriptElement;
39use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
40use crate::dom::node::Node;
41use crate::dom::processinginstruction::ProcessingInstruction;
42use crate::dom::servoparser::{
43    ElementAttribute, ParsingAlgorithm, attach_declarative_shadow_inner, create_element_for_token,
44};
45use crate::dom::virtualmethods::vtable_for;
46use crate::script_runtime::CanGc;
47
48type ParseNodeId = usize;
49
50#[derive(Clone, JSTraceable, MallocSizeOf)]
51pub(crate) struct ParseNode {
52    id: ParseNodeId,
53    #[no_trace]
54    qual_name: Option<QualName>,
55}
56
57#[derive(JSTraceable, MallocSizeOf)]
58enum NodeOrText {
59    Node(ParseNode),
60    Text(String),
61}
62
63#[derive(JSTraceable, MallocSizeOf)]
64struct Attribute {
65    #[no_trace]
66    name: QualName,
67    value: String,
68}
69
70#[derive(JSTraceable, MallocSizeOf)]
71enum ParseOperation {
72    GetTemplateContents {
73        target: ParseNodeId,
74        contents: ParseNodeId,
75    },
76
77    CreateElement {
78        node: ParseNodeId,
79        #[no_trace]
80        name: QualName,
81        attrs: Vec<Attribute>,
82        current_line: u64,
83    },
84
85    CreateComment {
86        text: String,
87        node: ParseNodeId,
88    },
89    AppendBeforeSibling {
90        sibling: ParseNodeId,
91        node: NodeOrText,
92    },
93    AppendBasedOnParentNode {
94        element: ParseNodeId,
95        prev_element: ParseNodeId,
96        node: NodeOrText,
97    },
98    Append {
99        parent: ParseNodeId,
100        node: NodeOrText,
101    },
102
103    AppendDoctypeToDocument {
104        name: String,
105        public_id: String,
106        system_id: String,
107    },
108
109    AddAttrsIfMissing {
110        target: ParseNodeId,
111        attrs: Vec<Attribute>,
112    },
113    RemoveFromParent {
114        target: ParseNodeId,
115    },
116    MarkScriptAlreadyStarted {
117        node: ParseNodeId,
118    },
119    ReparentChildren {
120        parent: ParseNodeId,
121        new_parent: ParseNodeId,
122    },
123
124    AssociateWithForm {
125        target: ParseNodeId,
126        form: ParseNodeId,
127        element: ParseNodeId,
128        prev_element: Option<ParseNodeId>,
129    },
130
131    CreatePI {
132        node: ParseNodeId,
133        target: String,
134        data: String,
135    },
136
137    Pop {
138        node: ParseNodeId,
139    },
140
141    SetQuirksMode {
142        #[ignore_malloc_size_of = "Defined in style"]
143        #[no_trace]
144        mode: ServoQuirksMode,
145    },
146
147    AttachDeclarativeShadowRoot {
148        location: ParseNodeId,
149        template: ParseNodeId,
150        attributes: Vec<Attribute>,
151        /// Used to notify the parser thread whether or not attaching the shadow root succeeded
152        #[no_trace]
153        sender: Sender<bool>,
154    },
155}
156
157#[derive(MallocSizeOf)]
158enum ToTokenizerMsg {
159    // From HtmlTokenizer
160    TokenizerResultDone {
161        #[ignore_malloc_size_of = "Defined in html5ever"]
162        updated_input: VecDeque<SendTendril<UTF8>>,
163    },
164    TokenizerResultScript {
165        script: ParseNode,
166        #[ignore_malloc_size_of = "Defined in html5ever"]
167        updated_input: VecDeque<SendTendril<UTF8>>,
168    },
169    End, // Sent to Tokenizer to signify HtmlTokenizer's end method has returned
170
171    // From Sink
172    ProcessOperation(ParseOperation),
173}
174
175#[derive(MallocSizeOf)]
176enum ToHtmlTokenizerMsg {
177    Feed {
178        #[ignore_malloc_size_of = "Defined in html5ever"]
179        input: VecDeque<SendTendril<UTF8>>,
180    },
181    End,
182    SetPlainTextState,
183}
184
185fn create_buffer_queue(mut buffers: VecDeque<SendTendril<UTF8>>) -> BufferQueue {
186    let buffer_queue = BufferQueue::default();
187    while let Some(st) = buffers.pop_front() {
188        buffer_queue.push_back(StrTendril::from(st));
189    }
190    buffer_queue
191}
192
193// The async HTML Tokenizer consists of two separate types working together: the Tokenizer
194// (defined below), which lives on the main thread, and the HtmlTokenizer, defined in html5ever, which
195// lives on the parser thread.
196// Steps:
197// 1. A call to Tokenizer::new will spin up a new parser thread, creating an HtmlTokenizer instance,
198//    which starts listening for messages from Tokenizer.
199// 2. Upon receiving an input from ServoParser, the Tokenizer forwards it to HtmlTokenizer, where it starts
200//    creating the necessary tree actions based on the input.
201// 3. HtmlTokenizer sends these tree actions to the Tokenizer as soon as it creates them. The Tokenizer
202//    then executes the received actions.
203//
204//    _____________                           _______________
205//   |             |                         |               |
206//   |             |                         |               |
207//   |             |   ToHtmlTokenizerMsg    |               |
208//   |             |------------------------>| HtmlTokenizer |
209//   |             |                         |               |
210//   |  Tokenizer  |     ToTokenizerMsg      |               |
211//   |             |<------------------------|    ________   |
212//   |             |                         |   |        |  |
213//   |             |     ToTokenizerMsg      |   |  Sink  |  |
214//   |             |<------------------------|---|        |  |
215//   |             |                         |   |________|  |
216//   |_____________|                         |_______________|
217//
218#[derive(JSTraceable, MallocSizeOf)]
219#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
220pub(crate) struct Tokenizer {
221    document: Dom<Document>,
222    #[ignore_malloc_size_of = "Defined in std"]
223    #[no_trace]
224    receiver: Receiver<ToTokenizerMsg>,
225    #[ignore_malloc_size_of = "Defined in std"]
226    #[no_trace]
227    html_tokenizer_sender: Sender<ToHtmlTokenizerMsg>,
228    //#[ignore_malloc_size_of = "Defined in std"]
229    nodes: RefCell<FxHashMap<ParseNodeId, Dom<Node>>>,
230    #[no_trace]
231    url: ServoUrl,
232    parsing_algorithm: ParsingAlgorithm,
233    #[conditional_malloc_size_of]
234    custom_element_reaction_stack: Rc<CustomElementReactionStack>,
235    current_line: Cell<u64>,
236}
237
238impl Tokenizer {
239    pub(crate) fn new(
240        document: &Document,
241        url: ServoUrl,
242        fragment_context: Option<super::FragmentContext>,
243    ) -> Self {
244        // Messages from the Tokenizer (main thread) to HtmlTokenizer (parser thread)
245        let (to_html_tokenizer_sender, html_tokenizer_receiver) = unbounded();
246        // Messages from HtmlTokenizer and Sink (parser thread) to Tokenizer (main thread)
247        let (to_tokenizer_sender, tokenizer_receiver) = unbounded();
248
249        let algorithm = match fragment_context {
250            Some(_) => ParsingAlgorithm::Fragment,
251            None => ParsingAlgorithm::Normal,
252        };
253
254        let custom_element_reaction_stack = document.custom_element_reaction_stack();
255        let tokenizer = Tokenizer {
256            document: Dom::from_ref(document),
257            receiver: tokenizer_receiver,
258            html_tokenizer_sender: to_html_tokenizer_sender,
259            nodes: RefCell::new(FxHashMap::default()),
260            url,
261            parsing_algorithm: algorithm,
262            custom_element_reaction_stack,
263            current_line: Cell::new(1),
264        };
265        tokenizer.insert_node(0, Dom::from_ref(document.upcast()));
266
267        let sink = Sink::new(
268            to_tokenizer_sender.clone(),
269            document.allow_declarative_shadow_roots(),
270        );
271        let mut form_parse_node = None;
272        let mut parser_fragment_context = None;
273        if let Some(fragment_context) = fragment_context {
274            let node = sink.new_parse_node();
275            tokenizer.insert_node(node.id, Dom::from_ref(fragment_context.context_elem));
276            parser_fragment_context =
277                Some((node, fragment_context.context_element_allows_scripting));
278
279            form_parse_node = fragment_context.form_elem.map(|form_elem| {
280                let node = sink.new_parse_node();
281                tokenizer.insert_node(node.id, Dom::from_ref(form_elem));
282                node
283            });
284        };
285
286        // Create new thread for HtmlTokenizer. This is where parser actions
287        // will be generated from the input provided. These parser actions are then passed
288        // onto the main thread to be executed.
289        let scripting_enabled = document.has_browsing_context();
290        thread::Builder::new()
291            .name(format!("Parse:{}", tokenizer.url.debug_compact()))
292            .spawn(move || {
293                run(
294                    sink,
295                    parser_fragment_context,
296                    form_parse_node,
297                    to_tokenizer_sender,
298                    html_tokenizer_receiver,
299                    scripting_enabled,
300                );
301            })
302            .expect("HTML Parser thread spawning failed");
303
304        tokenizer
305    }
306
307    pub(crate) fn feed(
308        &self,
309        input: &BufferQueue,
310        can_gc: CanGc,
311    ) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
312        let mut send_tendrils = VecDeque::new();
313        while let Some(str) = input.pop_front() {
314            send_tendrils.push_back(SendTendril::from(str));
315        }
316
317        // Send message to parser thread, asking it to start reading from the input.
318        // Parser operation messages will be sent to main thread as they are evaluated.
319        self.html_tokenizer_sender
320            .send(ToHtmlTokenizerMsg::Feed {
321                input: send_tendrils,
322            })
323            .unwrap();
324
325        loop {
326            match self
327                .receiver
328                .recv()
329                .expect("Unexpected channel panic in main thread.")
330            {
331                ToTokenizerMsg::ProcessOperation(parse_op) => {
332                    self.process_operation(parse_op, can_gc)
333                },
334                ToTokenizerMsg::TokenizerResultDone { updated_input } => {
335                    let buffer_queue = create_buffer_queue(updated_input);
336                    input.replace_with(buffer_queue);
337                    return TokenizerResult::Done;
338                },
339                ToTokenizerMsg::TokenizerResultScript {
340                    script,
341                    updated_input,
342                } => {
343                    let buffer_queue = create_buffer_queue(updated_input);
344                    input.replace_with(buffer_queue);
345                    let script = self.get_node(&script.id);
346                    return TokenizerResult::Script(DomRoot::from_ref(script.downcast().unwrap()));
347                },
348                _ => unreachable!(),
349            };
350        }
351    }
352
353    pub(crate) fn end(&self, can_gc: CanGc) {
354        self.html_tokenizer_sender
355            .send(ToHtmlTokenizerMsg::End)
356            .unwrap();
357        loop {
358            match self
359                .receiver
360                .recv()
361                .expect("Unexpected channel panic in main thread.")
362            {
363                ToTokenizerMsg::ProcessOperation(parse_op) => {
364                    self.process_operation(parse_op, can_gc)
365                },
366                ToTokenizerMsg::TokenizerResultDone { updated_input: _ } |
367                ToTokenizerMsg::TokenizerResultScript {
368                    script: _,
369                    updated_input: _,
370                } => continue,
371                ToTokenizerMsg::End => return,
372            };
373        }
374    }
375
376    pub(crate) fn url(&self) -> &ServoUrl {
377        &self.url
378    }
379
380    pub(crate) fn set_plaintext_state(&self) {
381        self.html_tokenizer_sender
382            .send(ToHtmlTokenizerMsg::SetPlainTextState)
383            .unwrap();
384    }
385
386    pub(crate) fn get_current_line(&self) -> u32 {
387        self.current_line.get() as u32
388    }
389
390    fn insert_node(&self, id: ParseNodeId, node: Dom<Node>) {
391        assert!(self.nodes.borrow_mut().insert(id, node).is_none());
392    }
393
394    fn get_node<'a>(&'a self, id: &ParseNodeId) -> Ref<'a, Dom<Node>> {
395        Ref::map(self.nodes.borrow(), |nodes| {
396            nodes.get(id).expect("Node not found!")
397        })
398    }
399
400    fn append_before_sibling(&self, sibling: ParseNodeId, node: NodeOrText, can_gc: CanGc) {
401        let node = match node {
402            NodeOrText::Node(n) => {
403                HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
404            },
405            NodeOrText::Text(text) => HtmlNodeOrText::AppendText(Tendril::from(text)),
406        };
407        let sibling = &**self.get_node(&sibling);
408        let parent = &*sibling
409            .GetParentNode()
410            .expect("append_before_sibling called on node without parent");
411
412        super::insert(
413            parent,
414            Some(sibling),
415            node,
416            self.parsing_algorithm,
417            &self.custom_element_reaction_stack,
418            can_gc,
419        );
420    }
421
422    fn append(&self, parent: ParseNodeId, node: NodeOrText, can_gc: CanGc) {
423        let node = match node {
424            NodeOrText::Node(n) => {
425                HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
426            },
427            NodeOrText::Text(text) => HtmlNodeOrText::AppendText(Tendril::from(text)),
428        };
429
430        let parent = &**self.get_node(&parent);
431        super::insert(
432            parent,
433            None,
434            node,
435            self.parsing_algorithm,
436            &self.custom_element_reaction_stack,
437            can_gc,
438        );
439    }
440
441    fn has_parent_node(&self, node: ParseNodeId) -> bool {
442        self.get_node(&node).GetParentNode().is_some()
443    }
444
445    fn same_tree(&self, x: ParseNodeId, y: ParseNodeId) -> bool {
446        let x = self.get_node(&x);
447        let y = self.get_node(&y);
448
449        let x = x.downcast::<Element>().expect("Element node expected");
450        let y = y.downcast::<Element>().expect("Element node expected");
451        x.is_in_same_home_subtree(y)
452    }
453
454    fn process_operation(&self, op: ParseOperation, can_gc: CanGc) {
455        let document = DomRoot::from_ref(&**self.get_node(&0));
456        let document = document
457            .downcast::<Document>()
458            .expect("Document node should be downcasted!");
459        match op {
460            ParseOperation::GetTemplateContents { target, contents } => {
461                let target = DomRoot::from_ref(&**self.get_node(&target));
462                let template = target
463                    .downcast::<HTMLTemplateElement>()
464                    .expect("Tried to extract contents from non-template element while parsing");
465                self.insert_node(contents, Dom::from_ref(template.Content(can_gc).upcast()));
466            },
467            ParseOperation::CreateElement {
468                node,
469                name,
470                attrs,
471                current_line,
472            } => {
473                self.current_line.set(current_line);
474                let attrs = attrs
475                    .into_iter()
476                    .map(|attr| ElementAttribute::new(attr.name, DOMString::from(attr.value)))
477                    .collect();
478                let element = create_element_for_token(
479                    name,
480                    attrs,
481                    &self.document,
482                    ElementCreator::ParserCreated(current_line),
483                    ParsingAlgorithm::Normal,
484                    &self.custom_element_reaction_stack,
485                    can_gc,
486                );
487                self.insert_node(node, Dom::from_ref(element.upcast()));
488            },
489            ParseOperation::CreateComment { text, node } => {
490                let comment = Comment::new(DOMString::from(text), document, None, can_gc);
491                self.insert_node(node, Dom::from_ref(comment.upcast()));
492            },
493            ParseOperation::AppendBeforeSibling { sibling, node } => {
494                self.append_before_sibling(sibling, node, can_gc);
495            },
496            ParseOperation::Append { parent, node } => {
497                self.append(parent, node, can_gc);
498            },
499            ParseOperation::AppendBasedOnParentNode {
500                element,
501                prev_element,
502                node,
503            } => {
504                if self.has_parent_node(element) {
505                    self.append_before_sibling(element, node, can_gc);
506                } else {
507                    self.append(prev_element, node, can_gc);
508                }
509            },
510            ParseOperation::AppendDoctypeToDocument {
511                name,
512                public_id,
513                system_id,
514            } => {
515                let doctype = DocumentType::new(
516                    DOMString::from(name),
517                    Some(DOMString::from(public_id)),
518                    Some(DOMString::from(system_id)),
519                    document,
520                    can_gc,
521                );
522
523                document
524                    .upcast::<Node>()
525                    .AppendChild(doctype.upcast(), can_gc)
526                    .expect("Appending failed");
527            },
528            ParseOperation::AddAttrsIfMissing { target, attrs } => {
529                let node = self.get_node(&target);
530                let elem = node
531                    .downcast::<Element>()
532                    .expect("tried to set attrs on non-Element in HTML parsing");
533                for attr in attrs {
534                    elem.set_attribute_from_parser(
535                        attr.name,
536                        DOMString::from(attr.value),
537                        None,
538                        can_gc,
539                    );
540                }
541            },
542            ParseOperation::RemoveFromParent { target } => {
543                if let Some(ref parent) = self.get_node(&target).GetParentNode() {
544                    parent.RemoveChild(&self.get_node(&target), can_gc).unwrap();
545                }
546            },
547            ParseOperation::MarkScriptAlreadyStarted { node } => {
548                let node = self.get_node(&node);
549                let script = node.downcast::<HTMLScriptElement>();
550                if let Some(script) = script {
551                    script.set_already_started(true)
552                }
553            },
554            ParseOperation::ReparentChildren { parent, new_parent } => {
555                let parent = self.get_node(&parent);
556                let new_parent = self.get_node(&new_parent);
557                while let Some(child) = parent.GetFirstChild() {
558                    new_parent.AppendChild(&child, can_gc).unwrap();
559                }
560            },
561            ParseOperation::AssociateWithForm {
562                target,
563                form,
564                element,
565                prev_element,
566            } => {
567                let tree_node = prev_element.map_or(element, |prev| {
568                    if self.has_parent_node(element) {
569                        element
570                    } else {
571                        prev
572                    }
573                });
574
575                if !self.same_tree(tree_node, form) {
576                    return;
577                }
578                let form = self.get_node(&form);
579                let form = DomRoot::downcast::<HTMLFormElement>(DomRoot::from_ref(&**form))
580                    .expect("Owner must be a form element");
581
582                let node = self.get_node(&target);
583                let elem = node.downcast::<Element>();
584                let control = elem.and_then(|e| e.as_maybe_form_control());
585
586                if let Some(control) = control {
587                    control.set_form_owner_from_parser(&form, can_gc);
588                }
589            },
590            ParseOperation::Pop { node } => {
591                vtable_for(&self.get_node(&node)).pop();
592            },
593            ParseOperation::CreatePI { node, target, data } => {
594                let pi = ProcessingInstruction::new(
595                    DOMString::from(target),
596                    DOMString::from(data),
597                    document,
598                    can_gc,
599                );
600                self.insert_node(node, Dom::from_ref(pi.upcast()));
601            },
602            ParseOperation::SetQuirksMode { mode } => {
603                document.set_quirks_mode(mode);
604            },
605            ParseOperation::AttachDeclarativeShadowRoot {
606                location,
607                template,
608                attributes,
609                sender,
610            } => {
611                let location = self.get_node(&location);
612                let template = self.get_node(&template);
613                let attributes: Vec<_> = attributes
614                    .into_iter()
615                    .map(|attribute| HtmlAttribute {
616                        name: attribute.name,
617                        value: StrTendril::from(attribute.value),
618                    })
619                    .collect();
620
621                let did_succeed =
622                    attach_declarative_shadow_inner(&location, &template, &attributes);
623                sender.send(did_succeed).unwrap();
624            },
625        }
626    }
627}
628
629/// Run the parser.
630///
631/// The `fragment_context` argument is `Some` in the fragment case and describes the context
632/// node as well as whether scripting is enabled for the context node. Note that whether or not
633/// scripting is enabled for the context node does not affect whether scripting is enabled for the
634/// parser, that is determined by the `scripting_enabled` argument.
635fn run(
636    sink: Sink,
637    fragment_context: Option<(ParseNode, bool)>,
638    form_parse_node: Option<ParseNode>,
639    sender: Sender<ToTokenizerMsg>,
640    receiver: Receiver<ToHtmlTokenizerMsg>,
641    scripting_enabled: bool,
642) {
643    let options = TreeBuilderOpts {
644        scripting_enabled,
645        ..Default::default()
646    };
647
648    let html_tokenizer = if let Some((context_node, context_scripting_enabled)) = fragment_context {
649        let tree_builder =
650            TreeBuilder::new_for_fragment(sink, context_node, form_parse_node, options);
651
652        let tok_options = TokenizerOpts {
653            initial_state: Some(
654                tree_builder.tokenizer_state_for_context_elem(context_scripting_enabled),
655            ),
656            ..Default::default()
657        };
658
659        HtmlTokenizer::new(tree_builder, tok_options)
660    } else {
661        HtmlTokenizer::new(TreeBuilder::new(sink, options), Default::default())
662    };
663
664    loop {
665        match receiver
666            .recv()
667            .expect("Unexpected channel panic in html parser thread")
668        {
669            ToHtmlTokenizerMsg::Feed { input } => {
670                let input = create_buffer_queue(input);
671                let res = html_tokenizer.feed(&input);
672
673                // Gather changes to 'input' and place them in 'updated_input',
674                // which will be sent to the main thread to update feed method's 'input'
675                let mut updated_input = VecDeque::new();
676                while let Some(st) = input.pop_front() {
677                    updated_input.push_back(SendTendril::from(st));
678                }
679
680                let res = match res {
681                    TokenizerResult::Done => ToTokenizerMsg::TokenizerResultDone { updated_input },
682                    TokenizerResult::Script(script) => ToTokenizerMsg::TokenizerResultScript {
683                        script,
684                        updated_input,
685                    },
686                };
687                sender.send(res).unwrap();
688            },
689            ToHtmlTokenizerMsg::End => {
690                html_tokenizer.end();
691                sender.send(ToTokenizerMsg::End).unwrap();
692                break;
693            },
694            ToHtmlTokenizerMsg::SetPlainTextState => html_tokenizer.set_plaintext_state(),
695        };
696    }
697}
698
699#[derive(Default, JSTraceable, MallocSizeOf)]
700struct ParseNodeData {
701    contents: Option<ParseNode>,
702    is_integration_point: bool,
703}
704
705pub(crate) struct Sink {
706    current_line: Cell<u64>,
707    parse_node_data: RefCell<FxHashMap<ParseNodeId, ParseNodeData>>,
708    next_parse_node_id: Cell<ParseNodeId>,
709    document_node: ParseNode,
710    sender: Sender<ToTokenizerMsg>,
711    allow_declarative_shadow_roots: bool,
712}
713
714impl Sink {
715    fn new(sender: Sender<ToTokenizerMsg>, allow_declarative_shadow_roots: bool) -> Sink {
716        let sink = Sink {
717            current_line: Cell::new(1),
718            parse_node_data: RefCell::new(FxHashMap::default()),
719            next_parse_node_id: Cell::new(1),
720            document_node: ParseNode {
721                id: 0,
722                qual_name: None,
723            },
724            sender,
725            allow_declarative_shadow_roots,
726        };
727        let data = ParseNodeData::default();
728        sink.insert_parse_node_data(0, data);
729        sink
730    }
731
732    fn new_parse_node(&self) -> ParseNode {
733        let id = self.next_parse_node_id.get();
734        let data = ParseNodeData::default();
735        self.insert_parse_node_data(id, data);
736        self.next_parse_node_id.set(id + 1);
737        ParseNode {
738            id,
739            qual_name: None,
740        }
741    }
742
743    fn send_op(&self, op: ParseOperation) {
744        self.sender
745            .send(ToTokenizerMsg::ProcessOperation(op))
746            .unwrap();
747    }
748
749    fn insert_parse_node_data(&self, id: ParseNodeId, data: ParseNodeData) {
750        assert!(self.parse_node_data.borrow_mut().insert(id, data).is_none());
751    }
752
753    fn get_parse_node_data<'a>(&'a self, id: &'a ParseNodeId) -> Ref<'a, ParseNodeData> {
754        Ref::map(self.parse_node_data.borrow(), |data| {
755            data.get(id).expect("Parse Node data not found!")
756        })
757    }
758
759    fn get_parse_node_data_mut<'a>(&'a self, id: &'a ParseNodeId) -> RefMut<'a, ParseNodeData> {
760        RefMut::map(self.parse_node_data.borrow_mut(), |data| {
761            data.get_mut(id).expect("Parse Node data not found!")
762        })
763    }
764}
765
766#[cfg_attr(crown, allow(crown::unrooted_must_root))]
767impl TreeSink for Sink {
768    type Output = Self;
769    fn finish(self) -> Self {
770        self
771    }
772
773    type Handle = ParseNode;
774    type ElemName<'a>
775        = ExpandedName<'a>
776    where
777        Self: 'a;
778
779    fn get_document(&self) -> Self::Handle {
780        self.document_node.clone()
781    }
782
783    fn get_template_contents(&self, target: &Self::Handle) -> Self::Handle {
784        if let Some(ref contents) = self.get_parse_node_data(&target.id).contents {
785            return contents.clone();
786        }
787        let node = self.new_parse_node();
788        {
789            let mut data = self.get_parse_node_data_mut(&target.id);
790            data.contents = Some(node.clone());
791        }
792        self.send_op(ParseOperation::GetTemplateContents {
793            target: target.id,
794            contents: node.id,
795        });
796        node
797    }
798
799    fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool {
800        x.id == y.id
801    }
802
803    fn elem_name<'a>(&self, target: &'a Self::Handle) -> ExpandedName<'a> {
804        target
805            .qual_name
806            .as_ref()
807            .expect("Expected qual name of node!")
808            .expanded()
809    }
810
811    fn create_element(
812        &self,
813        name: QualName,
814        html_attrs: Vec<HtmlAttribute>,
815        _flags: ElementFlags,
816    ) -> Self::Handle {
817        let mut node = self.new_parse_node();
818        node.qual_name = Some(name.clone());
819        {
820            let mut node_data = self.get_parse_node_data_mut(&node.id);
821            node_data.is_integration_point = html_attrs.iter().any(|attr| {
822                let attr_value = &String::from(attr.value.clone());
823                (attr.name.local == local_name!("encoding") && attr.name.ns == ns!()) &&
824                    (attr_value.eq_ignore_ascii_case("text/html") ||
825                        attr_value.eq_ignore_ascii_case("application/xhtml+xml"))
826            });
827        }
828        let attrs = html_attrs
829            .into_iter()
830            .map(|attr| Attribute {
831                name: attr.name,
832                value: String::from(attr.value),
833            })
834            .collect();
835
836        self.send_op(ParseOperation::CreateElement {
837            node: node.id,
838            name,
839            attrs,
840            current_line: self.current_line.get(),
841        });
842        node
843    }
844
845    fn create_comment(&self, text: StrTendril) -> Self::Handle {
846        let node = self.new_parse_node();
847        self.send_op(ParseOperation::CreateComment {
848            text: String::from(text),
849            node: node.id,
850        });
851        node
852    }
853
854    fn create_pi(&self, target: StrTendril, data: StrTendril) -> ParseNode {
855        let node = self.new_parse_node();
856        self.send_op(ParseOperation::CreatePI {
857            node: node.id,
858            target: String::from(target),
859            data: String::from(data),
860        });
861        node
862    }
863
864    fn associate_with_form(
865        &self,
866        target: &Self::Handle,
867        form: &Self::Handle,
868        nodes: (&Self::Handle, Option<&Self::Handle>),
869    ) {
870        let (element, prev_element) = nodes;
871        self.send_op(ParseOperation::AssociateWithForm {
872            target: target.id,
873            form: form.id,
874            element: element.id,
875            prev_element: prev_element.map(|p| p.id),
876        });
877    }
878
879    fn append_before_sibling(
880        &self,
881        sibling: &Self::Handle,
882        new_node: HtmlNodeOrText<Self::Handle>,
883    ) {
884        let new_node = match new_node {
885            HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node),
886            HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)),
887        };
888        self.send_op(ParseOperation::AppendBeforeSibling {
889            sibling: sibling.id,
890            node: new_node,
891        });
892    }
893
894    fn append_based_on_parent_node(
895        &self,
896        elem: &Self::Handle,
897        prev_elem: &Self::Handle,
898        child: HtmlNodeOrText<Self::Handle>,
899    ) {
900        let child = match child {
901            HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node),
902            HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)),
903        };
904        self.send_op(ParseOperation::AppendBasedOnParentNode {
905            element: elem.id,
906            prev_element: prev_elem.id,
907            node: child,
908        });
909    }
910
911    fn parse_error(&self, msg: Cow<'static, str>) {
912        debug!("Parse error: {}", msg);
913    }
914
915    fn set_quirks_mode(&self, mode: QuirksMode) {
916        let mode = match mode {
917            QuirksMode::Quirks => ServoQuirksMode::Quirks,
918            QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
919            QuirksMode::NoQuirks => ServoQuirksMode::NoQuirks,
920        };
921        self.send_op(ParseOperation::SetQuirksMode { mode });
922    }
923
924    fn append(&self, parent: &Self::Handle, child: HtmlNodeOrText<Self::Handle>) {
925        let child = match child {
926            HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node),
927            HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)),
928        };
929        self.send_op(ParseOperation::Append {
930            parent: parent.id,
931            node: child,
932        });
933    }
934
935    fn append_doctype_to_document(
936        &self,
937        name: StrTendril,
938        public_id: StrTendril,
939        system_id: StrTendril,
940    ) {
941        self.send_op(ParseOperation::AppendDoctypeToDocument {
942            name: String::from(name),
943            public_id: String::from(public_id),
944            system_id: String::from(system_id),
945        });
946    }
947
948    fn add_attrs_if_missing(&self, target: &Self::Handle, html_attrs: Vec<HtmlAttribute>) {
949        let attrs = html_attrs
950            .into_iter()
951            .map(|attr| Attribute {
952                name: attr.name,
953                value: String::from(attr.value),
954            })
955            .collect();
956        self.send_op(ParseOperation::AddAttrsIfMissing {
957            target: target.id,
958            attrs,
959        });
960    }
961
962    fn remove_from_parent(&self, target: &Self::Handle) {
963        self.send_op(ParseOperation::RemoveFromParent { target: target.id });
964    }
965
966    fn mark_script_already_started(&self, node: &Self::Handle) {
967        self.send_op(ParseOperation::MarkScriptAlreadyStarted { node: node.id });
968    }
969
970    fn reparent_children(&self, parent: &Self::Handle, new_parent: &Self::Handle) {
971        self.send_op(ParseOperation::ReparentChildren {
972            parent: parent.id,
973            new_parent: new_parent.id,
974        });
975    }
976
977    /// <https://html.spec.whatwg.org/multipage/#html-integration-point>
978    /// Specifically, the `<annotation-xml>` cases.
979    fn is_mathml_annotation_xml_integration_point(&self, handle: &Self::Handle) -> bool {
980        let node_data = self.get_parse_node_data(&handle.id);
981        node_data.is_integration_point
982    }
983
984    fn set_current_line(&self, line_number: u64) {
985        self.current_line.set(line_number);
986    }
987
988    fn pop(&self, node: &Self::Handle) {
989        self.send_op(ParseOperation::Pop { node: node.id });
990    }
991
992    fn allow_declarative_shadow_roots(&self, _intended_parent: &Self::Handle) -> bool {
993        self.allow_declarative_shadow_roots
994    }
995
996    fn attach_declarative_shadow(
997        &self,
998        location: &Self::Handle,
999        template: &Self::Handle,
1000        attributes: &[HtmlAttribute],
1001    ) -> bool {
1002        let attributes = attributes
1003            .iter()
1004            .map(|attribute| Attribute {
1005                name: attribute.name.clone(),
1006                value: String::from(attribute.value.clone()),
1007            })
1008            .collect();
1009
1010        // Unfortunately the parser can only proceed after it knows whether attaching the shadow root
1011        // succeeded or failed. Attaching a shadow root can fail for many different reasons,
1012        // and so we need to block until the script thread has processed this operation.
1013        let (sender, receiver) = unbounded();
1014        self.send_op(ParseOperation::AttachDeclarativeShadowRoot {
1015            location: location.id,
1016            template: template.id,
1017            attributes,
1018            sender,
1019        });
1020
1021        receiver.recv().unwrap()
1022    }
1023}