1#![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 #[no_trace]
153 sender: Sender<bool>,
154 },
155}
156
157#[derive(MallocSizeOf)]
158enum ToTokenizerMsg {
159 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, 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#[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 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 let (to_html_tokenizer_sender, html_tokenizer_receiver) = unbounded();
246 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 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 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
629fn 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 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 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 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}