1#![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 #[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 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#[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 #[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 let (to_parser_thread_sender, from_main_thread_receiver) = unbounded();
229 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 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 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
620fn 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 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 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 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}