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