1use std::borrow::Cow;
6use std::cell::{Cell, RefCell};
7use std::mem;
8use std::rc::Rc;
9
10use base::cross_process_instant::CrossProcessInstant;
11use base::id::{PipelineId, WebViewId};
12use base64::Engine as _;
13use base64::engine::general_purpose;
14use content_security_policy::sandboxing_directive::SandboxingFlagSet;
15use devtools_traits::ScriptToDevtoolsControlMsg;
16use dom_struct::dom_struct;
17use embedder_traits::resources::{self, Resource};
18use encoding_rs::{Encoding, UTF_8};
19use html5ever::buffer_queue::BufferQueue;
20use html5ever::tendril::StrTendril;
21use html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
22use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns};
23use hyper_serde::Serde;
24use markup5ever::TokenizerResult;
25use mime::{self, Mime};
26use net_traits::mime_classifier::{ApacheBugFlag, MediaType, MimeClassifier, NoSniffFlag};
27use net_traits::policy_container::PolicyContainer;
28use net_traits::request::RequestId;
29use net_traits::{
30 FetchMetadata, LoadContext, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming,
31};
32use profile_traits::time::{
33 ProfilerCategory, ProfilerChan, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
34};
35use profile_traits::time_profile;
36use script_bindings::script_runtime::temp_cx;
37use script_traits::DocumentActivity;
38use servo_config::pref;
39use servo_url::ServoUrl;
40use style::context::QuirksMode as ServoQuirksMode;
41use tendril::stream::LossyDecoder;
42use tendril::{ByteTendril, TendrilSink};
43
44use crate::document_loader::{DocumentLoader, LoadType};
45use crate::dom::bindings::cell::DomRefCell;
46use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
47 DocumentMethods, DocumentReadyState,
48};
49use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
50use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
51use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
52use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
53use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
54 ShadowRootMode, SlotAssignmentMode,
55};
56use crate::dom::bindings::inheritance::Castable;
57use crate::dom::bindings::refcounted::Trusted;
58use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
59use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
60use crate::dom::bindings::settings_stack::is_execution_stack_empty;
61use crate::dom::bindings::str::{DOMString, USVString};
62use crate::dom::characterdata::CharacterData;
63use crate::dom::comment::Comment;
64use crate::dom::csp::{GlobalCspReporting, Violation, parse_csp_list_from_metadata};
65use crate::dom::customelementregistry::CustomElementReactionStack;
66use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
67use crate::dom::documentfragment::DocumentFragment;
68use crate::dom::documenttype::DocumentType;
69use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
70use crate::dom::globalscope::GlobalScope;
71use crate::dom::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
72use crate::dom::html::htmlimageelement::HTMLImageElement;
73use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
74use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
75use crate::dom::node::{Node, ShadowIncluding};
76use crate::dom::performance::performanceentry::PerformanceEntry;
77use crate::dom::performance::performancenavigationtiming::PerformanceNavigationTiming;
78use crate::dom::processinginstruction::ProcessingInstruction;
79use crate::dom::processingoptions::{
80 LinkHeader, LinkProcessingPhase, extract_links_from_headers, process_link_headers,
81};
82use crate::dom::reportingendpoint::ReportingEndpoint;
83use crate::dom::shadowroot::IsUserAgentWidget;
84use crate::dom::text::Text;
85use crate::dom::types::{HTMLElement, HTMLMediaElement, HTMLOptionElement};
86use crate::dom::virtualmethods::vtable_for;
87use crate::network_listener::FetchResponseListener;
88use crate::realms::{enter_auto_realm, enter_realm};
89use crate::script_runtime::{CanGc, IntroductionType};
90use crate::script_thread::ScriptThread;
91
92mod async_html;
93pub(crate) mod encoding;
94pub(crate) mod html;
95mod prefetch;
96mod xml;
97
98use encoding::{NetworkDecoderState, NetworkSink};
99pub(crate) use html::serialize_html_fragment;
100
101#[dom_struct]
102pub(crate) struct ServoParser {
115 reflector: Reflector,
116 document: Dom<Document>,
118 network_decoder: DomRefCell<NetworkDecoderState>,
120 #[ignore_malloc_size_of = "Defined in html5ever"]
122 #[no_trace]
123 network_input: BufferQueue,
124 #[ignore_malloc_size_of = "Defined in html5ever"]
126 #[no_trace]
127 script_input: BufferQueue,
128 tokenizer: Tokenizer,
130 last_chunk_received: Cell<bool>,
132 suspended: Cell<bool>,
134 script_nesting_level: Cell<usize>,
136 aborted: Cell<bool>,
138 script_created_parser: bool,
140 #[no_trace]
145 prefetch_decoder: RefCell<LossyDecoder<NetworkSink>>,
146 prefetch_tokenizer: prefetch::Tokenizer,
150 #[ignore_malloc_size_of = "Defined in html5ever"]
151 #[no_trace]
152 prefetch_input: BufferQueue,
153 content_for_devtools: Option<DomRefCell<String>>,
156}
157
158pub(crate) struct ElementAttribute {
159 name: QualName,
160 value: DOMString,
161}
162
163#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
164pub(crate) enum ParsingAlgorithm {
165 Normal,
166 Fragment,
167}
168
169impl ElementAttribute {
170 pub(crate) fn new(name: QualName, value: DOMString) -> ElementAttribute {
171 ElementAttribute { name, value }
172 }
173}
174
175impl ServoParser {
176 pub(crate) fn parser_is_not_active(&self) -> bool {
177 self.can_write()
178 }
179
180 pub(crate) fn parse_html_document(
182 document: &Document,
183 input: Option<DOMString>,
184 url: ServoUrl,
185 encoding_hint_from_content_type: Option<&'static Encoding>,
186 encoding_of_container_document: Option<&'static Encoding>,
187 cx: &mut js::context::JSContext,
188 ) {
189 assert!(document.is_html_document());
193
194 let parser = ServoParser::new(
196 document,
197 if pref!(dom_servoparser_async_html_tokenizer_enabled) {
198 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None))
199 } else {
200 Tokenizer::Html(self::html::Tokenizer::new(
201 document,
202 url,
203 None,
204 ParsingAlgorithm::Normal,
205 ))
206 },
207 ParserKind::Normal,
208 encoding_hint_from_content_type,
209 encoding_of_container_document,
210 CanGc::from_cx(cx),
211 );
212
213 if let Some(input) = input {
219 parser.parse_complete_string_chunk(String::from(input), cx);
220 } else {
221 parser.document.set_current_parser(Some(&parser));
222 }
223 }
224
225 pub(crate) fn parse_html_fragment<'el>(
227 context: &'el Element,
228 input: DOMString,
229 allow_declarative_shadow_roots: bool,
230 cx: &mut js::context::JSContext,
231 ) -> impl Iterator<Item = DomRoot<Node>> + use<'el> {
232 let context_node = context.upcast::<Node>();
233 let context_document = context_node.owner_doc();
234 let window = context_document.window();
235 let url = context_document.url();
236
237 let loader = DocumentLoader::new_with_threads(
239 context_document.loader().resource_threads().clone(),
240 Some(url.clone()),
241 );
242 let document = Document::new(
243 window,
244 HasBrowsingContext::No,
245 Some(url.clone()),
246 context_document.about_base_url(),
247 context_document.origin().clone(),
248 IsHTMLDocument::HTMLDocument,
249 None,
250 None,
251 DocumentActivity::Inactive,
252 DocumentSource::FromParser,
253 loader,
254 None,
255 None,
256 Default::default(),
257 false,
258 allow_declarative_shadow_roots,
259 Some(context_document.insecure_requests_policy()),
260 context_document.has_trustworthy_ancestor_or_current_origin(),
261 context_document.custom_element_reaction_stack(),
262 context_document.creation_sandboxing_flag_set(),
263 CanGc::from_cx(cx),
264 );
265
266 document.set_quirks_mode(context_document.quirks_mode());
270
271 let form = context_node
278 .inclusive_ancestors(ShadowIncluding::No)
279 .find(|element| element.is::<HTMLFormElement>());
280
281 let fragment_context = FragmentContext {
282 context_elem: context_node,
283 form_elem: form.as_deref(),
284 context_element_allows_scripting: context_document.scripting_enabled(),
285 };
286
287 let parser = ServoParser::new(
288 &document,
289 Tokenizer::Html(self::html::Tokenizer::new(
290 &document,
291 url,
292 Some(fragment_context),
293 ParsingAlgorithm::Fragment,
294 )),
295 ParserKind::Normal,
296 None,
297 None,
298 CanGc::from_cx(cx),
299 );
300 parser.parse_complete_string_chunk(String::from(input), cx);
301
302 let root_element = document.GetDocumentElement().expect("no document element");
304 FragmentParsingResult {
305 inner: root_element.upcast::<Node>().children(),
306 }
307 }
308
309 pub(crate) fn parse_html_script_input(document: &Document, url: ServoUrl) {
310 let parser = ServoParser::new(
311 document,
312 if pref!(dom_servoparser_async_html_tokenizer_enabled) {
313 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None))
314 } else {
315 Tokenizer::Html(self::html::Tokenizer::new(
316 document,
317 url,
318 None,
319 ParsingAlgorithm::Normal,
320 ))
321 },
322 ParserKind::ScriptCreated,
323 None,
324 None,
325 CanGc::note(),
326 );
327 document.set_current_parser(Some(&parser));
328 }
329
330 pub(crate) fn parse_xml_document(
331 document: &Document,
332 input: Option<DOMString>,
333 url: ServoUrl,
334 encoding_hint_from_content_type: Option<&'static Encoding>,
335 cx: &mut js::context::JSContext,
336 ) {
337 let parser = ServoParser::new(
338 document,
339 Tokenizer::Xml(self::xml::Tokenizer::new(document, url)),
340 ParserKind::Normal,
341 encoding_hint_from_content_type,
342 None,
343 CanGc::from_cx(cx),
344 );
345
346 if let Some(input) = input {
348 parser.parse_complete_string_chunk(String::from(input), cx);
349 } else {
350 parser.document.set_current_parser(Some(&parser));
351 }
352 }
353
354 pub(crate) fn script_nesting_level(&self) -> usize {
355 self.script_nesting_level.get()
356 }
357
358 pub(crate) fn is_script_created(&self) -> bool {
359 self.script_created_parser
360 }
361
362 pub(crate) fn resume_with_pending_parsing_blocking_script(
377 &self,
378 script: &HTMLScriptElement,
379 result: ScriptResult,
380 cx: &mut js::context::JSContext,
381 ) {
382 assert!(self.suspended.get());
383 self.suspended.set(false);
384
385 self.script_input.swap_with(&self.network_input);
386 while let Some(chunk) = self.script_input.pop_front() {
387 self.network_input.push_back(chunk);
388 }
389
390 let script_nesting_level = self.script_nesting_level.get();
391 assert_eq!(script_nesting_level, 0);
392
393 self.script_nesting_level.set(script_nesting_level + 1);
394 script.execute(result, CanGc::from_cx(cx));
395 self.script_nesting_level.set(script_nesting_level);
396
397 if !self.suspended.get() && !self.aborted.get() {
398 self.parse_sync(cx);
399 }
400 }
401
402 pub(crate) fn can_write(&self) -> bool {
403 self.script_created_parser || self.script_nesting_level.get() > 0
404 }
405
406 pub(crate) fn write(&self, text: DOMString, cx: &mut js::context::JSContext) {
408 assert!(self.can_write());
409
410 if self.document.has_pending_parsing_blocking_script() {
411 self.script_input.push_back(String::from(text).into());
415 return;
416 }
417
418 assert!(self.script_input.is_empty());
422
423 let input = BufferQueue::default();
424 input.push_back(String::from(text).into());
425
426 let profiler_chan = self
427 .document
428 .window()
429 .as_global_scope()
430 .time_profiler_chan()
431 .clone();
432 let profiler_metadata = TimerMetadata {
433 url: self.document.url().as_str().into(),
434 iframe: TimerMetadataFrameType::RootWindow,
435 incremental: TimerMetadataReflowType::FirstReflow,
436 };
437 self.tokenize(
438 |cx, tokenizer| {
439 tokenizer.feed(&input, cx, profiler_chan.clone(), profiler_metadata.clone())
440 },
441 cx,
442 );
443
444 if self.suspended.get() {
445 while let Some(chunk) = input.pop_front() {
449 self.script_input.push_back(chunk);
450 }
451 return;
452 }
453
454 assert!(input.is_empty());
455 }
456
457 pub(crate) fn close(&self, cx: &mut js::context::JSContext) {
459 assert!(self.script_created_parser);
460
461 self.last_chunk_received.set(true);
463
464 if self.suspended.get() {
466 return;
467 }
468
469 self.parse_sync(cx);
472 }
473
474 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
476 assert!(!self.aborted.get());
477 self.aborted.set(true);
478
479 self.script_input.replace_with(BufferQueue::default());
481 self.network_input.replace_with(BufferQueue::default());
482
483 self.document
485 .set_ready_state(DocumentReadyState::Interactive, CanGc::from_cx(cx));
486
487 self.tokenizer.end(cx);
489 self.document.set_current_parser(None);
490
491 self.document
493 .set_ready_state(DocumentReadyState::Complete, CanGc::from_cx(cx));
494 }
495
496 pub(crate) fn is_active(&self) -> bool {
498 self.script_nesting_level() > 0 && !self.aborted.get()
499 }
500
501 pub(crate) fn get_current_line(&self) -> u32 {
502 self.tokenizer.get_current_line()
503 }
504
505 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
506 fn new_inherited(
507 document: &Document,
508 tokenizer: Tokenizer,
509 kind: ParserKind,
510 encoding_hint_from_content_type: Option<&'static Encoding>,
511 encoding_of_container_document: Option<&'static Encoding>,
512 ) -> Self {
513 let content_for_devtools = (document.global().devtools_chan().is_some() &&
517 document.has_browsing_context())
518 .then_some(DomRefCell::new(String::new()));
519
520 ServoParser {
521 reflector: Reflector::new(),
522 document: Dom::from_ref(document),
523 network_decoder: DomRefCell::new(NetworkDecoderState::new(
524 encoding_hint_from_content_type,
525 encoding_of_container_document,
526 )),
527 network_input: BufferQueue::default(),
528 script_input: BufferQueue::default(),
529 tokenizer,
530 last_chunk_received: Cell::new(false),
531 suspended: Default::default(),
532 script_nesting_level: Default::default(),
533 aborted: Default::default(),
534 script_created_parser: kind == ParserKind::ScriptCreated,
535 prefetch_decoder: RefCell::new(LossyDecoder::new_encoding_rs(
536 encoding_hint_from_content_type.unwrap_or(UTF_8),
537 Default::default(),
538 )),
539 prefetch_tokenizer: prefetch::Tokenizer::new(document),
540 prefetch_input: BufferQueue::default(),
541 content_for_devtools,
542 }
543 }
544
545 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
546 fn new(
547 document: &Document,
548 tokenizer: Tokenizer,
549 kind: ParserKind,
550 encoding_hint_from_content_type: Option<&'static Encoding>,
551 encoding_of_container_document: Option<&'static Encoding>,
552 can_gc: CanGc,
553 ) -> DomRoot<Self> {
554 reflect_dom_object(
555 Box::new(ServoParser::new_inherited(
556 document,
557 tokenizer,
558 kind,
559 encoding_hint_from_content_type,
560 encoding_of_container_document,
561 )),
562 document.window(),
563 can_gc,
564 )
565 }
566
567 fn push_tendril_input_chunk(&self, chunk: StrTendril) {
568 if let Some(mut content_for_devtools) = self
569 .content_for_devtools
570 .as_ref()
571 .map(|content| content.borrow_mut())
572 {
573 content_for_devtools.push_str(chunk.as_ref());
575 }
576
577 if chunk.is_empty() {
578 return;
579 }
580
581 self.network_input.push_back(chunk);
584 }
585
586 fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
587 if let Some(decoded_chunk) = self
589 .network_decoder
590 .borrow_mut()
591 .push(&chunk, &self.document)
592 {
593 self.push_tendril_input_chunk(decoded_chunk);
594 }
595
596 if self.should_prefetch() {
597 let mut prefetch_decoder = self.prefetch_decoder.borrow_mut();
603 prefetch_decoder.process(ByteTendril::from(&*chunk));
604
605 self.prefetch_input
606 .push_back(mem::take(&mut prefetch_decoder.inner_sink_mut().output));
607 self.prefetch_tokenizer.feed(&self.prefetch_input);
608 }
609 }
610
611 fn should_prefetch(&self) -> bool {
612 self.document.browsing_context().is_some()
620 }
621
622 fn push_string_input_chunk(&self, chunk: String) {
623 let chunk = StrTendril::from(chunk);
626 self.push_tendril_input_chunk(chunk);
627 }
628
629 fn parse_sync(&self, cx: &mut js::context::JSContext) {
630 assert!(self.script_input.is_empty());
631
632 if self.last_chunk_received.get() {
636 let chunk = self.network_decoder.borrow_mut().finish(&self.document);
637 if !chunk.is_empty() {
638 self.push_tendril_input_chunk(chunk);
639 }
640 }
641
642 if self.aborted.get() {
643 return;
644 }
645
646 let profiler_chan = self
647 .document
648 .window()
649 .as_global_scope()
650 .time_profiler_chan()
651 .clone();
652 let profiler_metadata = TimerMetadata {
653 url: self.document.url().as_str().into(),
654 iframe: TimerMetadataFrameType::RootWindow,
655 incremental: TimerMetadataReflowType::FirstReflow,
656 };
657 self.tokenize(
658 |cx, tokenizer| {
659 tokenizer.feed(
660 &self.network_input,
661 cx,
662 profiler_chan.clone(),
663 profiler_metadata.clone(),
664 )
665 },
666 cx,
667 );
668
669 if self.suspended.get() {
670 return;
671 }
672
673 assert!(self.network_input.is_empty());
674
675 if self.last_chunk_received.get() {
676 self.finish(cx);
677 }
678 }
679
680 fn parse_complete_string_chunk(&self, input: String, cx: &mut js::context::JSContext) {
681 self.document.set_current_parser(Some(self));
682 self.push_string_input_chunk(input);
683 self.last_chunk_received.set(true);
684 if !self.suspended.get() {
685 self.parse_sync(cx);
686 }
687 }
688
689 fn parse_bytes_chunk(&self, input: Vec<u8>, cx: &mut js::context::JSContext) {
690 let _realm = enter_realm(&*self.document);
691 self.document.set_current_parser(Some(self));
692 self.push_bytes_input_chunk(input);
693 if !self.suspended.get() {
694 self.parse_sync(cx);
695 }
696 }
697
698 fn tokenize<F>(&self, feed: F, cx: &mut js::context::JSContext)
699 where
700 F: Fn(
701 &mut js::context::JSContext,
702 &Tokenizer,
703 ) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
704 {
705 loop {
706 assert!(!self.suspended.get());
707 assert!(!self.aborted.get());
708
709 self.document.window().reflow_if_reflow_timer_expired();
710 let script = match feed(cx, &self.tokenizer) {
711 TokenizerResult::Done => return,
712 TokenizerResult::EncodingIndicator(_) => continue,
713 TokenizerResult::Script(script) => script,
714 };
715
716 if is_execution_stack_empty() {
723 self.document.window().perform_a_microtask_checkpoint(cx);
724 }
725
726 let script_nesting_level = self.script_nesting_level.get();
727
728 self.script_nesting_level.set(script_nesting_level + 1);
729 script.set_initial_script_text();
730 let introduction_type_override =
731 (script_nesting_level > 0).then_some(IntroductionType::INJECTED_SCRIPT);
732 script.prepare(introduction_type_override, CanGc::from_cx(cx));
733 self.script_nesting_level.set(script_nesting_level);
734
735 if self.document.has_pending_parsing_blocking_script() {
736 self.suspended.set(true);
737 return;
738 }
739 if self.aborted.get() {
740 return;
741 }
742 }
743 }
744
745 fn finish(&self, cx: &mut js::context::JSContext) {
747 assert!(!self.suspended.get());
748 assert!(self.last_chunk_received.get());
749 assert!(self.script_input.is_empty());
750 assert!(self.network_input.is_empty());
751 assert!(self.network_decoder.borrow().is_finished());
752
753 self.document
755 .set_ready_state(DocumentReadyState::Interactive, CanGc::from_cx(cx));
756
757 self.tokenizer.end(cx);
759 self.document.set_current_parser(None);
760
761 let url = self.tokenizer.url().clone();
763 self.document.finish_load(LoadType::PageSource(url), cx);
764
765 if let Some(content_for_devtools) = self
767 .content_for_devtools
768 .as_ref()
769 .map(|content| content.take())
770 {
771 let global = self.document.global();
772 let chan = global.devtools_chan().expect("Guaranteed by new");
773 let pipeline_id = self.document.global().pipeline_id();
774 let _ = chan.send(ScriptToDevtoolsControlMsg::UpdateSourceContent(
775 pipeline_id,
776 content_for_devtools,
777 ));
778 }
779 }
780}
781
782struct FragmentParsingResult<I>
783where
784 I: Iterator<Item = DomRoot<Node>>,
785{
786 inner: I,
787}
788
789impl<I> Iterator for FragmentParsingResult<I>
790where
791 I: Iterator<Item = DomRoot<Node>>,
792{
793 type Item = DomRoot<Node>;
794
795 #[expect(unsafe_code)]
796 fn next(&mut self) -> Option<DomRoot<Node>> {
797 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
798 let cx = &mut cx;
799
800 let next = self.inner.next()?;
801 next.remove_self(cx);
802 Some(next)
803 }
804
805 fn size_hint(&self) -> (usize, Option<usize>) {
806 self.inner.size_hint()
807 }
808}
809
810#[derive(JSTraceable, MallocSizeOf, PartialEq)]
811enum ParserKind {
812 Normal,
813 ScriptCreated,
814}
815
816#[derive(JSTraceable, MallocSizeOf)]
817#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
818enum Tokenizer {
819 Html(self::html::Tokenizer),
820 AsyncHtml(self::async_html::Tokenizer),
821 Xml(self::xml::Tokenizer),
822}
823
824impl Tokenizer {
825 fn feed(
826 &self,
827 input: &BufferQueue,
828 cx: &mut js::context::JSContext,
829 profiler_chan: ProfilerChan,
830 profiler_metadata: TimerMetadata,
831 ) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
832 match *self {
833 Tokenizer::Html(ref tokenizer) => time_profile!(
834 ProfilerCategory::ScriptParseHTML,
835 Some(profiler_metadata),
836 profiler_chan,
837 || tokenizer.feed(input),
838 ),
839 Tokenizer::AsyncHtml(ref tokenizer) => time_profile!(
840 ProfilerCategory::ScriptParseHTML,
841 Some(profiler_metadata),
842 profiler_chan,
843 || tokenizer.feed(input, cx),
844 ),
845 Tokenizer::Xml(ref tokenizer) => time_profile!(
846 ProfilerCategory::ScriptParseXML,
847 Some(profiler_metadata),
848 profiler_chan,
849 || tokenizer.feed(input),
850 ),
851 }
852 }
853
854 fn end(&self, cx: &mut js::context::JSContext) {
855 match *self {
856 Tokenizer::Html(ref tokenizer) => tokenizer.end(),
857 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(cx),
858 Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
859 }
860 }
861
862 fn url(&self) -> &ServoUrl {
863 match *self {
864 Tokenizer::Html(ref tokenizer) => tokenizer.url(),
865 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.url(),
866 Tokenizer::Xml(ref tokenizer) => tokenizer.url(),
867 }
868 }
869
870 fn set_plaintext_state(&self) {
871 match *self {
872 Tokenizer::Html(ref tokenizer) => tokenizer.set_plaintext_state(),
873 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.set_plaintext_state(),
874 Tokenizer::Xml(_) => unimplemented!(),
875 }
876 }
877
878 fn get_current_line(&self) -> u32 {
879 match *self {
880 Tokenizer::Html(ref tokenizer) => tokenizer.get_current_line(),
881 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.get_current_line(),
882 Tokenizer::Xml(ref tokenizer) => tokenizer.get_current_line(),
883 }
884 }
885}
886
887struct NavigationParams {
891 policy_container: PolicyContainer,
893 content_type: Option<Mime>,
895 link_headers: Vec<LinkHeader>,
897 final_sandboxing_flag_set: SandboxingFlagSet,
899 resource_header: Vec<u8>,
901 about_base_url: Option<ServoUrl>,
903}
904
905pub(crate) struct ParserContext {
908 parser: Option<Trusted<ServoParser>>,
910 is_synthesized_document: bool,
912 has_loaded_document: bool,
914 webview_id: WebViewId,
916 pipeline_id: PipelineId,
918 url: ServoUrl,
920 pushed_entry_index: Option<usize>,
922 navigation_params: NavigationParams,
924}
925
926impl ParserContext {
927 pub(crate) fn new(
928 webview_id: WebViewId,
929 pipeline_id: PipelineId,
930 url: ServoUrl,
931 creation_sandboxing_flag_set: SandboxingFlagSet,
932 ) -> ParserContext {
933 ParserContext {
934 parser: None,
935 is_synthesized_document: false,
936 has_loaded_document: false,
937 webview_id,
938 pipeline_id,
939 url,
940 pushed_entry_index: None,
941 navigation_params: NavigationParams {
942 policy_container: Default::default(),
943 content_type: None,
944 link_headers: vec![],
945 final_sandboxing_flag_set: creation_sandboxing_flag_set,
946 resource_header: vec![],
947 about_base_url: Default::default(),
948 },
949 }
950 }
951
952 pub(crate) fn set_policy_container(&mut self, policy_container: Option<&PolicyContainer>) {
953 let Some(policy_container) = policy_container else {
954 return;
955 };
956 self.navigation_params.policy_container = policy_container.clone();
957 }
958
959 pub(crate) fn set_about_base_url(&mut self, about_base_url: Option<ServoUrl>) {
960 self.navigation_params.about_base_url = about_base_url;
961 }
962
963 pub(crate) fn get_document(&self) -> Option<DomRoot<Document>> {
964 self.parser
965 .as_ref()
966 .map(|parser| parser.root().document.as_rooted())
967 }
968
969 fn create_policy_container_from_fetch_response(metadata: &Metadata) -> PolicyContainer {
971 PolicyContainer {
976 csp_list: parse_csp_list_from_metadata(&metadata.headers),
978 referrer_policy: ReferrerPolicy::parse_header_for_response(&metadata.headers),
980 }
981 }
982
983 fn initialize_document_object(&self, document: &Document) {
985 document.set_policy_container(self.navigation_params.policy_container.clone());
987 document.set_active_sandboxing_flag_set(self.navigation_params.final_sandboxing_flag_set);
988 document.set_about_base_url(self.navigation_params.about_base_url.clone());
989 process_link_headers(
991 &self.navigation_params.link_headers,
992 document,
993 LinkProcessingPhase::PreMedia,
994 );
995 }
996
997 fn process_link_headers_in_media_phase_with_task(&mut self, document: &Document) {
999 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
1003 if !link_headers.is_empty() {
1004 let window = document.window();
1005 let document = Trusted::new(document);
1006 window
1007 .upcast::<GlobalScope>()
1008 .task_manager()
1009 .networking_task_source()
1010 .queue(task!(process_link_headers_task: move || {
1011 process_link_headers(&link_headers, &document.root(), LinkProcessingPhase::Media);
1012 }));
1013 }
1014 }
1015
1016 fn load_document(&mut self, cx: &mut js::context::JSContext) {
1018 assert!(!self.has_loaded_document);
1019 self.has_loaded_document = true;
1020 let Some(ref parser) = self.parser.as_ref().map(|p| p.root()) else {
1021 return;
1022 };
1023 let content_type = &self.navigation_params.content_type;
1025 let mime_type = MimeClassifier::default().classify(
1026 LoadContext::Browsing,
1027 NoSniffFlag::Off,
1028 ApacheBugFlag::from_content_type(content_type.as_ref()),
1029 content_type,
1030 &self.navigation_params.resource_header,
1031 );
1032 let Some(media_type) = MimeClassifier::get_media_type(&mime_type) else {
1036 let page = format!(
1037 "<html><body><p>Unknown content type ({}).</p></body></html>",
1038 &mime_type,
1039 );
1040 self.load_inline_unknown_content(parser, page, cx);
1041 return;
1042 };
1043 match media_type {
1044 MediaType::Html => self.load_html_document(parser),
1046 MediaType::Xml => self.load_xml_document(parser),
1048 MediaType::JavaScript | MediaType::Json | MediaType::Text | MediaType::Css => {
1050 self.load_text_document(parser, cx)
1051 },
1052 MediaType::Image | MediaType::AudioVideo => {
1054 self.load_media_document(parser, media_type, &mime_type, cx);
1055 return;
1056 },
1057 MediaType::Font => {
1058 let page = format!(
1059 "<html><body><p>Unable to load font with content type ({}).</p></body></html>",
1060 &mime_type,
1061 );
1062 self.load_inline_unknown_content(parser, page, cx);
1063 return;
1064 },
1065 };
1066
1067 parser.parse_bytes_chunk(
1068 std::mem::take(&mut self.navigation_params.resource_header),
1069 cx,
1070 );
1071 }
1072
1073 fn load_html_document(&mut self, parser: &ServoParser) {
1075 self.initialize_document_object(&parser.document);
1078 self.process_link_headers_in_media_phase_with_task(&parser.document);
1082 }
1083
1084 fn load_xml_document(&mut self, parser: &ServoParser) {
1086 self.initialize_document_object(&parser.document);
1092 self.process_link_headers_in_media_phase_with_task(&parser.document);
1096 }
1097
1098 fn load_text_document(&mut self, parser: &ServoParser, cx: &mut js::context::JSContext) {
1100 self.initialize_document_object(&parser.document);
1103 let page = "<pre>\n".into();
1110 parser.push_string_input_chunk(page);
1111 parser.parse_sync(cx);
1112 parser.tokenizer.set_plaintext_state();
1113 self.process_link_headers_in_media_phase_with_task(&parser.document);
1117 }
1118
1119 fn load_media_document(
1121 &mut self,
1122 parser: &ServoParser,
1123 media_type: MediaType,
1124 mime_type: &Mime,
1125 cx: &mut js::context::JSContext,
1126 ) {
1127 self.initialize_document_object(&parser.document);
1130 self.is_synthesized_document = true;
1132 let page = "<html><body></body></html>".into();
1134 parser.push_string_input_chunk(page);
1135 parser.parse_sync(cx);
1136
1137 let doc = &parser.document;
1138 let node = if media_type == MediaType::Image {
1141 let img = Element::create(
1142 QualName::new(None, ns!(html), local_name!("img")),
1143 None,
1144 doc,
1145 ElementCreator::ParserCreated(1),
1146 CustomElementCreationMode::Asynchronous,
1147 None,
1148 CanGc::from_cx(cx),
1149 );
1150 let img = DomRoot::downcast::<HTMLImageElement>(img).unwrap();
1151 img.SetSrc(USVString(self.url.to_string()));
1152 DomRoot::upcast::<Node>(img)
1153 } else if mime_type.type_() == mime::AUDIO {
1154 let audio = Element::create(
1155 QualName::new(None, ns!(html), local_name!("audio")),
1156 None,
1157 doc,
1158 ElementCreator::ParserCreated(1),
1159 CustomElementCreationMode::Asynchronous,
1160 None,
1161 CanGc::from_cx(cx),
1162 );
1163 let audio = DomRoot::downcast::<HTMLMediaElement>(audio).unwrap();
1164 audio.SetControls(true);
1165 audio.SetSrc(USVString(self.url.to_string()));
1166 DomRoot::upcast::<Node>(audio)
1167 } else {
1168 let video = Element::create(
1169 QualName::new(None, ns!(html), local_name!("video")),
1170 None,
1171 doc,
1172 ElementCreator::ParserCreated(1),
1173 CustomElementCreationMode::Asynchronous,
1174 None,
1175 CanGc::from_cx(cx),
1176 );
1177 let video = DomRoot::downcast::<HTMLMediaElement>(video).unwrap();
1178 video.SetControls(true);
1179 video.SetSrc(USVString(self.url.to_string()));
1180 DomRoot::upcast::<Node>(video)
1181 };
1182 let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap());
1184 doc_body
1185 .AppendChild(&node, CanGc::from_cx(cx))
1186 .expect("Appending failed");
1187 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
1189 process_link_headers(&link_headers, doc, LinkProcessingPhase::Media);
1190 }
1191
1192 fn load_inline_unknown_content(
1194 &mut self,
1195 parser: &ServoParser,
1196 page: String,
1197 cx: &mut js::context::JSContext,
1198 ) {
1199 self.is_synthesized_document = true;
1200 parser.push_string_input_chunk(page);
1201 parser.parse_sync(cx);
1202 }
1203
1204 fn submit_resource_timing(&mut self) {
1206 let Some(parser) = self.parser.as_ref() else {
1207 return;
1208 };
1209 let parser = parser.root();
1210 if parser.aborted.get() {
1211 return;
1212 }
1213
1214 let document = &parser.document;
1215
1216 let performance_entry = PerformanceNavigationTiming::new(
1218 &document.global(),
1219 CrossProcessInstant::now(),
1220 document,
1221 CanGc::note(),
1222 );
1223 self.pushed_entry_index = document
1224 .global()
1225 .performance()
1226 .queue_entry(performance_entry.upcast::<PerformanceEntry>());
1227 }
1228}
1229
1230impl FetchResponseListener for ParserContext {
1231 fn process_request_body(&mut self, _: RequestId) {}
1232
1233 fn process_request_eof(&mut self, _: RequestId) {}
1234
1235 #[expect(unsafe_code)]
1236 fn process_response(&mut self, _: RequestId, meta_result: Result<FetchMetadata, NetworkError>) {
1237 let mut cx = unsafe { temp_cx() };
1239 let cx = &mut cx;
1240 let (metadata, error) = match meta_result {
1241 Ok(meta) => (
1242 Some(match meta {
1243 FetchMetadata::Unfiltered(m) => m,
1244 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
1245 }),
1246 None,
1247 ),
1248 Err(error) => (
1249 match &error {
1251 NetworkError::LoadCancelled => {
1252 return;
1253 },
1254 _ => {
1255 let mut meta = Metadata::default(self.url.clone());
1256 let mime: Option<Mime> = "text/html".parse().ok();
1257 meta.set_content_type(mime.as_ref());
1258 Some(meta)
1259 },
1260 },
1261 Some(error),
1262 ),
1263 };
1264 let content_type: Option<Mime> = metadata
1265 .clone()
1266 .and_then(|meta| meta.content_type)
1267 .map(Serde::into_inner)
1268 .map(Into::into);
1269
1270 let (policy_container, endpoints_list, link_headers) = match metadata.as_ref() {
1271 None => (PolicyContainer::default(), None, vec![]),
1272 Some(metadata) => (
1273 Self::create_policy_container_from_fetch_response(metadata),
1274 ReportingEndpoint::parse_reporting_endpoints_header(
1275 &self.url.clone(),
1276 &metadata.headers,
1277 ),
1278 extract_links_from_headers(&metadata.headers),
1279 ),
1280 };
1281
1282 let parser = match ScriptThread::page_headers_available(
1283 self.webview_id,
1284 self.pipeline_id,
1285 metadata,
1286 cx,
1287 ) {
1288 Some(parser) => parser,
1289 None => return,
1290 };
1291 if parser.aborted.get() {
1292 return;
1293 }
1294
1295 let mut realm = enter_auto_realm(cx, &*parser.document);
1296 let cx = &mut realm;
1297 let window = parser.document.window();
1298
1299 let final_sandboxing_flag_set = policy_container
1306 .csp_list
1307 .as_ref()
1308 .and_then(|csp| csp.get_sandboxing_flag_set_for_document())
1309 .unwrap_or(SandboxingFlagSet::empty())
1310 .union(parser.document.creation_sandboxing_flag_set());
1311
1312 if let Some(endpoints) = endpoints_list {
1313 window.set_endpoints_list(endpoints);
1314 }
1315 self.parser = Some(Trusted::new(&*parser));
1316 self.navigation_params = NavigationParams {
1317 policy_container,
1318 content_type,
1319 final_sandboxing_flag_set,
1320 link_headers,
1321 about_base_url: parser.document.about_base_url(),
1322 resource_header: vec![],
1323 };
1324 self.submit_resource_timing();
1325
1326 if let Some(error) = error {
1334 let page = match error {
1335 NetworkError::SslValidation(reason, bytes) => {
1336 let page = resources::read_string(Resource::BadCertHTML);
1337 let page = page.replace("${reason}", &reason);
1338 let encoded_bytes = general_purpose::STANDARD_NO_PAD.encode(bytes);
1339 let page = page.replace("${bytes}", encoded_bytes.as_str());
1340 page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string())
1341 },
1342 NetworkError::BlobURLStoreError(reason) |
1343 NetworkError::WebsocketConnectionFailure(reason) |
1344 NetworkError::HttpError(reason) |
1345 NetworkError::ResourceLoadError(reason) |
1346 NetworkError::MimeType(reason) => {
1347 let page = resources::read_string(Resource::NetErrorHTML);
1348 page.replace("${reason}", &reason)
1349 },
1350 NetworkError::Crash(details) => {
1351 let page = resources::read_string(Resource::CrashHTML);
1352 page.replace("${details}", &details)
1353 },
1354 NetworkError::UnsupportedScheme |
1355 NetworkError::CorsGeneral |
1356 NetworkError::CrossOriginResponse |
1357 NetworkError::CorsCredentials |
1358 NetworkError::CorsAllowMethods |
1359 NetworkError::CorsAllowHeaders |
1360 NetworkError::CorsMethod |
1361 NetworkError::CorsAuthorization |
1362 NetworkError::CorsHeaders |
1363 NetworkError::ConnectionFailure |
1364 NetworkError::RedirectError |
1365 NetworkError::TooManyRedirects |
1366 NetworkError::TooManyInFlightKeepAliveRequests |
1367 NetworkError::InvalidMethod |
1368 NetworkError::ContentSecurityPolicy |
1369 NetworkError::Nosniff |
1370 NetworkError::SubresourceIntegrity |
1371 NetworkError::MixedContent |
1372 NetworkError::CacheError |
1373 NetworkError::InvalidPort |
1374 NetworkError::LocalDirectoryError |
1375 NetworkError::PartialResponseToNonRangeRequestError |
1376 NetworkError::ProtocolHandlerSubstitutionError |
1377 NetworkError::DecompressionError => {
1378 let page = resources::read_string(Resource::NetErrorHTML);
1379 page.replace("${reason}", &format!("{:?}", error))
1380 },
1381 NetworkError::LoadCancelled => {
1382 return;
1384 },
1385 };
1386 self.load_inline_unknown_content(&parser, page, cx);
1387 }
1388 }
1389
1390 #[expect(unsafe_code)]
1391 fn process_response_chunk(&mut self, _: RequestId, payload: Vec<u8>) {
1392 let mut cx = unsafe { temp_cx() };
1394 let cx = &mut cx;
1395 if self.is_synthesized_document {
1396 return;
1397 }
1398 let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
1399 return;
1400 };
1401 if parser.aborted.get() {
1402 return;
1403 }
1404 if !self.has_loaded_document {
1405 self.navigation_params
1407 .resource_header
1408 .extend_from_slice(&payload);
1409 if self.navigation_params.resource_header.len() >= 1445 {
1411 self.load_document(cx);
1412 }
1413 } else {
1414 parser.parse_bytes_chunk(payload, cx);
1415 }
1416 }
1417
1418 fn process_response_eof(
1422 mut self,
1423 cx: &mut js::context::JSContext,
1424 _: RequestId,
1425 status: Result<(), NetworkError>,
1426 timing: ResourceFetchTiming,
1427 ) {
1428 let parser = match self.parser.as_ref() {
1429 Some(parser) => parser.root(),
1430 None => return,
1431 };
1432 if parser.aborted.get() {
1433 return;
1434 }
1435
1436 if let Err(error) = &status {
1437 debug!("Failed to load page URL {}, error: {error:?}", self.url);
1439 }
1440
1441 if !self.has_loaded_document {
1445 self.load_document(cx);
1446 }
1447
1448 let mut realm = enter_auto_realm(cx, &*parser);
1449 let cx = &mut realm;
1450
1451 if status.is_ok() {
1452 parser.document.set_redirect_count(timing.redirect_count);
1453 }
1454
1455 parser.last_chunk_received.set(true);
1456 if !parser.suspended.get() {
1457 parser.parse_sync(cx);
1458 }
1459
1460 if let Some(pushed_index) = self.pushed_entry_index {
1463 let document = &parser.document;
1464 let performance_entry = PerformanceNavigationTiming::new(
1465 &document.global(),
1466 CrossProcessInstant::now(),
1467 document,
1468 CanGc::from_cx(cx),
1469 );
1470 document
1471 .global()
1472 .performance()
1473 .update_entry(pushed_index, performance_entry.upcast::<PerformanceEntry>());
1474 }
1475 }
1476
1477 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
1478 let parser = match self.parser.as_ref() {
1479 Some(parser) => parser.root(),
1480 None => return,
1481 };
1482 let document = &parser.document;
1483 let global = &document.global();
1484 global.report_csp_violations(violations, None, None);
1486 }
1487}
1488
1489pub(crate) struct FragmentContext<'a> {
1490 pub(crate) context_elem: &'a Node,
1491 pub(crate) form_elem: Option<&'a Node>,
1492 pub(crate) context_element_allows_scripting: bool,
1493}
1494
1495#[cfg_attr(crown, expect(crown::unrooted_must_root))]
1496fn insert(
1497 parent: &Node,
1498 reference_child: Option<&Node>,
1499 child: NodeOrText<Dom<Node>>,
1500 parsing_algorithm: ParsingAlgorithm,
1501 custom_element_reaction_stack: &CustomElementReactionStack,
1502 can_gc: CanGc,
1503) {
1504 match child {
1505 NodeOrText::AppendNode(n) => {
1506 let element_in_non_fragment =
1510 parsing_algorithm != ParsingAlgorithm::Fragment && n.is::<Element>();
1511 if element_in_non_fragment {
1512 custom_element_reaction_stack.push_new_element_queue();
1513 }
1514 parent.InsertBefore(&n, reference_child, can_gc).unwrap();
1515 if element_in_non_fragment {
1516 custom_element_reaction_stack.pop_current_element_queue(can_gc);
1517 }
1518 },
1519 NodeOrText::AppendText(t) => {
1520 let text = reference_child
1522 .and_then(Node::GetPreviousSibling)
1523 .or_else(|| parent.GetLastChild())
1524 .and_then(DomRoot::downcast::<Text>);
1525
1526 if let Some(text) = text {
1527 text.upcast::<CharacterData>().append_data(&t);
1528 } else {
1529 let text = Text::new(String::from(t).into(), &parent.owner_doc(), can_gc);
1530 parent
1531 .InsertBefore(text.upcast(), reference_child, can_gc)
1532 .unwrap();
1533 }
1534 },
1535 }
1536}
1537
1538#[derive(JSTraceable, MallocSizeOf)]
1539#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
1540pub(crate) struct Sink {
1541 #[no_trace]
1542 base_url: ServoUrl,
1543 document: Dom<Document>,
1544 current_line: Cell<u64>,
1545 script: MutNullableDom<HTMLScriptElement>,
1546 parsing_algorithm: ParsingAlgorithm,
1547 #[conditional_malloc_size_of]
1548 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
1549}
1550
1551impl Sink {
1552 fn same_tree(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1553 let x = x.downcast::<Element>().expect("Element node expected");
1554 let y = y.downcast::<Element>().expect("Element node expected");
1555
1556 x.is_in_same_home_subtree(y)
1557 }
1558
1559 fn has_parent_node(&self, node: &Dom<Node>) -> bool {
1560 node.GetParentNode().is_some()
1561 }
1562}
1563
1564impl TreeSink for Sink {
1565 type Output = Self;
1566 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1567 fn finish(self) -> Self {
1568 self
1569 }
1570
1571 type Handle = Dom<Node>;
1572 type ElemName<'a>
1573 = ExpandedName<'a>
1574 where
1575 Self: 'a;
1576
1577 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1578 fn get_document(&self) -> Dom<Node> {
1579 Dom::from_ref(self.document.upcast())
1580 }
1581
1582 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1583 fn get_template_contents(&self, target: &Dom<Node>) -> Dom<Node> {
1584 let template = target
1585 .downcast::<HTMLTemplateElement>()
1586 .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
1587 Dom::from_ref(template.Content(CanGc::note()).upcast())
1588 }
1589
1590 fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1591 x == y
1592 }
1593
1594 fn elem_name<'a>(&self, target: &'a Dom<Node>) -> ExpandedName<'a> {
1595 let elem = target
1596 .downcast::<Element>()
1597 .expect("tried to get name of non-Element in HTML parsing");
1598 ExpandedName {
1599 ns: elem.namespace(),
1600 local: elem.local_name(),
1601 }
1602 }
1603
1604 #[expect(unsafe_code)]
1605 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1606 fn create_element(
1607 &self,
1608 name: QualName,
1609 attrs: Vec<Attribute>,
1610 flags: ElementFlags,
1611 ) -> Dom<Node> {
1612 let mut cx = unsafe { temp_cx() };
1614 let cx = &mut cx;
1615 let attrs = attrs
1616 .into_iter()
1617 .map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
1618 .collect();
1619 let parsing_algorithm = if flags.template {
1620 ParsingAlgorithm::Fragment
1621 } else {
1622 self.parsing_algorithm
1623 };
1624 let element = create_element_for_token(
1625 name,
1626 attrs,
1627 &self.document,
1628 ElementCreator::ParserCreated(self.current_line.get()),
1629 parsing_algorithm,
1630 &self.custom_element_reaction_stack,
1631 cx,
1632 );
1633 Dom::from_ref(element.upcast())
1634 }
1635
1636 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1637 fn create_comment(&self, text: StrTendril) -> Dom<Node> {
1638 let comment = Comment::new(
1639 DOMString::from(String::from(text)),
1640 &self.document,
1641 None,
1642 CanGc::note(),
1643 );
1644 Dom::from_ref(comment.upcast())
1645 }
1646
1647 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1648 fn create_pi(&self, target: StrTendril, data: StrTendril) -> Dom<Node> {
1649 let doc = &*self.document;
1650 let pi = ProcessingInstruction::new(
1651 DOMString::from(String::from(target)),
1652 DOMString::from(String::from(data)),
1653 doc,
1654 CanGc::note(),
1655 );
1656 Dom::from_ref(pi.upcast())
1657 }
1658
1659 fn associate_with_form(
1660 &self,
1661 target: &Dom<Node>,
1662 form: &Dom<Node>,
1663 nodes: (&Dom<Node>, Option<&Dom<Node>>),
1664 ) {
1665 let (element, prev_element) = nodes;
1666 let tree_node = prev_element.map_or(element, |prev| {
1667 if self.has_parent_node(element) {
1668 element
1669 } else {
1670 prev
1671 }
1672 });
1673 if !self.same_tree(tree_node, form) {
1674 return;
1675 }
1676
1677 let node = target;
1678 let form = DomRoot::downcast::<HTMLFormElement>(DomRoot::from_ref(&**form))
1679 .expect("Owner must be a form element");
1680
1681 let elem = node.downcast::<Element>();
1682 let control = elem.and_then(|e| e.as_maybe_form_control());
1683
1684 if let Some(control) = control {
1685 control.set_form_owner_from_parser(&form, CanGc::note());
1686 }
1687 }
1688
1689 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1690 fn append_before_sibling(&self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
1691 let parent = sibling
1692 .GetParentNode()
1693 .expect("append_before_sibling called on node without parent");
1694
1695 insert(
1696 &parent,
1697 Some(sibling),
1698 new_node,
1699 self.parsing_algorithm,
1700 &self.custom_element_reaction_stack,
1701 CanGc::note(),
1702 );
1703 }
1704
1705 fn parse_error(&self, msg: Cow<'static, str>) {
1706 debug!("Parse error: {}", msg);
1707 }
1708
1709 fn set_quirks_mode(&self, mode: QuirksMode) {
1710 let mode = match mode {
1711 QuirksMode::Quirks => ServoQuirksMode::Quirks,
1712 QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
1713 QuirksMode::NoQuirks => ServoQuirksMode::NoQuirks,
1714 };
1715 self.document.set_quirks_mode(mode);
1716 }
1717
1718 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1719 fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
1720 insert(
1721 parent,
1722 None,
1723 child,
1724 self.parsing_algorithm,
1725 &self.custom_element_reaction_stack,
1726 CanGc::note(),
1727 );
1728 }
1729
1730 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1731 fn append_based_on_parent_node(
1732 &self,
1733 elem: &Dom<Node>,
1734 prev_elem: &Dom<Node>,
1735 child: NodeOrText<Dom<Node>>,
1736 ) {
1737 if self.has_parent_node(elem) {
1738 self.append_before_sibling(elem, child);
1739 } else {
1740 self.append(prev_elem, child);
1741 }
1742 }
1743
1744 fn append_doctype_to_document(
1745 &self,
1746 name: StrTendril,
1747 public_id: StrTendril,
1748 system_id: StrTendril,
1749 ) {
1750 let doc = &*self.document;
1751 let doctype = DocumentType::new(
1752 DOMString::from(String::from(name)),
1753 Some(DOMString::from(String::from(public_id))),
1754 Some(DOMString::from(String::from(system_id))),
1755 doc,
1756 CanGc::note(),
1757 );
1758 doc.upcast::<Node>()
1759 .AppendChild(doctype.upcast(), CanGc::note())
1760 .expect("Appending failed");
1761 }
1762
1763 fn add_attrs_if_missing(&self, target: &Dom<Node>, attrs: Vec<Attribute>) {
1764 let elem = target
1765 .downcast::<Element>()
1766 .expect("tried to set attrs on non-Element in HTML parsing");
1767 for attr in attrs {
1768 elem.set_attribute_from_parser(
1769 attr.name,
1770 DOMString::from(String::from(attr.value)),
1771 None,
1772 CanGc::note(),
1773 );
1774 }
1775 }
1776
1777 #[expect(unsafe_code)]
1778 fn remove_from_parent(&self, target: &Dom<Node>) {
1779 let mut cx = unsafe { temp_cx() };
1781 let cx = &mut cx;
1782
1783 if let Some(ref parent) = target.GetParentNode() {
1784 parent.RemoveChild(cx, target).unwrap();
1785 }
1786 }
1787
1788 fn mark_script_already_started(&self, node: &Dom<Node>) {
1789 let script = node.downcast::<HTMLScriptElement>();
1790 if let Some(script) = script {
1791 script.set_already_started(true)
1792 }
1793 }
1794
1795 fn reparent_children(&self, node: &Dom<Node>, new_parent: &Dom<Node>) {
1796 while let Some(ref child) = node.GetFirstChild() {
1797 new_parent.AppendChild(child, CanGc::note()).unwrap();
1798 }
1799 }
1800
1801 fn is_mathml_annotation_xml_integration_point(&self, handle: &Dom<Node>) -> bool {
1804 let elem = handle.downcast::<Element>().unwrap();
1805 elem.get_attribute(&local_name!("encoding"))
1806 .is_some_and(|attr| {
1807 attr.value().eq_ignore_ascii_case("text/html") ||
1808 attr.value().eq_ignore_ascii_case("application/xhtml+xml")
1809 })
1810 }
1811
1812 fn set_current_line(&self, line_number: u64) {
1813 self.current_line.set(line_number);
1814 }
1815
1816 fn pop(&self, node: &Dom<Node>) {
1817 let node = DomRoot::from_ref(&**node);
1818 vtable_for(&node).pop();
1819 }
1820
1821 fn allow_declarative_shadow_roots(&self, intended_parent: &Dom<Node>) -> bool {
1822 intended_parent.owner_doc().allow_declarative_shadow_roots()
1823 }
1824
1825 fn attach_declarative_shadow(
1829 &self,
1830 host: &Dom<Node>,
1831 template: &Dom<Node>,
1832 attributes: &[Attribute],
1833 ) -> bool {
1834 attach_declarative_shadow_inner(host, template, attributes)
1835 }
1836
1837 #[expect(unsafe_code)]
1838 fn maybe_clone_an_option_into_selectedcontent(&self, option: &Self::Handle) {
1839 let mut cx = unsafe { temp_cx() };
1841 let cx = &mut cx;
1842
1843 let Some(option) = option.downcast::<HTMLOptionElement>() else {
1844 if cfg!(debug_assertions) {
1845 unreachable!();
1846 }
1847 log::error!(
1848 "Received non-option element in maybe_clone_an_option_into_selectedcontent"
1849 );
1850 return;
1851 };
1852
1853 option.maybe_clone_an_option_into_selectedcontent(cx)
1854 }
1855}
1856
1857fn create_element_for_token(
1859 name: QualName,
1860 attrs: Vec<ElementAttribute>,
1861 document: &Document,
1862 creator: ElementCreator,
1863 parsing_algorithm: ParsingAlgorithm,
1864 custom_element_reaction_stack: &CustomElementReactionStack,
1865 cx: &mut js::context::JSContext,
1866) -> DomRoot<Element> {
1867 let is = attrs
1885 .iter()
1886 .find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
1887 .map(|attr| LocalName::from(&attr.value));
1888
1889 let definition = document.lookup_custom_element_definition(&name.ns, &name.local, is.as_ref());
1895
1896 let will_execute_script =
1899 definition.is_some() && parsing_algorithm != ParsingAlgorithm::Fragment;
1900
1901 if will_execute_script {
1903 document.increment_throw_on_dynamic_markup_insertion_counter();
1905 if is_execution_stack_empty() {
1908 document.window().perform_a_microtask_checkpoint(cx);
1909 }
1910 custom_element_reaction_stack.push_new_element_queue()
1913 }
1914
1915 let creation_mode = if will_execute_script {
1918 CustomElementCreationMode::Synchronous
1919 } else {
1920 CustomElementCreationMode::Asynchronous
1921 };
1922 let element = Element::create(
1923 name,
1924 is,
1925 document,
1926 creator,
1927 creation_mode,
1928 None,
1929 CanGc::from_cx(cx),
1930 );
1931
1932 for attr in attrs {
1934 element.set_attribute_from_parser(attr.name, attr.value, None, CanGc::from_cx(cx));
1935 }
1936
1937 if will_execute_script {
1939 custom_element_reaction_stack.pop_current_element_queue(CanGc::from_cx(cx));
1944 document.decrement_throw_on_dynamic_markup_insertion_counter();
1946 }
1947
1948 if let Some(html_element) = element.downcast::<HTMLElement>() {
1958 if element.is_resettable() && !html_element.is_form_associated_custom_element() {
1959 element.reset(CanGc::from_cx(cx));
1960 }
1961 }
1962
1963 element
1973}
1974
1975fn attach_declarative_shadow_inner(host: &Node, template: &Node, attributes: &[Attribute]) -> bool {
1976 let host_element = host.downcast::<Element>().unwrap();
1977
1978 if host_element.shadow_root().is_some() {
1979 return false;
1980 }
1981
1982 let template_element = template.downcast::<HTMLTemplateElement>().unwrap();
1983
1984 let mut shadow_root_mode = ShadowRootMode::Open;
1991 let mut clonable = false;
1992 let mut delegatesfocus = false;
1993 let mut serializable = false;
1994
1995 let attributes: Vec<ElementAttribute> = attributes
1996 .iter()
1997 .map(|attr| {
1998 ElementAttribute::new(
1999 attr.name.clone(),
2000 DOMString::from(String::from(attr.value.clone())),
2001 )
2002 })
2003 .collect();
2004
2005 attributes
2006 .iter()
2007 .for_each(|attr: &ElementAttribute| match attr.name.local {
2008 local_name!("shadowrootmode") => {
2009 if attr.value.str().eq_ignore_ascii_case("open") {
2010 shadow_root_mode = ShadowRootMode::Open;
2011 } else if attr.value.str().eq_ignore_ascii_case("closed") {
2012 shadow_root_mode = ShadowRootMode::Closed;
2013 } else {
2014 unreachable!("shadowrootmode value is not open nor closed");
2015 }
2016 },
2017 local_name!("shadowrootclonable") => {
2018 clonable = true;
2019 },
2020 local_name!("shadowrootdelegatesfocus") => {
2021 delegatesfocus = true;
2022 },
2023 local_name!("shadowrootserializable") => {
2024 serializable = true;
2025 },
2026 _ => {},
2027 });
2028
2029 match host_element.attach_shadow(
2032 IsUserAgentWidget::No,
2033 shadow_root_mode,
2034 clonable,
2035 serializable,
2036 delegatesfocus,
2037 SlotAssignmentMode::Named,
2038 CanGc::note(),
2039 ) {
2040 Ok(shadow_root) => {
2041 shadow_root.set_declarative(true);
2043
2044 let shadow = shadow_root.upcast::<DocumentFragment>();
2046 template_element.set_contents(Some(shadow));
2047
2048 shadow_root.set_available_to_element_internals(true);
2050
2051 true
2052 },
2053 Err(_) => false,
2054 }
2055}