1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use bitflags::bitflags;
17use chrono::Local;
18use content_security_policy::sandboxing_directive::SandboxingFlagSet;
19use content_security_policy::{CspList, Policy as CspPolicy, PolicyDisposition};
20use cookie::Cookie;
21use data_url::mime::Mime;
22use devtools_traits::ScriptToDevtoolsControlMsg;
23use dom_struct::dom_struct;
24use embedder_traits::{
25 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, Image, LoadStatus,
26};
27use encoding_rs::{Encoding, UTF_8};
28use fonts::WebFontDocumentContext;
29use html5ever::{LocalName, Namespace, QualName, local_name, ns};
30use hyper_serde::Serde;
31use js::rust::{HandleObject, HandleValue, MutableHandleValue};
32use layout_api::{
33 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
34 ScrollContainerQueryFlags, TrustedNodeAddress,
35};
36use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
37use net_traits::CookieSource::NonHTTP;
38use net_traits::CoreResourceMsg::{GetCookieStringForUrl, SetCookiesForUrl};
39use net_traits::ReferrerPolicy;
40use net_traits::policy_container::PolicyContainer;
41use net_traits::pub_domains::is_pub_domain;
42use net_traits::request::{
43 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
44};
45use net_traits::response::HttpsState;
46use percent_encoding::percent_decode;
47use profile_traits::generic_channel as profile_generic_channel;
48use profile_traits::time::TimerMetadataFrameType;
49use regex::bytes::Regex;
50use rustc_hash::{FxBuildHasher, FxHashMap};
51use script_bindings::interfaces::DocumentHelpers;
52use script_bindings::script_runtime::JSContext;
53use script_traits::{DocumentActivity, ProgressiveWebMetricType};
54use servo_arc::Arc;
55use servo_base::cross_process_instant::CrossProcessInstant;
56use servo_base::generic_channel::GenericSend;
57use servo_base::id::WebViewId;
58use servo_base::{Epoch, generic_channel};
59use servo_config::pref;
60use servo_constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
61use servo_media::{ClientContextId, ServoMedia};
62use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
63use style::attr::AttrValue;
64use style::context::QuirksMode;
65use style::invalidation::element::restyle_hints::RestyleHint;
66use style::selector_parser::Snapshot;
67use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
68use style::str::{split_html_space_chars, str_join};
69use style::stylesheet_set::DocumentStylesheetSet;
70use style::stylesheets::{Origin, OriginSet, Stylesheet};
71use style::stylist::Stylist;
72use stylo_atoms::Atom;
73use time::Duration as TimeDuration;
74use url::{Host, Position};
75
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::animationtimeline::AnimationTimeline;
79use crate::dom::attr::Attr;
80use crate::dom::beforeunloadevent::BeforeUnloadEvent;
81use crate::dom::bindings::callback::ExceptionHandling;
82use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
83use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
84use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
85 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
86};
87use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
88use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
90#[cfg(any(feature = "webxr", feature = "gamepad"))]
91use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
92use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
93use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
94use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
95use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
96use crate::dom::bindings::codegen::Bindings::WindowBinding::{
97 FrameRequestCallback, ScrollBehavior, WindowMethods,
98};
99use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
100use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
101use crate::dom::bindings::codegen::UnionTypes::{
102 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
103};
104use crate::dom::bindings::domname::{
105 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
106};
107use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
108use crate::dom::bindings::frozenarray::CachedFrozenArray;
109use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
110use crate::dom::bindings::num::Finite;
111use crate::dom::bindings::refcounted::Trusted;
112use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
113use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout, UnrootedDom};
114use crate::dom::bindings::str::{DOMString, USVString};
115use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
116use crate::dom::bindings::weakref::DOMTracker;
117use crate::dom::bindings::xmlname::matches_name_production;
118use crate::dom::cdatasection::CDATASection;
119use crate::dom::comment::Comment;
120use crate::dom::compositionevent::CompositionEvent;
121use crate::dom::css::cssstylesheet::CSSStyleSheet;
122use crate::dom::css::fontfaceset::FontFaceSet;
123use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
124use crate::dom::customelementregistry::{
125 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
126};
127use crate::dom::customevent::CustomEvent;
128use crate::dom::document::focus::{DocumentFocusHandler, FocusableArea};
129use crate::dom::document_embedder_controls::DocumentEmbedderControls;
130use crate::dom::document_event_handler::DocumentEventHandler;
131use crate::dom::documentfragment::DocumentFragment;
132use crate::dom::documentorshadowroot::{
133 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
134};
135use crate::dom::documenttimeline::DocumentTimeline;
136use crate::dom::documenttype::DocumentType;
137use crate::dom::domimplementation::DOMImplementation;
138use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
139use crate::dom::event::{Event, EventBubbles, EventCancelable};
140use crate::dom::eventtarget::EventTarget;
141use crate::dom::execcommand::basecommand::{CommandName, DefaultSingleLineContainerName};
142use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
143use crate::dom::focusevent::FocusEvent;
144use crate::dom::globalscope::GlobalScope;
145use crate::dom::hashchangeevent::HashChangeEvent;
146use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
147use crate::dom::html::htmlareaelement::HTMLAreaElement;
148use crate::dom::html::htmlbaseelement::HTMLBaseElement;
149use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
150use crate::dom::html::htmlelement::HTMLElement;
151use crate::dom::html::htmlembedelement::HTMLEmbedElement;
152use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
153use crate::dom::html::htmlheadelement::HTMLHeadElement;
154use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
155use crate::dom::html::htmliframeelement::HTMLIFrameElement;
156use crate::dom::html::htmlimageelement::HTMLImageElement;
157use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
158use crate::dom::html::htmltitleelement::HTMLTitleElement;
159use crate::dom::htmldetailselement::DetailsNameGroups;
160use crate::dom::intersectionobserver::IntersectionObserver;
161use crate::dom::keyboardevent::KeyboardEvent;
162use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
163use crate::dom::location::Location;
164use crate::dom::messageevent::MessageEvent;
165use crate::dom::mouseevent::MouseEvent;
166use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
167use crate::dom::nodeiterator::NodeIterator;
168use crate::dom::nodelist::NodeList;
169use crate::dom::pagetransitionevent::PageTransitionEvent;
170use crate::dom::performance::performanceentry::PerformanceEntry;
171use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
172use crate::dom::processinginstruction::ProcessingInstruction;
173use crate::dom::promise::Promise;
174use crate::dom::range::Range;
175use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
176use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
177use crate::dom::selection::Selection;
178use crate::dom::servoparser::ServoParser;
179use crate::dom::shadowroot::ShadowRoot;
180use crate::dom::storageevent::StorageEvent;
181use crate::dom::text::Text;
182use crate::dom::touchevent::TouchEvent as DomTouchEvent;
183use crate::dom::touchlist::TouchList;
184use crate::dom::treewalker::TreeWalker;
185use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
186use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
187use crate::dom::uievent::UIEvent;
188use crate::dom::virtualmethods::vtable_for;
189use crate::dom::websocket::WebSocket;
190use crate::dom::window::Window;
191use crate::dom::windowproxy::WindowProxy;
192use crate::dom::xpathevaluator::XPathEvaluator;
193use crate::dom::xpathexpression::XPathExpression;
194use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
195use crate::iframe_collection::IFrameCollection;
196use crate::image_animation::ImageAnimationManager;
197use crate::mime::{APPLICATION, CHARSET};
198use crate::navigation::navigate;
199use crate::network_listener::{FetchResponseListener, NetworkListener};
200use crate::realms::enter_realm;
201use crate::script_runtime::CanGc;
202use crate::script_thread::ScriptThread;
203use crate::stylesheet_set::StylesheetSetRef;
204use crate::task::NonSendTaskBox;
205use crate::task_source::TaskSourceName;
206use crate::timers::OneshotTimerCallback;
207use crate::xpath::parse_expression;
208
209#[derive(Clone, Copy, PartialEq)]
210pub(crate) enum FireMouseEventType {
211 Move,
212 Over,
213 Out,
214 Enter,
215 Leave,
216}
217
218impl FireMouseEventType {
219 pub(crate) fn as_str(&self) -> &str {
220 match *self {
221 FireMouseEventType::Move => "mousemove",
222 FireMouseEventType::Over => "mouseover",
223 FireMouseEventType::Out => "mouseout",
224 FireMouseEventType::Enter => "mouseenter",
225 FireMouseEventType::Leave => "mouseleave",
226 }
227 }
228}
229
230#[derive(JSTraceable, MallocSizeOf)]
231pub(crate) struct RefreshRedirectDue {
232 #[no_trace]
233 pub(crate) url: ServoUrl,
234 #[ignore_malloc_size_of = "non-owning"]
235 pub(crate) window: DomRoot<Window>,
236}
237impl RefreshRedirectDue {
238 pub(crate) fn invoke(self, cx: &mut js::context::JSContext) {
240 let load_data = self
250 .window
251 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
252 navigate(
253 cx,
254 &self.window,
255 NavigationHistoryBehavior::Replace,
256 false,
257 load_data,
258 );
259 }
260}
261
262#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
263pub(crate) enum IsHTMLDocument {
264 HTMLDocument,
265 NonHTMLDocument,
266}
267
268#[derive(JSTraceable, MallocSizeOf)]
270pub(crate) enum DeclarativeRefresh {
271 PendingLoad {
272 #[no_trace]
273 url: ServoUrl,
274 time: u64,
275 },
276 CreatedAfterLoad,
277}
278
279#[derive(JSTraceable, MallocSizeOf, PartialEq)]
280#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
281struct PendingScrollEvent {
282 target: Dom<EventTarget>,
284 #[no_trace]
286 event: Atom,
287}
288
289impl PendingScrollEvent {
290 fn equivalent(&self, target: &EventTarget, event: &Atom) -> bool {
291 &*self.target == target && self.event == *event
292 }
293}
294
295#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
298pub(crate) struct RenderingUpdateReason(u8);
299
300bitflags! {
301 impl RenderingUpdateReason: u8 {
302 const ResizeObserverStartedObservingTarget = 1 << 0;
305 const IntersectionObserverStartedObservingTarget = 1 << 1;
308 const FontReadyPromiseFulfilled = 1 << 2;
312 }
313}
314
315#[dom_struct]
317pub(crate) struct Document {
318 node: Node,
319 document_or_shadow_root: DocumentOrShadowRoot,
320 window: Dom<Window>,
321 implementation: MutNullableDom<DOMImplementation>,
322 #[ignore_malloc_size_of = "type from external crate"]
323 #[no_trace]
324 content_type: Mime,
325 last_modified: Option<String>,
326 #[no_trace]
327 encoding: Cell<&'static Encoding>,
328 has_browsing_context: bool,
329 is_html_document: bool,
330 #[no_trace]
331 activity: Cell<DocumentActivity>,
332 #[no_trace]
334 url: DomRefCell<ServoUrl>,
335 #[no_trace]
337 about_base_url: DomRefCell<Option<ServoUrl>>,
338 #[ignore_malloc_size_of = "defined in selectors"]
339 #[no_trace]
340 quirks_mode: Cell<QuirksMode>,
341 event_handler: DocumentEventHandler,
343 focus_handler: DocumentFocusHandler,
345 embedder_controls: DocumentEmbedderControls,
347 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
350 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
351 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
352 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
353 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
354 images: MutNullableDom<HTMLCollection>,
355 embeds: MutNullableDom<HTMLCollection>,
356 links: MutNullableDom<HTMLCollection>,
357 forms: MutNullableDom<HTMLCollection>,
358 scripts: MutNullableDom<HTMLCollection>,
359 anchors: MutNullableDom<HTMLCollection>,
360 applets: MutNullableDom<HTMLCollection>,
361 iframes: RefCell<IFrameCollection>,
363 #[no_trace]
366 style_shared_lock: StyleSharedRwLock,
367 #[custom_trace]
369 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
370 stylesheet_list: MutNullableDom<StyleSheetList>,
371 ready_state: Cell<DocumentReadyState>,
372 domcontentloaded_dispatched: Cell<bool>,
374 current_script: MutNullableDom<HTMLScriptElement>,
376 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
378 script_blocking_stylesheets_count: Cell<u32>,
380 render_blocking_element_count: Cell<u32>,
383 deferred_scripts: PendingInOrderScriptVec,
385 asap_in_order_scripts_list: PendingInOrderScriptVec,
387 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
389 animation_frame_ident: Cell<u32>,
392 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
395 running_animation_callbacks: Cell<bool>,
400 loader: DomRefCell<DocumentLoader>,
402 current_parser: MutNullableDom<ServoParser>,
404 base_element: MutNullableDom<HTMLBaseElement>,
406 target_base_element: MutNullableDom<HTMLBaseElement>,
408 appropriate_template_contents_owner_document: MutNullableDom<Document>,
411 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
414 #[no_trace]
418 needs_restyle: Cell<RestyleReason>,
419 #[no_trace]
422 dom_interactive: Cell<Option<CrossProcessInstant>>,
423 #[no_trace]
425 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
426 #[no_trace]
428 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
429 #[no_trace]
430 dom_complete: Cell<Option<CrossProcessInstant>>,
431 #[no_trace]
432 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
433 #[no_trace]
434 load_event_start: Cell<Option<CrossProcessInstant>>,
435 #[no_trace]
436 load_event_end: Cell<Option<CrossProcessInstant>>,
437 #[no_trace]
438 unload_event_start: Cell<Option<CrossProcessInstant>>,
439 #[no_trace]
440 unload_event_end: Cell<Option<CrossProcessInstant>>,
441 #[no_trace]
443 https_state: Cell<HttpsState>,
444 #[no_trace]
446 origin: DomRefCell<MutableOrigin>,
447 referrer: Option<String>,
449 target_element: MutNullableDom<Element>,
451 #[no_trace]
453 policy_container: DomRefCell<PolicyContainer>,
454 #[no_trace]
456 preloaded_resources: DomRefCell<PreloadedResources>,
457 ignore_destructive_writes_counter: Cell<u32>,
459 ignore_opens_during_unload_counter: Cell<u32>,
461 spurious_animation_frames: Cell<u8>,
465
466 fullscreen_element: MutNullableDom<Element>,
468 form_id_listener_map:
475 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
476 #[no_trace]
477 interactive_time: DomRefCell<ProgressiveWebMetrics>,
478 #[no_trace]
479 tti_window: DomRefCell<InteractiveWindow>,
480 canceller: FetchCanceller,
482 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
484 page_showing: Cell<bool>,
486 salvageable: Cell<bool>,
488 active_parser_was_aborted: Cell<bool>,
490 fired_unload: Cell<bool>,
492 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
494 redirect_count: Cell<u16>,
496 script_and_layout_blockers: Cell<u32>,
498 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
500 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
501 completely_loaded: Cell<bool>,
503 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
505 shadow_roots_styles_changed: Cell<bool>,
507 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
513 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
516 has_pending_animated_image_update: Cell<bool>,
518 selection: MutNullableDom<Selection>,
520 timeline: Dom<DocumentTimeline>,
523 animations: Animations,
525 image_animation_manager: DomRefCell<ImageAnimationManager>,
527 dirty_root: MutNullableDom<Element>,
529 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
531 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
540 fonts: MutNullableDom<FontFaceSet>,
543 visibility_state: Cell<DocumentVisibilityState>,
545 status_code: Option<u16>,
547 is_initial_about_blank: Cell<bool>,
549 allow_declarative_shadow_roots: Cell<bool>,
551 #[no_trace]
553 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
554 has_trustworthy_ancestor_origin: Cell<bool>,
556 intersection_observer_task_queued: Cell<bool>,
558 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
570 highlighted_dom_node: MutNullableDom<Node>,
572 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
575 #[ignore_malloc_size_of = "mozjs"]
577 adopted_stylesheets_frozen_types: CachedFrozenArray,
578 pending_scroll_events: DomRefCell<Vec<PendingScrollEvent>>,
582 rendering_update_reasons: Cell<RenderingUpdateReason>,
584 waiting_on_canvas_image_updates: Cell<bool>,
588 root_removal_noted: Cell<bool>,
590 #[no_trace]
598 current_rendering_epoch: Cell<Epoch>,
599 #[conditional_malloc_size_of]
601 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
602 #[no_trace]
603 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
605 #[no_trace]
606 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
613 #[no_trace]
615 favicon: RefCell<Option<Image>>,
616
617 websockets: DOMTracker<WebSocket>,
619
620 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
622
623 #[no_trace]
625 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
626
627 layout_animations_test_enabled: bool,
629
630 #[no_trace]
632 state_override: DomRefCell<FxHashMap<CommandName, bool>>,
633
634 #[no_trace]
636 value_override: DomRefCell<FxHashMap<CommandName, DOMString>>,
637
638 #[no_trace]
640 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
641
642 css_styling_flag: Cell<bool>,
644}
645
646impl Document {
647 fn unloading_cleanup_steps(&self) {
649 if self.close_outstanding_websockets() {
652 self.salvageable.set(false);
654 }
655
656 if !self.salvageable.get() {
661 let global_scope = self.window.as_global_scope();
662
663 global_scope.close_event_sources();
665
666 let msg = ScriptToConstellationMessage::DiscardDocument;
671 let _ = global_scope.script_to_constellation_chan().send(msg);
672 }
673 }
674
675 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
676 self.websockets.track(websocket);
677 }
678
679 fn close_outstanding_websockets(&self) -> bool {
680 let mut closed_any_websocket = false;
681 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
682 if websocket.make_disappear() {
683 closed_any_websocket = true;
684 }
685 });
686 closed_any_websocket
687 }
688
689 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
690 debug_assert!(*node.owner_doc() == *self);
691 if !node.is_connected() {
692 return;
693 }
694
695 let parent = match node.parent_in_flat_tree() {
696 Some(parent) => parent,
697 None => {
698 let Some(document_element) = self.GetDocumentElement() else {
701 if !self.root_removal_noted.get() {
703 self.add_restyle_reason(RestyleReason::DOMChanged);
704 self.root_removal_noted.set(true);
705 }
706 return;
707 };
708 self.root_removal_noted.set(false);
711
712 if let Some(dirty_root) = self.dirty_root.get() {
713 for ancestor in dirty_root
716 .upcast::<Node>()
717 .inclusive_ancestors_in_flat_tree()
718 {
719 if ancestor.is::<Element>() {
720 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
721 }
722 }
723 }
724 self.dirty_root.set(Some(&document_element));
725 return;
726 },
727 };
728
729 if let Some(parent_element) = parent.downcast::<Element>() {
730 if !parent_element.is_styled() {
731 return;
732 }
733 if parent_element.is_display_none() {
734 return;
735 }
736 }
737
738 let element_parent: DomRoot<Element>;
739 let element = match node.downcast::<Element>() {
740 Some(element) => element,
741 None => {
742 match DomRoot::downcast::<Element>(parent) {
745 Some(parent) => {
746 element_parent = parent;
747 &element_parent
748 },
749 None => {
750 return;
754 },
755 }
756 },
757 };
758
759 let dirty_root = match self.dirty_root.get() {
760 Some(root) if root.is_connected() => root,
761 _ => {
762 element
763 .upcast::<Node>()
764 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
765 self.dirty_root.set(Some(element));
766 return;
767 },
768 };
769
770 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
771 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
772 return;
773 }
774
775 if ancestor.is::<Element>() {
776 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
777 }
778 }
779
780 let new_dirty_root = element
781 .upcast::<Node>()
782 .common_ancestor_in_flat_tree(dirty_root.upcast())
783 .expect("Couldn't find common ancestor");
784
785 let mut has_dirty_descendants = true;
786 for ancestor in dirty_root
787 .upcast::<Node>()
788 .inclusive_ancestors_in_flat_tree()
789 {
790 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
791 has_dirty_descendants &= *ancestor != *new_dirty_root;
792 }
793
794 self.dirty_root
795 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
796 }
797
798 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
799 self.dirty_root.take()
800 }
801
802 #[inline]
803 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
804 self.loader.borrow()
805 }
806
807 #[inline]
808 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
809 self.loader.borrow_mut()
810 }
811
812 #[inline]
813 pub(crate) fn has_browsing_context(&self) -> bool {
814 self.has_browsing_context
815 }
816
817 #[inline]
819 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
820 if self.has_browsing_context {
821 self.window.undiscarded_window_proxy()
822 } else {
823 None
824 }
825 }
826
827 pub(crate) fn webview_id(&self) -> WebViewId {
828 self.window.webview_id()
829 }
830
831 #[inline]
832 pub(crate) fn window(&self) -> &Window {
833 &self.window
834 }
835
836 #[inline]
837 pub(crate) fn is_html_document(&self) -> bool {
838 self.is_html_document
839 }
840
841 pub(crate) fn is_xhtml_document(&self) -> bool {
842 self.content_type.matches(APPLICATION, "xhtml+xml")
843 }
844
845 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
846 self.https_state.set(https_state);
847 }
848
849 pub(crate) fn is_fully_active(&self) -> bool {
850 self.activity.get() == DocumentActivity::FullyActive
851 }
852
853 pub(crate) fn is_active(&self) -> bool {
854 self.activity.get() != DocumentActivity::Inactive
855 }
856
857 #[inline]
858 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
859 self.current_rendering_epoch.get()
860 }
861
862 pub(crate) fn set_activity(&self, cx: &mut js::context::JSContext, activity: DocumentActivity) {
863 assert!(self.has_browsing_context);
865 if activity == self.activity.get() {
866 return;
867 }
868
869 self.activity.set(activity);
871 let media = ServoMedia::get();
872 let pipeline_id = self.window().pipeline_id();
873 let client_context_id =
874 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
875
876 if activity != DocumentActivity::FullyActive {
877 self.window().suspend(cx);
878 media.suspend(&client_context_id);
879 return;
880 }
881
882 self.title_changed();
883 self.notify_embedder_favicon();
884 self.dirty_all_nodes();
885 self.window().resume(CanGc::from_cx(cx));
886 media.resume(&client_context_id);
887
888 if self.ready_state.get() != DocumentReadyState::Complete {
889 return;
890 }
891
892 let document = Trusted::new(self);
896 self.owner_global()
897 .task_manager()
898 .dom_manipulation_task_source()
899 .queue(task!(fire_pageshow_event: move || {
900 let document = document.root();
901 let window = document.window();
902 if document.page_showing.get() {
904 return;
905 }
906 document.page_showing.set(true);
908 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::deprecated_note());
910 let event = PageTransitionEvent::new(
913 window,
914 atom!("pageshow"),
915 false, false, true, CanGc::deprecated_note(),
919 );
920 let event = event.upcast::<Event>();
921 event.set_trusted(true);
922 window.dispatch_event_with_target_override(event, CanGc::deprecated_note());
923 }))
924 }
925
926 pub(crate) fn origin(&self) -> Ref<'_, MutableOrigin> {
927 self.origin.borrow()
928 }
929
930 pub(crate) fn mark_as_internal(&self) {
933 *self.origin.borrow_mut() = MutableOrigin::new(ImmutableOrigin::new_opaque());
934 }
935
936 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
937 *self.protocol_handler_automation_mode.borrow_mut() = mode;
938 }
939
940 pub(crate) fn url(&self) -> ServoUrl {
942 self.url.borrow().clone()
943 }
944
945 pub(crate) fn set_url(&self, url: ServoUrl) {
946 *self.url.borrow_mut() = url;
947 }
948
949 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
950 self.about_base_url.borrow().clone()
951 }
952
953 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
954 *self.about_base_url.borrow_mut() = about_base_url;
955 }
956
957 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
959 let document_url = self.url();
960 if document_url.as_str() == "about:srcdoc" {
962 return self
965 .about_base_url()
966 .expect("about:srcdoc page should always have an about base URL");
967 }
968
969 if document_url.matches_about_blank() {
972 if let Some(about_base_url) = self.about_base_url() {
973 return about_base_url;
974 }
975 }
976
977 document_url
979 }
980
981 pub(crate) fn base_url(&self) -> ServoUrl {
983 match self.base_element() {
984 None => self.fallback_base_url(),
986 Some(base) => base.frozen_base_url(),
988 }
989 }
990
991 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
992 self.needs_restyle.set(self.needs_restyle.get() | reason)
993 }
994
995 pub(crate) fn clear_restyle_reasons(&self) {
996 self.needs_restyle.set(RestyleReason::empty());
997 }
998
999 pub(crate) fn restyle_reason(&self) -> RestyleReason {
1000 let mut condition = self.needs_restyle.get();
1001 if self.stylesheets.borrow().has_changed() {
1002 condition.insert(RestyleReason::StylesheetsChanged);
1003 }
1004
1005 if let Some(root) = self.GetDocumentElement() {
1009 if root.upcast::<Node>().has_dirty_descendants() {
1010 condition.insert(RestyleReason::DOMChanged);
1011 }
1012 }
1013
1014 if !self.pending_restyles.borrow().is_empty() {
1015 condition.insert(RestyleReason::PendingRestyles);
1016 }
1017
1018 condition
1019 }
1020
1021 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1023 self.base_element.get()
1024 }
1025
1026 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1028 self.target_base_element.get()
1029 }
1030
1031 pub(crate) fn refresh_base_element(&self) {
1033 if let Some(base_element) = self.base_element.get() {
1034 base_element.clear_frozen_base_url();
1035 }
1036 let new_base_element = self
1037 .upcast::<Node>()
1038 .traverse_preorder(ShadowIncluding::No)
1039 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1040 .find(|element| {
1041 element
1042 .upcast::<Element>()
1043 .has_attribute(&local_name!("href"))
1044 });
1045 if let Some(ref new_base_element) = new_base_element {
1046 new_base_element.set_frozen_base_url();
1047 }
1048 self.base_element.set(new_base_element.as_deref());
1049
1050 let new_target_base_element = self
1051 .upcast::<Node>()
1052 .traverse_preorder(ShadowIncluding::No)
1053 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1054 .next();
1055 self.target_base_element
1056 .set(new_target_base_element.as_deref());
1057 }
1058
1059 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1060 self.quirks_mode.get()
1061 }
1062
1063 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1064 let old_mode = self.quirks_mode.replace(new_mode);
1065
1066 if old_mode != new_mode {
1067 self.window.layout_mut().set_quirks_mode(new_mode);
1068 }
1069 }
1070
1071 pub(crate) fn encoding(&self) -> &'static Encoding {
1072 self.encoding.get()
1073 }
1074
1075 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1076 self.encoding.set(encoding);
1077 }
1078
1079 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1080 if node.is_connected() {
1081 node.note_dirty_descendants();
1082 }
1083
1084 node.dirty(NodeDamage::ContentOrHeritage);
1087 }
1088
1089 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1091 self.document_or_shadow_root
1092 .unregister_named_element(&self.id_map, to_unregister, &id);
1093 self.reset_form_owner_for_listeners(&id, can_gc);
1094 }
1095
1096 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1098 let root = self.GetDocumentElement().expect(
1099 "The element is in the document, so there must be a document \
1100 element.",
1101 );
1102 self.document_or_shadow_root.register_named_element(
1103 &self.id_map,
1104 element,
1105 &id,
1106 DomRoot::from_ref(root.upcast::<Node>()),
1107 );
1108 self.reset_form_owner_for_listeners(&id, can_gc);
1109 }
1110
1111 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1113 self.document_or_shadow_root
1114 .unregister_named_element(&self.name_map, to_unregister, &name);
1115 }
1116
1117 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1119 let root = self.GetDocumentElement().expect(
1120 "The element is in the document, so there must be a document \
1121 element.",
1122 );
1123 self.document_or_shadow_root.register_named_element(
1124 &self.name_map,
1125 element,
1126 &name,
1127 DomRoot::from_ref(root.upcast::<Node>()),
1128 );
1129 }
1130
1131 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1132 &self,
1133 id: DOMString,
1134 listener: &T,
1135 ) {
1136 let mut map = self.form_id_listener_map.borrow_mut();
1137 let listener = listener.to_element();
1138 let set = map.entry(Atom::from(id)).or_default();
1139 set.insert(Dom::from_ref(listener));
1140 }
1141
1142 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1143 &self,
1144 id: DOMString,
1145 listener: &T,
1146 ) {
1147 let mut map = self.form_id_listener_map.borrow_mut();
1148 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1149 entry
1150 .get_mut()
1151 .remove(&Dom::from_ref(listener.to_element()));
1152 if entry.get().is_empty() {
1153 entry.remove();
1154 }
1155 }
1156 }
1157
1158 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1160 self.get_element_by_id(&Atom::from(fragment))
1164 .or_else(|| self.get_anchor_by_name(fragment))
1168 }
1169
1170 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1173 if fragment.is_empty() {
1183 return Some(DomRoot::from_ref(self.upcast()));
1184 }
1185 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1187 {
1188 return Some(DomRoot::upcast(potential_indicated_element));
1190 }
1191 let fragment_bytes = percent_decode(fragment.as_bytes());
1193 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1195 return None;
1196 };
1197 if let Some(potential_indicated_element) =
1199 self.find_a_potential_indicated_element(&decoded_fragment)
1200 {
1201 return Some(DomRoot::upcast(potential_indicated_element));
1203 }
1204 if decoded_fragment.eq_ignore_ascii_case("top") {
1206 return Some(DomRoot::from_ref(self.upcast()));
1207 }
1208 None
1210 }
1211
1212 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str, can_gc: CanGc) {
1214 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1219 self.set_target_element(None);
1220 return;
1221 };
1222 if *indicated_part == *self.upcast() {
1224 self.set_target_element(None);
1226 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1231 return;
1233 }
1234 let Some(target) = indicated_part.downcast::<Element>() else {
1237 unreachable!("Indicated part should always be an element");
1239 };
1240 self.set_target_element(Some(target));
1242 target.scroll_into_view_with_options(
1246 ScrollBehavior::Auto,
1247 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1248 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1249 None,
1250 None,
1251 );
1252
1253 indicated_part.run_the_focusing_steps(Some(FocusableArea::Viewport), can_gc);
1256
1257 self.event_handler()
1259 .set_sequential_focus_navigation_starting_point(target.upcast());
1260 }
1261
1262 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1263 let name = Atom::from(name);
1264 self.name_map.borrow().get(&name).and_then(|elements| {
1265 elements
1266 .iter()
1267 .find(|e| e.is::<HTMLAnchorElement>())
1268 .map(|e| DomRoot::from_ref(&**e))
1269 })
1270 }
1271
1272 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1274 match state {
1275 DocumentReadyState::Loading => {
1276 if self.window().is_top_level() {
1277 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1278 self.webview_id(),
1279 LoadStatus::Started,
1280 ));
1281 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1282 }
1283 },
1284 DocumentReadyState::Complete => {
1285 if self.window().is_top_level() {
1286 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1287 self.webview_id(),
1288 LoadStatus::Complete,
1289 ));
1290 }
1291 update_with_current_instant(&self.dom_complete);
1292 },
1293 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1294 };
1295
1296 self.ready_state.set(state);
1297
1298 self.upcast::<EventTarget>()
1299 .fire_event(atom!("readystatechange"), can_gc);
1300 }
1301
1302 pub(crate) fn scripting_enabled(&self) -> bool {
1305 self.has_browsing_context() &&
1308 !self.has_active_sandboxing_flag(
1312 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1313 )
1314 }
1315
1316 pub(crate) fn title_changed(&self) {
1318 if self.browsing_context().is_some() {
1319 self.send_title_to_embedder();
1320 let title = String::from(self.Title());
1321 self.window
1322 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1323 self.window.pipeline_id(),
1324 title.clone(),
1325 ));
1326 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1327 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1328 self.window.pipeline_id(),
1329 title,
1330 ));
1331 }
1332 }
1333 }
1334
1335 fn title(&self) -> Option<DOMString> {
1339 let title = self.GetDocumentElement().and_then(|root| {
1340 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1341 root.upcast::<Node>()
1343 .child_elements()
1344 .find(|node| {
1345 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1346 })
1347 .map(DomRoot::upcast::<Node>)
1348 } else {
1349 root.upcast::<Node>()
1351 .traverse_preorder(ShadowIncluding::No)
1352 .find(|node| node.is::<HTMLTitleElement>())
1353 }
1354 });
1355
1356 title.map(|title| {
1357 let value = title.child_text_content();
1359 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1360 })
1361 }
1362
1363 pub(crate) fn send_title_to_embedder(&self) {
1365 let window = self.window();
1366 if window.is_top_level() {
1367 let title = self.title().map(String::from);
1368 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1369 }
1370 }
1371
1372 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1373 let window = self.window();
1374 window.send_to_embedder(msg);
1375 }
1376
1377 pub(crate) fn dirty_all_nodes(&self) {
1378 let root = match self.GetDocumentElement() {
1379 Some(root) => root,
1380 None => return,
1381 };
1382 for node in root
1383 .upcast::<Node>()
1384 .traverse_preorder(ShadowIncluding::Yes)
1385 {
1386 node.dirty(NodeDamage::Other)
1387 }
1388 }
1389
1390 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1392 let boxes_that_were_scrolled: Vec<_> = self
1400 .pending_scroll_events
1401 .borrow()
1402 .iter()
1403 .filter_map(|pending_event| {
1404 if &*pending_event.event == "scroll" {
1405 Some(pending_event.target.as_rooted())
1406 } else {
1407 None
1408 }
1409 })
1410 .collect();
1411
1412 for target in boxes_that_were_scrolled.into_iter() {
1413 let Some(element) = target.downcast::<Element>() else {
1419 continue;
1420 };
1421 let document = element.owner_document();
1422
1423 let mut pending_scroll_events = document.pending_scroll_events.borrow_mut();
1430 let event = "scrollend".into();
1431 if pending_scroll_events
1432 .iter()
1433 .any(|existing| existing.equivalent(&target, &event))
1434 {
1435 continue;
1436 }
1437
1438 pending_scroll_events.push(PendingScrollEvent {
1440 target: target.as_traced(),
1441 event: "scrollend".into(),
1442 });
1443 }
1444
1445 rooted_vec!(let pending_scroll_events <- self.pending_scroll_events.take().into_iter());
1448 for pending_event in pending_scroll_events.iter() {
1449 let event = pending_event.event.clone();
1452 if pending_event.target.is::<Document>() {
1453 pending_event.target.fire_bubbling_event(event, can_gc);
1454 }
1455 else {
1464 pending_event.target.fire_event(event, can_gc);
1465 }
1466 }
1467
1468 }
1471
1472 pub(crate) fn handle_viewport_scroll_event(&self) {
1477 self.finish_handle_scroll_event(self.upcast());
1489 }
1490
1491 pub(crate) fn finish_handle_scroll_event(&self, event_target: &EventTarget) {
1496 let event = "scroll".into();
1499 if self
1500 .pending_scroll_events
1501 .borrow()
1502 .iter()
1503 .any(|existing| existing.equivalent(event_target, &event))
1504 {
1505 return;
1506 }
1507
1508 self.pending_scroll_events
1511 .borrow_mut()
1512 .push(PendingScrollEvent {
1513 target: Dom::from_ref(event_target),
1514 event: "scroll".into(),
1515 });
1516 }
1517
1518 pub(crate) fn node_from_nodes_and_strings(
1520 &self,
1521 cx: &mut js::context::JSContext,
1522 mut nodes: Vec<NodeOrString>,
1523 ) -> Fallible<DomRoot<Node>> {
1524 if nodes.len() == 1 {
1525 Ok(match nodes.pop().unwrap() {
1526 NodeOrString::Node(node) => node,
1527 NodeOrString::String(string) => DomRoot::upcast(self.CreateTextNode(cx, string)),
1528 })
1529 } else {
1530 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(cx));
1531 for node in nodes {
1532 match node {
1533 NodeOrString::Node(node) => {
1534 fragment.AppendChild(cx, &node)?;
1535 },
1536 NodeOrString::String(string) => {
1537 let node = DomRoot::upcast::<Node>(self.CreateTextNode(cx, string));
1538 fragment.AppendChild(cx, &node).unwrap();
1541 },
1542 }
1543 }
1544 Ok(fragment)
1545 }
1546 }
1547
1548 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1549 match self.GetBody() {
1550 Some(ref body) if body.is_body_element() => {
1551 body.upcast::<Element>().get_string_attribute(local_name)
1552 },
1553 _ => DOMString::new(),
1554 }
1555 }
1556
1557 pub(crate) fn set_body_attribute(
1558 &self,
1559 local_name: &LocalName,
1560 value: DOMString,
1561 can_gc: CanGc,
1562 ) {
1563 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1564 let body = body.upcast::<Element>();
1565 let value = body.parse_attribute(&ns!(), local_name, value);
1566 body.set_attribute(local_name, value, can_gc);
1567 }
1568 }
1569
1570 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1571 self.current_script.set(script);
1572 }
1573
1574 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1575 self.script_blocking_stylesheets_count.get()
1576 }
1577
1578 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1579 let count_cell = &self.script_blocking_stylesheets_count;
1580 count_cell.set(count_cell.get() + 1);
1581 }
1582
1583 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1584 let count_cell = &self.script_blocking_stylesheets_count;
1585 assert!(count_cell.get() > 0);
1586 count_cell.set(count_cell.get() - 1);
1587 }
1588
1589 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1590 self.render_blocking_element_count.get()
1591 }
1592
1593 pub(crate) fn increment_render_blocking_element_count(&self) {
1595 assert!(self.allows_adding_render_blocking_elements());
1602 let count_cell = &self.render_blocking_element_count;
1603 count_cell.set(count_cell.get() + 1);
1604 }
1605
1606 pub(crate) fn decrement_render_blocking_element_count(&self) {
1608 let count_cell = &self.render_blocking_element_count;
1614 assert!(count_cell.get() > 0);
1615 count_cell.set(count_cell.get() - 1);
1616 }
1617
1618 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1620 self.is_html_document && self.GetBody().is_none()
1623 }
1624
1625 pub(crate) fn is_render_blocked(&self) -> bool {
1627 self.render_blocking_element_count() > 0
1631 }
1636
1637 pub(crate) fn invalidate_stylesheets(&self) {
1638 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1639
1640 if let Some(element) = self.GetDocumentElement() {
1644 element.upcast::<Node>().dirty(NodeDamage::Style);
1645 }
1646 }
1647
1648 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1651 !self.animation_frame_list.borrow().is_empty()
1652 }
1653
1654 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1656 let ident = self.animation_frame_ident.get() + 1;
1657 self.animation_frame_ident.set(ident);
1658
1659 let had_animation_frame_callbacks;
1660 {
1661 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1662 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1663 animation_frame_list.push_back((ident, Some(callback)));
1664 }
1665
1666 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1672 self.window().send_to_constellation(
1673 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1674 AnimationState::AnimationCallbacksPresent,
1675 ),
1676 );
1677 }
1678
1679 ident
1680 }
1681
1682 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1684 let mut list = self.animation_frame_list.borrow_mut();
1685 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1686 pair.1 = None;
1687 }
1688 }
1689
1690 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1692 let _realm = enter_realm(self);
1693
1694 self.running_animation_callbacks.set(true);
1695 let timing = self.global().performance().Now();
1696
1697 let num_callbacks = self.animation_frame_list.borrow().len();
1698 for _ in 0..num_callbacks {
1699 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1700 if let Some(callback) = maybe_callback {
1701 callback.call(self, *timing, can_gc);
1702 }
1703 }
1704 self.running_animation_callbacks.set(false);
1705
1706 if self.animation_frame_list.borrow().is_empty() {
1707 self.window().send_to_constellation(
1708 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1709 AnimationState::NoAnimationCallbacksPresent,
1710 ),
1711 );
1712 }
1713 }
1714
1715 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1716 self.policy_container.borrow()
1717 }
1718
1719 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1720 *self.policy_container.borrow_mut() = policy_container;
1721 }
1722
1723 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1724 self.policy_container.borrow_mut().set_csp_list(csp_list);
1725 }
1726
1727 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
1729 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
1731 csp_list.push(policy);
1732 self.policy_container
1733 .borrow_mut()
1734 .set_csp_list(Some(csp_list));
1735 }
1736
1737 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
1738 Ref::map(self.policy_container.borrow(), |policy_container| {
1739 &policy_container.csp_list
1740 })
1741 }
1742
1743 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1744 self.preloaded_resources.borrow()
1745 }
1746
1747 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1748 self.preloaded_resources
1749 .borrow_mut()
1750 .insert(key, preload_id);
1751 }
1752
1753 pub(crate) fn fetch<Listener: FetchResponseListener>(
1754 &self,
1755 load: LoadType,
1756 mut request: RequestBuilder,
1757 listener: Listener,
1758 ) {
1759 request = request
1760 .insecure_requests_policy(self.insecure_requests_policy())
1761 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1762 let callback = NetworkListener {
1763 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1764 task_source: self
1765 .owner_global()
1766 .task_manager()
1767 .networking_task_source()
1768 .into(),
1769 }
1770 .into_callback();
1771 self.loader_mut()
1772 .fetch_async_with_callback(load, request, callback);
1773 }
1774
1775 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1776 &self,
1777 mut request: RequestBuilder,
1778 listener: Listener,
1779 ) {
1780 request = request
1781 .insecure_requests_policy(self.insecure_requests_policy())
1782 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1783 let callback = NetworkListener {
1784 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1785 task_source: self
1786 .owner_global()
1787 .task_manager()
1788 .networking_task_source()
1789 .into(),
1790 }
1791 .into_callback();
1792 self.loader_mut().fetch_async_background(request, callback);
1793 }
1794
1795 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
1797 match self.window().window_proxy().frame_element() {
1798 None => DomRoot::from_ref(self),
1801 Some(container) => container.owner_document().deferred_fetch_control_document(),
1803 }
1804 }
1805
1806 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
1808 let control_document = self.deferred_fetch_control_document();
1810 let navigable = control_document.window();
1812 let is_top_level = navigable.is_top_level();
1815 let deferred_fetch_allowed = true;
1819 let deferred_fetch_minimal_allowed = true;
1823 let mut quota = match is_top_level {
1825 true if !deferred_fetch_allowed => 0,
1827 true if !deferred_fetch_minimal_allowed => 640 * 1024,
1829 true => 512 * 1024,
1831 _ if deferred_fetch_allowed => 0,
1835 _ if deferred_fetch_minimal_allowed => 8 * 1024,
1839 _ => 0,
1841 } as isize;
1842 let mut quota_for_request_origin = 64 * 1024_isize;
1844 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
1853 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
1855 continue;
1856 }
1857 let request_length = deferred_fetch.request.total_request_length();
1859 quota -= request_length as isize;
1861 if deferred_fetch.request.url().origin() == origin {
1864 quota_for_request_origin -= request_length as isize;
1865 }
1866 }
1867 if quota <= 0 {
1869 return 0;
1870 }
1871 if quota < quota_for_request_origin {
1873 return quota;
1874 }
1875 quota_for_request_origin
1877 }
1878
1879 pub(crate) fn update_document_for_history_step_application(
1881 &self,
1882 old_url: &ServoUrl,
1883 new_url: &ServoUrl,
1884 ) {
1885 if old_url.as_url()[Position::BeforeFragment..] !=
1915 new_url.as_url()[Position::BeforeFragment..]
1916 {
1917 let window = Trusted::new(self.owner_window().deref());
1918 let old_url = old_url.to_string();
1919 let new_url = new_url.to_string();
1920 self.owner_global()
1921 .task_manager()
1922 .dom_manipulation_task_source()
1923 .queue(task!(hashchange_event: move || {
1924 let window = window.root();
1925 HashChangeEvent::new(
1926 &window,
1927 atom!("hashchange"),
1928 false,
1929 false,
1930 old_url,
1931 new_url,
1932 CanGc::deprecated_note(),
1933 )
1934 .upcast::<Event>()
1935 .fire(window.upcast(), CanGc::deprecated_note());
1936 }));
1937 }
1938 }
1939
1940 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut js::context::JSContext) {
1943 debug!("Document got finish_load: {:?}", load);
1945 self.loader.borrow_mut().finish_load(&load);
1946
1947 match load {
1948 LoadType::Stylesheet(_) => {
1949 self.process_pending_parsing_blocking_script(cx);
1952
1953 self.process_deferred_scripts(cx);
1955 },
1956 LoadType::PageSource(_) => {
1957 if self.has_browsing_context && self.is_fully_active() {
1960 self.window().allow_layout_if_necessary();
1961 }
1962
1963 self.process_deferred_scripts(cx);
1968 },
1969 _ => {},
1970 }
1971
1972 let loader = self.loader.borrow();
1979
1980 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1982 update_with_current_instant(&self.top_level_dom_complete);
1983 }
1984
1985 if loader.is_blocked() || loader.events_inhibited() {
1986 return;
1988 }
1989
1990 ScriptThread::mark_document_with_no_blocked_loads(self);
1991 }
1992
1993 pub(crate) fn check_if_unloading_is_cancelled(
1995 &self,
1996 recursive_flag: bool,
1997 can_gc: CanGc,
1998 ) -> bool {
1999 self.incr_ignore_opens_during_unload_counter();
2002 let beforeunload_event = BeforeUnloadEvent::new(
2004 &self.window,
2005 atom!("beforeunload"),
2006 EventBubbles::Bubbles,
2007 EventCancelable::Cancelable,
2008 can_gc,
2009 );
2010 let event = beforeunload_event.upcast::<Event>();
2011 event.set_trusted(true);
2012 let event_target = self.window.upcast::<EventTarget>();
2013 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2014 self.window
2015 .dispatch_event_with_target_override(event, can_gc);
2016 if has_listeners {
2019 self.salvageable.set(false);
2020 }
2021 let mut can_unload = true;
2022 let default_prevented = event.DefaultPrevented();
2024 let return_value_not_empty = !event
2025 .downcast::<BeforeUnloadEvent>()
2026 .unwrap()
2027 .ReturnValue()
2028 .is_empty();
2029 if default_prevented || return_value_not_empty {
2030 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2031 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2032 self.send_to_embedder(msg);
2033 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2034 }
2035 if !recursive_flag {
2037 let iframes: Vec<_> = self.iframes().iter().collect();
2040 for iframe in &iframes {
2041 let document = iframe.owner_document();
2043 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2044 if !document.salvageable() {
2045 self.salvageable.set(false);
2046 }
2047 if !can_unload {
2048 break;
2049 }
2050 }
2051 }
2052 self.decr_ignore_opens_during_unload_counter();
2054 can_unload
2055 }
2056
2057 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2059 self.incr_ignore_opens_during_unload_counter();
2062 if self.page_showing.get() {
2064 self.page_showing.set(false);
2066 let event = PageTransitionEvent::new(
2069 &self.window,
2070 atom!("pagehide"),
2071 false, false, self.salvageable.get(), can_gc,
2075 );
2076 let event = event.upcast::<Event>();
2077 event.set_trusted(true);
2078 self.window
2079 .dispatch_event_with_target_override(event, can_gc);
2080 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2082 }
2083 if !self.fired_unload.get() {
2085 let event = Event::new(
2086 self.window.upcast(),
2087 atom!("unload"),
2088 EventBubbles::Bubbles,
2089 EventCancelable::Cancelable,
2090 can_gc,
2091 );
2092 event.set_trusted(true);
2093 let event_target = self.window.upcast::<EventTarget>();
2094 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2095 self.window
2096 .dispatch_event_with_target_override(&event, can_gc);
2097 self.fired_unload.set(true);
2098 if has_listeners {
2100 self.salvageable.set(false);
2101 }
2102 }
2103 if !recursive_flag {
2107 let iframes: Vec<_> = self.iframes().iter().collect();
2110 for iframe in &iframes {
2111 let document = iframe.owner_document();
2113 document.unload(true, can_gc);
2114 if !document.salvageable() {
2115 self.salvageable.set(false);
2116 }
2117 }
2118 }
2119
2120 self.unloading_cleanup_steps();
2122
2123 self.window.as_global_scope().clean_up_all_file_resources();
2125
2126 self.decr_ignore_opens_during_unload_counter();
2128
2129 }
2132
2133 fn completely_finish_loading(&self) {
2135 self.completely_loaded.set(true);
2140 self.notify_constellation_load();
2149
2150 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2159 &*self.declarative_refresh.borrow()
2160 {
2161 self.window.as_global_scope().schedule_callback(
2162 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2163 window: DomRoot::from_ref(self.window()),
2164 url: url.clone(),
2165 }),
2166 Duration::from_secs(*time),
2167 );
2168 }
2169 }
2170
2171 pub(crate) fn maybe_queue_document_completion(&self) {
2173 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2175 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2176 None => false,
2177 };
2178
2179 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2184 !self.is_fully_active() ||
2185 is_in_delaying_load_events_mode ||
2186 self.loader.borrow().events_inhibited();
2189
2190 if not_ready_for_load {
2191 return;
2193 }
2194
2195 self.loader.borrow_mut().inhibit_events();
2196
2197 debug!("Document loads are complete.");
2202 let document = Trusted::new(self);
2203 self.owner_global()
2204 .task_manager()
2205 .dom_manipulation_task_source()
2206 .queue(task!(fire_load_event: move || {
2207 let document = document.root();
2208 let window = document.window();
2210 if !window.is_alive() {
2211 return;
2212 }
2213
2214 document.set_ready_state(DocumentReadyState::Complete, CanGc::deprecated_note());
2216
2217 if document.browsing_context().is_none() {
2219 return;
2220 }
2221
2222 update_with_current_instant(&document.load_event_start);
2224
2225 let load_event = Event::new(
2227 window.upcast(),
2228 atom!("load"),
2229 EventBubbles::DoesNotBubble,
2230 EventCancelable::NotCancelable,
2231 CanGc::deprecated_note(),
2232 );
2233 load_event.set_trusted(true);
2234 debug!("About to dispatch load for {:?}", document.url());
2235 window.dispatch_event_with_target_override(&load_event, CanGc::deprecated_note());
2236
2237 update_with_current_instant(&document.load_event_end);
2247
2248 document.page_showing.set(true);
2253
2254 let page_show_event = PageTransitionEvent::new(
2256 window,
2257 atom!("pageshow"),
2258 false, false, false, CanGc::deprecated_note(),
2262 );
2263 let page_show_event = page_show_event.upcast::<Event>();
2264 page_show_event.set_trusted(true);
2265 page_show_event.fire(window.upcast(), CanGc::deprecated_note());
2266
2267 document.completely_finish_loading();
2269
2270 if let Some(fragment) = document.url().fragment() {
2274 document.scroll_to_the_fragment(fragment, CanGc::deprecated_note());
2275 }
2276 }));
2277
2278 #[cfg(feature = "webxr")]
2293 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2294 self.window.Navigator().Xr().dispatch_sessionavailable();
2295 }
2296 }
2297
2298 pub(crate) fn completely_loaded(&self) -> bool {
2299 self.completely_loaded.get()
2300 }
2301
2302 pub(crate) fn set_pending_parsing_blocking_script(
2304 &self,
2305 script: &HTMLScriptElement,
2306 load: Option<ScriptResult>,
2307 ) {
2308 assert!(!self.has_pending_parsing_blocking_script());
2309 *self.pending_parsing_blocking_script.borrow_mut() =
2310 Some(PendingScript::new_with_load(script, load));
2311 }
2312
2313 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2315 self.pending_parsing_blocking_script.borrow().is_some()
2316 }
2317
2318 pub(crate) fn pending_parsing_blocking_script_loaded(
2320 &self,
2321 element: &HTMLScriptElement,
2322 result: ScriptResult,
2323 cx: &mut js::context::JSContext,
2324 ) {
2325 {
2326 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2327 let entry = blocking_script.as_mut().unwrap();
2328 assert!(&*entry.element == element);
2329 entry.loaded(result);
2330 }
2331 self.process_pending_parsing_blocking_script(cx);
2332 }
2333
2334 fn process_pending_parsing_blocking_script(&self, cx: &mut js::context::JSContext) {
2335 if self.script_blocking_stylesheets_count.get() > 0 {
2336 return;
2337 }
2338 let pair = self
2339 .pending_parsing_blocking_script
2340 .borrow_mut()
2341 .as_mut()
2342 .and_then(PendingScript::take_result);
2343 if let Some((element, result)) = pair {
2344 *self.pending_parsing_blocking_script.borrow_mut() = None;
2345 self.get_current_parser()
2346 .unwrap()
2347 .resume_with_pending_parsing_blocking_script(&element, result, cx);
2348 }
2349 }
2350
2351 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2353 self.asap_scripts_set
2354 .borrow_mut()
2355 .push(Dom::from_ref(script));
2356 }
2357
2358 pub(crate) fn asap_script_loaded(
2361 &self,
2362 cx: &mut js::context::JSContext,
2363 element: &HTMLScriptElement,
2364 result: ScriptResult,
2365 ) {
2366 {
2367 let mut scripts = self.asap_scripts_set.borrow_mut();
2368 let idx = scripts
2369 .iter()
2370 .position(|entry| &**entry == element)
2371 .unwrap();
2372 scripts.swap_remove(idx);
2373 }
2374 element.execute(cx, result);
2375 }
2376
2377 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2379 self.asap_in_order_scripts_list.push(script);
2380 }
2381
2382 pub(crate) fn asap_in_order_script_loaded(
2385 &self,
2386 cx: &mut js::context::JSContext,
2387 element: &HTMLScriptElement,
2388 result: ScriptResult,
2389 ) {
2390 self.asap_in_order_scripts_list.loaded(element, result);
2391 while let Some((element, result)) = self
2392 .asap_in_order_scripts_list
2393 .take_next_ready_to_be_executed()
2394 {
2395 element.execute(cx, result);
2396 }
2397 }
2398
2399 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2401 self.deferred_scripts.push(script);
2402 }
2403
2404 pub(crate) fn deferred_script_loaded(
2407 &self,
2408 cx: &mut js::context::JSContext,
2409 element: &HTMLScriptElement,
2410 result: ScriptResult,
2411 ) {
2412 self.deferred_scripts.loaded(element, result);
2413 self.process_deferred_scripts(cx);
2414 }
2415
2416 fn process_deferred_scripts(&self, cx: &mut js::context::JSContext) {
2418 if self.ready_state.get() != DocumentReadyState::Interactive {
2419 return;
2420 }
2421 loop {
2423 if self.script_blocking_stylesheets_count.get() > 0 {
2424 return;
2425 }
2426 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2427 {
2428 element.execute(cx, result);
2429 } else {
2430 break;
2431 }
2432 }
2433 if self.deferred_scripts.is_empty() {
2434 self.maybe_dispatch_dom_content_loaded();
2436 }
2437 }
2438
2439 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2441 if self.domcontentloaded_dispatched.get() {
2442 return;
2443 }
2444 self.domcontentloaded_dispatched.set(true);
2445 assert_ne!(
2446 self.ReadyState(),
2447 DocumentReadyState::Complete,
2448 "Complete before DOMContentLoaded?"
2449 );
2450
2451 let document = Trusted::new(self);
2454 self.owner_global()
2455 .task_manager()
2456 .dom_manipulation_task_source()
2457 .queue(
2458 task!(fire_dom_content_loaded_event: move || {
2459 let document = document.root();
2460
2461 update_with_current_instant(&document.dom_content_loaded_event_start);
2464
2465 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::deprecated_note());
2468
2469 update_with_current_instant(&document.dom_content_loaded_event_end);
2472
2473 })
2480 );
2481
2482 self.interactive_time
2484 .borrow()
2485 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2486
2487 }
2490
2491 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut js::context::JSContext) {
2493 if !self.is_fully_active() {
2495 self.salvageable.set(false);
2500 }
2504 for exited_iframe in self.iframes().iter() {
2517 debug!("Destroying nested iframe document");
2518 exited_iframe.destroy_document_and_its_descendants(cx);
2519 }
2520 self.destroy(cx);
2525 }
2528
2529 pub(crate) fn destroy(&self, cx: &mut js::context::JSContext) {
2531 let exited_window = self.window();
2532 self.abort(cx);
2534 self.salvageable.set(false);
2536 self.unloading_cleanup_steps();
2546
2547 exited_window
2550 .as_global_scope()
2551 .task_manager()
2552 .cancel_all_tasks_and_ignore_future_tasks();
2553
2554 exited_window.discard_browsing_context();
2556
2557 }
2569
2570 fn terminate_fetch_group(&self) -> bool {
2572 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2573
2574 for canceller in &mut load_cancellers {
2578 if !canceller.keep_alive() {
2579 canceller.terminate();
2580 }
2581 }
2582 self.owner_global().process_deferred_fetches();
2584
2585 !load_cancellers.is_empty()
2586 }
2587
2588 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
2590 self.loader.borrow_mut().inhibit_events();
2592
2593 for iframe in self.iframes().iter() {
2595 if let Some(document) = iframe.GetContentDocument() {
2596 document.abort(cx);
2597 }
2598 }
2599
2600 self.script_blocking_stylesheets_count.set(0);
2606 *self.pending_parsing_blocking_script.borrow_mut() = None;
2607 *self.asap_scripts_set.borrow_mut() = vec![];
2608 self.asap_in_order_scripts_list.clear();
2609 self.deferred_scripts.clear();
2610 let loads_cancelled = self.terminate_fetch_group();
2611 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2612 if loads_cancelled || event_sources_canceled {
2613 self.salvageable.set(false);
2615 };
2616
2617 self.owner_global()
2622 .task_manager()
2623 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2624
2625 if let Some(parser) = self.get_current_parser() {
2630 self.active_parser_was_aborted.set(true);
2632 parser.abort(cx);
2634 self.salvageable.set(false);
2636 }
2637 }
2638
2639 pub(crate) fn notify_constellation_load(&self) {
2640 self.window()
2641 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2642 }
2643
2644 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2645 self.current_parser.set(script);
2646 }
2647
2648 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2649 self.current_parser.get()
2650 }
2651
2652 pub(crate) fn get_current_parser_line(&self) -> u32 {
2653 self.get_current_parser()
2654 .map(|parser| parser.get_current_line())
2655 .unwrap_or(0)
2656 }
2657
2658 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2661 self.iframes.borrow_mut().validate(self);
2662 self.iframes.borrow()
2663 }
2664
2665 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2668 self.iframes.borrow_mut().validate(self);
2669 self.iframes.borrow_mut()
2670 }
2671
2672 pub(crate) fn invalidate_iframes_collection(&self) {
2673 self.iframes.borrow_mut().invalidate();
2674 }
2675
2676 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2677 self.dom_interactive.get()
2678 }
2679
2680 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2681 self.interactive_time
2682 .borrow_mut()
2683 .set_navigation_start(navigation_start);
2684 }
2685
2686 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2687 self.interactive_time.borrow()
2688 }
2689
2690 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2691 self.get_interactive_metrics().get_tti().is_some()
2692 }
2693
2694 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2695 self.dom_content_loaded_event_start.get()
2696 }
2697
2698 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2699 self.dom_content_loaded_event_end.get()
2700 }
2701
2702 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2703 self.dom_complete.get()
2704 }
2705
2706 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2707 self.top_level_dom_complete.get()
2708 }
2709
2710 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2711 self.load_event_start.get()
2712 }
2713
2714 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2715 self.load_event_end.get()
2716 }
2717
2718 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2719 self.unload_event_start.get()
2720 }
2721
2722 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2723 self.unload_event_end.get()
2724 }
2725
2726 pub(crate) fn start_tti(&self) {
2727 if self.get_interactive_metrics().needs_tti() {
2728 self.tti_window.borrow_mut().start_window();
2729 }
2730 }
2731
2732 pub(crate) fn record_tti_if_necessary(&self) {
2736 if self.has_recorded_tti_metric() {
2737 return;
2738 }
2739 if self.tti_window.borrow().needs_check() {
2740 self.get_interactive_metrics()
2741 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2742 self.tti_window.borrow().get_start(),
2743 ));
2744 }
2745 }
2746
2747 pub(crate) fn is_cookie_averse(&self) -> bool {
2749 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2750 }
2751
2752 pub(crate) fn lookup_custom_element_definition(
2754 &self,
2755 namespace: &Namespace,
2756 local_name: &LocalName,
2757 is: Option<&LocalName>,
2758 ) -> Option<Rc<CustomElementDefinition>> {
2759 if *namespace != ns!(html) {
2761 return None;
2762 }
2763
2764 if !self.has_browsing_context {
2766 return None;
2767 }
2768
2769 let registry = self.window.CustomElements();
2771
2772 registry.lookup_definition(local_name, is)
2773 }
2774
2775 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
2777 self.window.CustomElements()
2778 }
2779
2780 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2781 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2782 self.throw_on_dynamic_markup_insertion_counter
2783 .set(counter + 1);
2784 }
2785
2786 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2787 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2788 self.throw_on_dynamic_markup_insertion_counter
2789 .set(counter - 1);
2790 }
2791
2792 pub(crate) fn react_to_environment_changes(&self) {
2793 for image in self.responsive_images.borrow().iter() {
2794 image.react_to_environment_changes();
2795 }
2796 }
2797
2798 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2799 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2800 }
2801
2802 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2803 let index = self
2804 .responsive_images
2805 .borrow()
2806 .iter()
2807 .position(|x| **x == *img);
2808 if let Some(i) = index {
2809 self.responsive_images.borrow_mut().remove(i);
2810 }
2811 }
2812
2813 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
2814 let did_have_these_media_controls = self
2815 .media_controls
2816 .borrow_mut()
2817 .insert(id.to_string(), Dom::from_ref(controls))
2818 .is_some();
2819 debug_assert!(
2820 !did_have_these_media_controls,
2821 "Trying to register known media controls"
2822 );
2823 }
2824
2825 pub(crate) fn unregister_media_controls(&self, id: &str) {
2826 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2827 debug_assert!(
2828 did_have_these_media_controls,
2829 "Trying to unregister unknown media controls"
2830 );
2831 }
2832
2833 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
2834 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
2835 if dirty_canvases
2836 .iter()
2837 .any(|dirty_canvas| dirty_canvas == canvas)
2838 {
2839 return;
2840 }
2841 dirty_canvases.push(canvas.clone());
2842 }
2843
2844 pub(crate) fn needs_rendering_update(&self) -> bool {
2848 if !self.is_fully_active() {
2849 return false;
2850 }
2851 if !self.window().layout_blocked() &&
2852 (!self.restyle_reason().is_empty() ||
2853 self.window().layout().needs_new_display_list() ||
2854 self.window().layout().needs_accessibility_update())
2855 {
2856 return true;
2857 }
2858 if !self.rendering_update_reasons.get().is_empty() {
2859 return true;
2860 }
2861 if self.event_handler.has_pending_input_events() {
2862 return true;
2863 }
2864 if self.has_pending_scroll_events() {
2865 return true;
2866 }
2867 if self.window().has_unhandled_resize_event() {
2868 return true;
2869 }
2870 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
2871 {
2872 return true;
2873 }
2874
2875 false
2876 }
2877
2878 pub(crate) fn update_the_rendering(&self) -> (ReflowPhasesRun, ReflowStatistics) {
2886 assert!(!self.is_render_blocked());
2887
2888 let mut phases = ReflowPhasesRun::empty();
2889 if self.has_pending_animated_image_update.get() {
2890 self.image_animation_manager
2891 .borrow()
2892 .update_active_frames(&self.window, self.current_animation_timeline_value());
2893 self.has_pending_animated_image_update.set(false);
2894 phases.insert(ReflowPhasesRun::UpdatedImageData);
2895 }
2896
2897 self.current_rendering_epoch
2898 .set(self.current_rendering_epoch.get().next());
2899 let current_rendering_epoch = self.current_rendering_epoch.get();
2900
2901 let image_keys: Vec<_> = self
2903 .dirty_canvases
2904 .borrow_mut()
2905 .drain(..)
2906 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
2907 .collect();
2908
2909 let pipeline_id = self.window().pipeline_id();
2912 if !image_keys.is_empty() {
2913 phases.insert(ReflowPhasesRun::UpdatedImageData);
2914 self.waiting_on_canvas_image_updates.set(true);
2915 self.window().paint_api().delay_new_frame_for_canvas(
2916 self.webview_id(),
2917 self.window().pipeline_id(),
2918 current_rendering_epoch,
2919 image_keys,
2920 );
2921 }
2922
2923 let (reflow_phases, statistics) = self.window().reflow(ReflowGoal::UpdateTheRendering);
2924 let phases = phases.union(reflow_phases);
2925
2926 self.window().paint_api().update_epoch(
2927 self.webview_id(),
2928 pipeline_id,
2929 current_rendering_epoch,
2930 );
2931
2932 (phases, statistics)
2933 }
2934
2935 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2936 self.waiting_on_canvas_image_updates.set(false);
2937 }
2938
2939 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2940 self.waiting_on_canvas_image_updates.get()
2941 }
2942
2943 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2953 if !self.is_fully_active() {
2954 return false;
2955 }
2956
2957 let fonts = self.Fonts(can_gc);
2958 if !fonts.waiting_to_fullfill_promise() {
2959 return false;
2960 }
2961 if self.window().font_context().web_fonts_still_loading() != 0 {
2962 return false;
2963 }
2964 if self.ReadyState() != DocumentReadyState::Complete {
2965 return false;
2966 }
2967 if !self.restyle_reason().is_empty() {
2968 return false;
2969 }
2970 if !self.rendering_update_reasons.get().is_empty() {
2971 return false;
2972 }
2973
2974 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
2975
2976 if result {
2980 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
2981 }
2982
2983 result
2984 }
2985
2986 pub(crate) fn id_map(
2987 &self,
2988 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2989 self.id_map.borrow()
2990 }
2991
2992 pub(crate) fn name_map(
2993 &self,
2994 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2995 self.name_map.borrow()
2996 }
2997
2998 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3000 self.resize_observers
3001 .borrow_mut()
3002 .push(Dom::from_ref(resize_observer));
3003 }
3004
3005 pub(crate) fn has_resize_observers(&self) -> bool {
3007 !self.resize_observers.borrow().is_empty()
3008 }
3009
3010 pub(crate) fn gather_active_resize_observations_at_depth(
3013 &self,
3014 depth: &ResizeObservationDepth,
3015 ) -> bool {
3016 let mut has_active_resize_observations = false;
3017 for observer in self.resize_observers.borrow_mut().iter_mut() {
3018 observer.gather_active_resize_observations_at_depth(
3019 depth,
3020 &mut has_active_resize_observations,
3021 );
3022 }
3023 has_active_resize_observations
3024 }
3025
3026 #[expect(clippy::redundant_iter_cloned)]
3028 pub(crate) fn broadcast_active_resize_observations(
3029 &self,
3030 can_gc: CanGc,
3031 ) -> ResizeObservationDepth {
3032 let mut shallowest = ResizeObservationDepth::max();
3033 let iterator: Vec<DomRoot<ResizeObserver>> = self
3037 .resize_observers
3038 .borrow()
3039 .iter()
3040 .cloned()
3041 .map(|obs| DomRoot::from_ref(&*obs))
3042 .collect();
3043 for observer in iterator {
3044 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3045 }
3046 shallowest
3047 }
3048
3049 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3051 self.resize_observers
3052 .borrow()
3053 .iter()
3054 .any(|observer| observer.has_skipped_resize_observations())
3055 }
3056
3057 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3059 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3060 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3061 ..Default::default()
3062 };
3063 self.window
3064 .as_global_scope()
3065 .report_an_error(error_info, HandleValue::null(), can_gc);
3066 }
3067
3068 pub(crate) fn status_code(&self) -> Option<u16> {
3069 self.status_code
3070 }
3071
3072 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3074 let encoding = self.encoding.get();
3080
3081 let base_url = self.base_url();
3087
3088 url::Url::options()
3090 .base_url(Some(base_url.as_url()))
3091 .encoding_override(Some(&|input| {
3092 servo_url::encoding::encode_as_url_query_string(input, encoding)
3093 }))
3094 .parse(url)
3095 .map(ServoUrl::from)
3096 }
3097
3098 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3100 if !self.has_browsing_context {
3102 return false;
3103 }
3104
3105 if !self.is_fully_active() {
3107 return false;
3108 }
3109
3110 true
3116 }
3117
3118 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3121 self.intersection_observers
3122 .borrow_mut()
3123 .push(Dom::from_ref(intersection_observer));
3124 }
3125
3126 pub(crate) fn remove_intersection_observer(
3130 &self,
3131 intersection_observer: &IntersectionObserver,
3132 ) {
3133 self.intersection_observers
3134 .borrow_mut()
3135 .retain(|observer| *observer != intersection_observer)
3136 }
3137
3138 pub(crate) fn update_intersection_observer_steps(
3140 &self,
3141 time: CrossProcessInstant,
3142 can_gc: CanGc,
3143 ) {
3144 for intersection_observer in &*self.intersection_observers.borrow() {
3146 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3147 }
3148 }
3149
3150 fn update_single_intersection_observer_steps(
3152 &self,
3153 intersection_observer: &IntersectionObserver,
3154 time: CrossProcessInstant,
3155 can_gc: CanGc,
3156 ) {
3157 let root_bounds = intersection_observer.root_intersection_rectangle();
3160
3161 intersection_observer.update_intersection_observations_steps(
3165 self,
3166 time,
3167 root_bounds,
3168 can_gc,
3169 );
3170 }
3171
3172 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3174 self.intersection_observer_task_queued.set(false);
3177
3178 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3183
3184 for intersection_observer in notify_list.iter() {
3187 intersection_observer.invoke_callback_if_necessary(can_gc);
3189 }
3190 }
3191
3192 pub(crate) fn queue_an_intersection_observer_task(&self) {
3194 if self.intersection_observer_task_queued.get() {
3197 return;
3198 }
3199
3200 self.intersection_observer_task_queued.set(true);
3203
3204 let document = Trusted::new(self);
3208 self.owner_global()
3209 .task_manager()
3210 .intersection_observer_task_source()
3211 .queue(task!(notify_intersection_observers: move || {
3212 document.root().notify_intersection_observers(CanGc::deprecated_note());
3213 }));
3214 }
3215
3216 pub(crate) fn handle_paint_metric(
3217 &self,
3218 metric_type: ProgressiveWebMetricType,
3219 metric_value: CrossProcessInstant,
3220 first_reflow: bool,
3221 can_gc: CanGc,
3222 ) {
3223 let metrics = self.interactive_time.borrow();
3224 match metric_type {
3225 ProgressiveWebMetricType::FirstPaint |
3226 ProgressiveWebMetricType::FirstContentfulPaint => {
3227 let binding = PerformancePaintTiming::new(
3228 self.window.as_global_scope(),
3229 metric_type.clone(),
3230 metric_value,
3231 can_gc,
3232 );
3233 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3234 let entry = binding.upcast::<PerformanceEntry>();
3235 self.window.Performance().queue_entry(entry);
3236 },
3237 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3238 let binding = LargestContentfulPaint::new(
3239 self.window.as_global_scope(),
3240 metric_value,
3241 area,
3242 url,
3243 can_gc,
3244 );
3245 metrics.set_largest_contentful_paint(metric_value, area);
3246 let entry = binding.upcast::<PerformanceEntry>();
3247 self.window.Performance().queue_entry(entry);
3248 },
3249 ProgressiveWebMetricType::TimeToInteractive => {
3250 unreachable!("Unexpected non-paint metric.")
3251 },
3252 }
3253 }
3254
3255 fn write(
3257 &self,
3258 cx: &mut js::context::JSContext,
3259 text: Vec<TrustedHTMLOrString>,
3260 line_feed: bool,
3261 containing_class: &str,
3262 field: &str,
3263 ) -> ErrorResult {
3264 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3266 let mut is_trusted = true;
3268 for value in text {
3270 match value {
3271 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3273 strings.push(trusted_html.to_string());
3274 },
3275 TrustedHTMLOrString::String(str_) => {
3276 is_trusted = false;
3278 strings.push(str_.into());
3280 },
3281 };
3282 }
3283 let mut string = itertools::join(strings, "");
3284 if !is_trusted {
3288 string = TrustedHTML::get_trusted_type_compliant_string(
3289 cx,
3290 &self.global(),
3291 TrustedHTMLOrString::String(string.into()),
3292 &format!("{} {}", containing_class, field),
3293 )?
3294 .str()
3295 .to_owned();
3296 }
3297 if line_feed {
3299 string.push('\n');
3300 }
3301 if !self.is_html_document() {
3303 return Err(Error::InvalidState(None));
3304 }
3305
3306 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3309 return Err(Error::InvalidState(None));
3310 }
3311
3312 if !self.is_active() || self.active_parser_was_aborted.get() {
3314 return Ok(());
3315 }
3316
3317 let parser = match self.get_current_parser() {
3318 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3319 _ => {
3321 if self.is_prompting_or_unloading() ||
3324 self.ignore_destructive_writes_counter.get() > 0
3325 {
3326 return Ok(());
3327 }
3328 self.Open(cx, None, None)?;
3330 self.get_current_parser().unwrap()
3331 },
3332 };
3333
3334 parser.write(string.into(), cx);
3336
3337 Ok(())
3338 }
3339
3340 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3341 RefMut::map(
3342 self.details_name_groups.borrow_mut(),
3343 |details_name_groups| details_name_groups.get_or_insert_default(),
3344 )
3345 }
3346}
3347
3348#[derive(MallocSizeOf, PartialEq)]
3349pub(crate) enum DocumentSource {
3350 FromParser,
3351 NotFromParser,
3352}
3353
3354#[expect(unsafe_code)]
3355impl<'dom> LayoutDom<'dom, Document> {
3356 #[inline]
3357 pub(crate) fn is_html_document_for_layout(&self) -> bool {
3358 self.unsafe_get().is_html_document
3359 }
3360
3361 #[inline]
3362 pub(crate) fn quirks_mode(self) -> QuirksMode {
3363 self.unsafe_get().quirks_mode.get()
3364 }
3365
3366 #[inline]
3367 pub(crate) fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3368 self.unsafe_get().style_shared_lock()
3369 }
3370
3371 #[inline]
3372 pub(crate) fn flush_shadow_root_stylesheets_if_necessary(
3373 self,
3374 stylist: &mut Stylist,
3375 guard: &SharedRwLockReadGuard,
3376 ) {
3377 (*self.unsafe_get()).flush_shadow_root_stylesheets_if_necessary_for_layout(stylist, guard)
3378 }
3379
3380 #[inline]
3381 pub(crate) fn shadow_roots_styles_changed(self) -> bool {
3382 self.unsafe_get().shadow_roots_styles_changed.get()
3383 }
3384
3385 pub(crate) fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3386 let id_map = unsafe { self.unsafe_get().id_map.borrow_for_layout() };
3387 let matching_elements = id_map.get(id).map(Vec::as_slice).unwrap_or_default();
3388 unsafe { LayoutDom::to_layout_slice(matching_elements) }
3389 }
3390}
3391
3392pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3396 host_suffix_string: &str,
3397 original_host: Host,
3398) -> Option<Host> {
3399 if host_suffix_string.is_empty() {
3401 return None;
3402 }
3403
3404 let host = match Host::parse(host_suffix_string) {
3406 Ok(host) => host,
3407 Err(_) => return None,
3408 };
3409
3410 if host != original_host {
3412 let host = match host {
3414 Host::Domain(ref host) => host,
3415 _ => return None,
3416 };
3417 let original_host = match original_host {
3418 Host::Domain(ref original_host) => original_host,
3419 _ => return None,
3420 };
3421
3422 let index = original_host.len().checked_sub(host.len())?;
3424 let (prefix, suffix) = original_host.split_at(index);
3425
3426 if !prefix.ends_with('.') {
3427 return None;
3428 }
3429 if suffix != host {
3430 return None;
3431 }
3432
3433 if is_pub_domain(host) {
3435 return None;
3436 }
3437 }
3438
3439 Some(host)
3441}
3442
3443fn url_has_network_scheme(url: &ServoUrl) -> bool {
3445 matches!(url.scheme(), "ftp" | "http" | "https")
3446}
3447
3448#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3449pub(crate) enum HasBrowsingContext {
3450 No,
3451 Yes,
3452}
3453
3454impl Document {
3455 #[allow(clippy::too_many_arguments)]
3456 pub(crate) fn new_inherited(
3457 window: &Window,
3458 has_browsing_context: HasBrowsingContext,
3459 url: Option<ServoUrl>,
3460 about_base_url: Option<ServoUrl>,
3461 origin: MutableOrigin,
3462 is_html_document: IsHTMLDocument,
3463 content_type: Option<Mime>,
3464 last_modified: Option<String>,
3465 activity: DocumentActivity,
3466 source: DocumentSource,
3467 doc_loader: DocumentLoader,
3468 referrer: Option<String>,
3469 status_code: Option<u16>,
3470 canceller: FetchCanceller,
3471 is_initial_about_blank: bool,
3472 allow_declarative_shadow_roots: bool,
3473 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3474 has_trustworthy_ancestor_origin: bool,
3475 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3476 creation_sandboxing_flag_set: SandboxingFlagSet,
3477 can_gc: CanGc,
3478 ) -> Document {
3479 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3480
3481 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3482 (DocumentReadyState::Loading, false)
3483 } else {
3484 (DocumentReadyState::Complete, true)
3485 };
3486
3487 let frame_type = match window.is_top_level() {
3488 true => TimerMetadataFrameType::RootWindow,
3489 false => TimerMetadataFrameType::IFrame,
3490 };
3491 let interactive_time = ProgressiveWebMetrics::new(
3492 window.time_profiler_chan().clone(),
3493 url.clone(),
3494 frame_type,
3495 );
3496
3497 let content_type = content_type.unwrap_or_else(|| {
3498 match is_html_document {
3499 IsHTMLDocument::HTMLDocument => "text/html",
3501 IsHTMLDocument::NonHTMLDocument => "application/xml",
3503 }
3504 .parse()
3505 .unwrap()
3506 });
3507
3508 let encoding = content_type
3509 .get_parameter(CHARSET)
3510 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3511 .unwrap_or(UTF_8);
3512
3513 let has_focus = window.parent_info().is_none();
3514
3515 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3516
3517 Document {
3518 node: Node::new_document_node(),
3519 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3520 window: Dom::from_ref(window),
3521 has_browsing_context,
3522 implementation: Default::default(),
3523 content_type,
3524 last_modified,
3525 url: DomRefCell::new(url),
3526 about_base_url: DomRefCell::new(about_base_url),
3527 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3529 event_handler: DocumentEventHandler::new(window),
3530 focus_handler: DocumentFocusHandler::new(window, has_focus),
3531 embedder_controls: DocumentEmbedderControls::new(window),
3532 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3533 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3534 encoding: Cell::new(encoding),
3536 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3537 activity: Cell::new(activity),
3538 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3539 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3540 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3541 images: Default::default(),
3542 embeds: Default::default(),
3543 links: Default::default(),
3544 forms: Default::default(),
3545 scripts: Default::default(),
3546 anchors: Default::default(),
3547 applets: Default::default(),
3548 iframes: RefCell::new(IFrameCollection::new()),
3549 style_shared_lock: {
3550 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3557 LazyLock::new(StyleSharedRwLock::new);
3558
3559 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3560 },
3562 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3563 stylesheet_list: MutNullableDom::new(None),
3564 ready_state: Cell::new(ready_state),
3565 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3566
3567 current_script: Default::default(),
3568 pending_parsing_blocking_script: Default::default(),
3569 script_blocking_stylesheets_count: Default::default(),
3570 render_blocking_element_count: Default::default(),
3571 deferred_scripts: Default::default(),
3572 asap_in_order_scripts_list: Default::default(),
3573 asap_scripts_set: Default::default(),
3574 animation_frame_ident: Cell::new(0),
3575 animation_frame_list: DomRefCell::new(VecDeque::new()),
3576 running_animation_callbacks: Cell::new(false),
3577 loader: DomRefCell::new(doc_loader),
3578 current_parser: Default::default(),
3579 base_element: Default::default(),
3580 target_base_element: Default::default(),
3581 appropriate_template_contents_owner_document: Default::default(),
3582 pending_restyles: DomRefCell::new(FxHashMap::default()),
3583 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3584 dom_interactive: Cell::new(Default::default()),
3585 dom_content_loaded_event_start: Cell::new(Default::default()),
3586 dom_content_loaded_event_end: Cell::new(Default::default()),
3587 dom_complete: Cell::new(Default::default()),
3588 top_level_dom_complete: Cell::new(Default::default()),
3589 load_event_start: Cell::new(Default::default()),
3590 load_event_end: Cell::new(Default::default()),
3591 unload_event_start: Cell::new(Default::default()),
3592 unload_event_end: Cell::new(Default::default()),
3593 https_state: Cell::new(HttpsState::None),
3594 origin: DomRefCell::new(origin),
3595 referrer,
3596 target_element: MutNullableDom::new(None),
3597 policy_container: DomRefCell::new(PolicyContainer::default()),
3598 preloaded_resources: Default::default(),
3599 ignore_destructive_writes_counter: Default::default(),
3600 ignore_opens_during_unload_counter: Default::default(),
3601 spurious_animation_frames: Cell::new(0),
3602 fullscreen_element: MutNullableDom::new(None),
3603 form_id_listener_map: Default::default(),
3604 interactive_time: DomRefCell::new(interactive_time),
3605 tti_window: DomRefCell::new(InteractiveWindow::default()),
3606 canceller,
3607 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3608 page_showing: Cell::new(false),
3609 salvageable: Cell::new(true),
3610 active_parser_was_aborted: Cell::new(false),
3611 fired_unload: Cell::new(false),
3612 responsive_images: Default::default(),
3613 redirect_count: Cell::new(0),
3614 completely_loaded: Cell::new(false),
3615 script_and_layout_blockers: Cell::new(0),
3616 delayed_tasks: Default::default(),
3617 shadow_roots: DomRefCell::new(HashSet::new()),
3618 shadow_roots_styles_changed: Cell::new(false),
3619 media_controls: DomRefCell::new(HashMap::new()),
3620 dirty_canvases: DomRefCell::new(Default::default()),
3621 has_pending_animated_image_update: Cell::new(false),
3622 selection: MutNullableDom::new(None),
3623 timeline: DocumentTimeline::new(window, can_gc).as_traced(),
3624 animations: Animations::new(),
3625 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3626 dirty_root: Default::default(),
3627 declarative_refresh: Default::default(),
3628 resize_observers: Default::default(),
3629 fonts: Default::default(),
3630 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3631 status_code,
3632 is_initial_about_blank: Cell::new(is_initial_about_blank),
3633 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3634 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3635 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3636 intersection_observer_task_queued: Cell::new(false),
3637 intersection_observers: Default::default(),
3638 highlighted_dom_node: Default::default(),
3639 adopted_stylesheets: Default::default(),
3640 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3641 pending_scroll_events: Default::default(),
3642 rendering_update_reasons: Default::default(),
3643 waiting_on_canvas_image_updates: Cell::new(false),
3644 root_removal_noted: Cell::new(true),
3645 current_rendering_epoch: Default::default(),
3646 custom_element_reaction_stack,
3647 active_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3648 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3649 favicon: RefCell::new(None),
3650 websockets: DOMTracker::new(),
3651 details_name_groups: Default::default(),
3652 protocol_handler_automation_mode: Default::default(),
3653 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3654 state_override: Default::default(),
3655 value_override: Default::default(),
3656 default_single_line_container_name: Default::default(),
3657 css_styling_flag: Default::default(),
3658 }
3659 }
3660
3661 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3663 if let Some(csp_list) = self.get_csp_list().as_ref() {
3664 for policy in &csp_list.0 {
3665 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3666 policy.disposition == PolicyDisposition::Enforce
3667 {
3668 return InsecureRequestsPolicy::Upgrade;
3669 }
3670 }
3671 }
3672
3673 self.inherited_insecure_requests_policy
3674 .get()
3675 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3676 }
3677
3678 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3680 &self.event_handler
3681 }
3682
3683 pub(crate) fn focus_handler(&self) -> &DocumentFocusHandler {
3685 &self.focus_handler
3686 }
3687
3688 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3690 &self.embedder_controls
3691 }
3692
3693 fn has_pending_scroll_events(&self) -> bool {
3696 !self.pending_scroll_events.borrow().is_empty()
3697 }
3698
3699 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3702 self.rendering_update_reasons
3703 .set(self.rendering_update_reasons.get().union(reason));
3704 }
3705
3706 pub(crate) fn clear_rendering_update_reasons(&self) {
3708 self.rendering_update_reasons
3709 .set(RenderingUpdateReason::empty())
3710 }
3711
3712 pub(crate) fn add_script_and_layout_blocker(&self) {
3719 self.script_and_layout_blockers
3720 .set(self.script_and_layout_blockers.get() + 1);
3721 }
3722
3723 #[expect(unsafe_code)]
3724 pub(crate) fn remove_script_and_layout_blocker(&self) {
3728 assert!(self.script_and_layout_blockers.get() > 0);
3729 self.script_and_layout_blockers
3730 .set(self.script_and_layout_blockers.get() - 1);
3731 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3732 {
3733 let task = self.delayed_tasks.borrow_mut().remove(0);
3734 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
3735 task.run_box(&mut cx);
3736 }
3737 }
3738
3739 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3741 self.delayed_tasks.borrow_mut().push(Box::new(task));
3742 }
3743
3744 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3747 assert_eq!(
3748 self.script_and_layout_blockers.get(),
3749 0,
3750 "Attempt to use script or layout while DOM not in a stable state"
3751 );
3752 }
3753
3754 #[allow(clippy::too_many_arguments)]
3755 pub(crate) fn new(
3756 window: &Window,
3757 has_browsing_context: HasBrowsingContext,
3758 url: Option<ServoUrl>,
3759 about_base_url: Option<ServoUrl>,
3760 origin: MutableOrigin,
3761 doctype: IsHTMLDocument,
3762 content_type: Option<Mime>,
3763 last_modified: Option<String>,
3764 activity: DocumentActivity,
3765 source: DocumentSource,
3766 doc_loader: DocumentLoader,
3767 referrer: Option<String>,
3768 status_code: Option<u16>,
3769 canceller: FetchCanceller,
3770 is_initial_about_blank: bool,
3771 allow_declarative_shadow_roots: bool,
3772 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3773 has_trustworthy_ancestor_origin: bool,
3774 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3775 creation_sandboxing_flag_set: SandboxingFlagSet,
3776 can_gc: CanGc,
3777 ) -> DomRoot<Document> {
3778 Self::new_with_proto(
3779 window,
3780 None,
3781 has_browsing_context,
3782 url,
3783 about_base_url,
3784 origin,
3785 doctype,
3786 content_type,
3787 last_modified,
3788 activity,
3789 source,
3790 doc_loader,
3791 referrer,
3792 status_code,
3793 canceller,
3794 is_initial_about_blank,
3795 allow_declarative_shadow_roots,
3796 inherited_insecure_requests_policy,
3797 has_trustworthy_ancestor_origin,
3798 custom_element_reaction_stack,
3799 creation_sandboxing_flag_set,
3800 can_gc,
3801 )
3802 }
3803
3804 #[allow(clippy::too_many_arguments)]
3805 fn new_with_proto(
3806 window: &Window,
3807 proto: Option<HandleObject>,
3808 has_browsing_context: HasBrowsingContext,
3809 url: Option<ServoUrl>,
3810 about_base_url: Option<ServoUrl>,
3811 origin: MutableOrigin,
3812 doctype: IsHTMLDocument,
3813 content_type: Option<Mime>,
3814 last_modified: Option<String>,
3815 activity: DocumentActivity,
3816 source: DocumentSource,
3817 doc_loader: DocumentLoader,
3818 referrer: Option<String>,
3819 status_code: Option<u16>,
3820 canceller: FetchCanceller,
3821 is_initial_about_blank: bool,
3822 allow_declarative_shadow_roots: bool,
3823 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3824 has_trustworthy_ancestor_origin: bool,
3825 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3826 creation_sandboxing_flag_set: SandboxingFlagSet,
3827 can_gc: CanGc,
3828 ) -> DomRoot<Document> {
3829 let document = reflect_dom_object_with_proto(
3830 Box::new(Document::new_inherited(
3831 window,
3832 has_browsing_context,
3833 url,
3834 about_base_url,
3835 origin,
3836 doctype,
3837 content_type,
3838 last_modified,
3839 activity,
3840 source,
3841 doc_loader,
3842 referrer,
3843 status_code,
3844 canceller,
3845 is_initial_about_blank,
3846 allow_declarative_shadow_roots,
3847 inherited_insecure_requests_policy,
3848 has_trustworthy_ancestor_origin,
3849 custom_element_reaction_stack,
3850 creation_sandboxing_flag_set,
3851 can_gc,
3852 )),
3853 window,
3854 proto,
3855 can_gc,
3856 );
3857 {
3858 let node = document.upcast::<Node>();
3859 node.set_owner_doc(&document);
3860 }
3861 document
3862 }
3863
3864 pub(crate) fn get_redirect_count(&self) -> u16 {
3865 self.redirect_count.get()
3866 }
3867
3868 pub(crate) fn set_redirect_count(&self, count: u16) {
3869 self.redirect_count.set(count)
3870 }
3871
3872 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3873 if name.is_empty() {
3874 return 0;
3875 }
3876 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3877 }
3878
3879 pub(crate) fn nth_element_by_name(
3880 &self,
3881 index: u32,
3882 name: &DOMString,
3883 ) -> Option<DomRoot<Node>> {
3884 if name.is_empty() {
3885 return None;
3886 }
3887 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3888 }
3889
3890 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3893 let element = match node.downcast::<Element>() {
3894 Some(element) => element,
3895 None => return false,
3896 };
3897 if element.namespace() != &ns!(html) {
3898 return false;
3899 }
3900 element.get_name().is_some_and(|n| &*n == name)
3901 }
3902
3903 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3904 let doc = self.GetDocumentElement();
3905 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3906 maybe_node
3907 .iter()
3908 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3909 .filter(|node| callback(node))
3910 .count() as u32
3911 }
3912
3913 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3914 &self,
3915 index: u32,
3916 callback: F,
3917 ) -> Option<DomRoot<Node>> {
3918 let doc = self.GetDocumentElement();
3919 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3920 maybe_node
3921 .iter()
3922 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3923 .filter(|node| callback(node))
3924 .nth(index as usize)
3925 .map(|n| DomRoot::from_ref(&*n))
3926 }
3927
3928 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3929 self.GetDocumentElement().and_then(DomRoot::downcast)
3930 }
3931
3932 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3934 &self.style_shared_lock
3935 }
3936
3937 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3939 let mut stylesheets = self.stylesheets.borrow_mut();
3946 let have_changed = stylesheets.has_changed();
3947 stylesheets.flush_without_invalidation();
3948 have_changed
3949 }
3950
3951 pub(crate) fn salvageable(&self) -> bool {
3952 self.salvageable.get()
3953 }
3954
3955 pub(crate) fn make_document_unsalvageable(&self) {
3957 self.salvageable.set(false);
3963 }
3964
3965 pub(crate) fn appropriate_template_contents_owner_document(
3967 &self,
3968 can_gc: CanGc,
3969 ) -> DomRoot<Document> {
3970 self.appropriate_template_contents_owner_document
3971 .or_init(|| {
3972 let doctype = if self.is_html_document {
3973 IsHTMLDocument::HTMLDocument
3974 } else {
3975 IsHTMLDocument::NonHTMLDocument
3976 };
3977 let new_doc = Document::new(
3978 self.window(),
3979 HasBrowsingContext::No,
3980 None,
3981 None,
3982 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3984 doctype,
3985 None,
3986 None,
3987 DocumentActivity::Inactive,
3988 DocumentSource::NotFromParser,
3989 DocumentLoader::new(&self.loader()),
3990 None,
3991 None,
3992 Default::default(),
3993 false,
3994 self.allow_declarative_shadow_roots(),
3995 Some(self.insecure_requests_policy()),
3996 self.has_trustworthy_ancestor_or_current_origin(),
3997 self.custom_element_reaction_stack.clone(),
3998 self.creation_sandboxing_flag_set(),
3999 can_gc,
4000 );
4001 new_doc
4002 .appropriate_template_contents_owner_document
4003 .set(Some(&new_doc));
4004 new_doc
4005 })
4006 }
4007
4008 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4009 self.id_map
4010 .borrow()
4011 .get(id)
4012 .map(|elements| DomRoot::from_ref(&*elements[0]))
4013 }
4014
4015 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4016 let map = self.pending_restyles.borrow_mut();
4017 RefMut::map(map, |m| {
4018 &mut m
4019 .entry(Dom::from_ref(el))
4020 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4021 .0
4022 })
4023 }
4024
4025 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4026 let mut entry = self.ensure_pending_restyle(el);
4032 if entry.snapshot.is_none() {
4033 entry.snapshot = Some(Snapshot::new());
4034 }
4035 if attr.local_name() == &local_name!("style") {
4036 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4037 }
4038
4039 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4040 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4041 }
4042
4043 let snapshot = entry.snapshot.as_mut().unwrap();
4044 if attr.local_name() == &local_name!("id") {
4045 if snapshot.id_changed {
4046 return;
4047 }
4048 snapshot.id_changed = true;
4049 } else if attr.local_name() == &local_name!("class") {
4050 if snapshot.class_changed {
4051 return;
4052 }
4053 snapshot.class_changed = true;
4054 } else {
4055 snapshot.other_attributes_changed = true;
4056 }
4057 let local_name = style::LocalName::cast(attr.local_name());
4058 if !snapshot.changed_attrs.contains(local_name) {
4059 snapshot.changed_attrs.push(local_name.clone());
4060 }
4061 if snapshot.attrs.is_none() {
4062 let attrs = el
4063 .attrs()
4064 .iter()
4065 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4066 .collect();
4067 snapshot.attrs = Some(attrs);
4068 }
4069 }
4070
4071 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4072 self.policy_container
4073 .borrow_mut()
4074 .set_referrer_policy(policy);
4075 }
4076
4077 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4078 self.policy_container.borrow().get_referrer_policy()
4079 }
4080
4081 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4082 if let Some(ref element) = self.target_element.get() {
4083 element.set_target_state(false);
4084 }
4085
4086 self.target_element.set(node);
4087
4088 if let Some(ref element) = self.target_element.get() {
4089 element.set_target_state(true);
4090 }
4091 }
4092
4093 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4094 self.ignore_destructive_writes_counter
4095 .set(self.ignore_destructive_writes_counter.get() + 1);
4096 }
4097
4098 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4099 self.ignore_destructive_writes_counter
4100 .set(self.ignore_destructive_writes_counter.get() - 1);
4101 }
4102
4103 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4104 self.ignore_opens_during_unload_counter.get() > 0
4105 }
4106
4107 fn incr_ignore_opens_during_unload_counter(&self) {
4108 self.ignore_opens_during_unload_counter
4109 .set(self.ignore_opens_during_unload_counter.get() + 1);
4110 }
4111
4112 fn decr_ignore_opens_during_unload_counter(&self) {
4113 self.ignore_opens_during_unload_counter
4114 .set(self.ignore_opens_during_unload_counter.get() - 1);
4115 }
4116
4117 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4118 self.fullscreen_element.set(element);
4119 }
4120
4121 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4122 let map = self.form_id_listener_map.borrow();
4123 if let Some(listeners) = map.get(id) {
4124 for listener in listeners {
4125 listener
4126 .as_maybe_form_control()
4127 .expect("Element must be a form control")
4128 .reset_form_owner(can_gc);
4129 }
4130 }
4131 }
4132
4133 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4134 self.shadow_roots
4135 .borrow_mut()
4136 .insert(Dom::from_ref(shadow_root));
4137 self.invalidate_shadow_roots_stylesheets();
4138 }
4139
4140 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4141 let mut shadow_roots = self.shadow_roots.borrow_mut();
4142 shadow_roots.remove(&Dom::from_ref(shadow_root));
4143 }
4144
4145 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4146 self.shadow_roots_styles_changed.set(true);
4147 }
4148
4149 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4150 self.shadow_roots_styles_changed.get()
4151 }
4152
4153 pub(crate) fn flush_shadow_root_stylesheets_if_necessary_for_layout(
4154 &self,
4155 stylist: &mut Stylist,
4156 guard: &SharedRwLockReadGuard,
4157 ) {
4158 if !self.shadow_roots_styles_changed.get() {
4159 return;
4160 }
4161 #[expect(unsafe_code)]
4162 unsafe {
4163 for shadow_root in self.shadow_roots.borrow_for_layout().iter() {
4164 shadow_root
4165 .to_layout()
4166 .flush_stylesheets_for_layout(stylist, guard);
4167 }
4168 }
4169 self.shadow_roots_styles_changed.set(false);
4170 }
4171
4172 pub(crate) fn stylesheet_count(&self) -> usize {
4173 self.stylesheets.borrow().len()
4174 }
4175
4176 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4177 let stylesheets = self.stylesheets.borrow();
4178
4179 stylesheets
4180 .get(Origin::Author, index)
4181 .and_then(|s| s.owner.get_cssom_object())
4182 }
4183
4184 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4191 let stylesheets = &mut *self.stylesheets.borrow_mut();
4192
4193 let insertion_point = stylesheets
4195 .iter()
4196 .map(|(sheet, _origin)| sheet)
4197 .find(|sheet_in_doc| {
4198 match &sheet_in_doc.owner {
4199 StylesheetSource::Element(other_node) => {
4200 owner_node.upcast::<Node>().is_before(other_node.upcast())
4201 },
4202 StylesheetSource::Constructed(_) => true,
4205 }
4206 })
4207 .cloned();
4208
4209 if self.has_browsing_context() {
4210 let document_context = self.window.web_font_context();
4211
4212 self.window.layout_mut().add_stylesheet(
4213 sheet.clone(),
4214 insertion_point.as_ref().map(|s| s.sheet.clone()),
4215 &document_context,
4216 );
4217 }
4218
4219 DocumentOrShadowRoot::add_stylesheet(
4220 StylesheetSource::Element(Dom::from_ref(owner_node)),
4221 StylesheetSetRef::Document(stylesheets),
4222 sheet,
4223 insertion_point,
4224 self.style_shared_lock(),
4225 );
4226 }
4227
4228 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4233 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4234 debug_assert!(cssom_stylesheet.is_constructed());
4235
4236 let stylesheets = &mut *self.stylesheets.borrow_mut();
4237 let sheet = cssom_stylesheet.style_stylesheet().clone();
4238
4239 let insertion_point = stylesheets
4240 .iter()
4241 .last()
4242 .map(|(sheet, _origin)| sheet)
4243 .cloned();
4244
4245 if self.has_browsing_context() {
4246 self.window.layout_mut().add_stylesheet(
4247 sheet.clone(),
4248 insertion_point.as_ref().map(|s| s.sheet.clone()),
4249 &self.window.web_font_context(),
4250 );
4251 }
4252
4253 DocumentOrShadowRoot::add_stylesheet(
4254 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4255 StylesheetSetRef::Document(stylesheets),
4256 sheet,
4257 insertion_point,
4258 self.style_shared_lock(),
4259 );
4260 }
4261
4262 pub(crate) fn load_web_fonts_from_stylesheet(
4264 &self,
4265 stylesheet: &Arc<Stylesheet>,
4266 document_context: &WebFontDocumentContext,
4267 ) {
4268 self.window
4269 .layout()
4270 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4271 }
4272
4273 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4276 if self.has_browsing_context() {
4277 self.window
4278 .layout_mut()
4279 .remove_stylesheet(stylesheet.clone());
4280 }
4281
4282 DocumentOrShadowRoot::remove_stylesheet(
4283 owner,
4284 stylesheet,
4285 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4286 )
4287 }
4288
4289 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4290 Ref::map(self.id_map.borrow(), |map| {
4291 map.get(id).map(|vec| &**vec).unwrap_or_default()
4292 })
4293 }
4294
4295 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4296 Ref::map(self.name_map.borrow(), |map| {
4297 map.get(name).map(|vec| &**vec).unwrap_or_default()
4298 })
4299 }
4300
4301 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4302 self.pending_restyles
4303 .borrow_mut()
4304 .drain()
4305 .filter_map(|(elem, restyle)| {
4306 let node = elem.upcast::<Node>();
4307 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4308 return None;
4309 }
4310 node.note_dirty_descendants();
4311 Some((node.to_trusted_node_address(), restyle.0))
4312 })
4313 .collect()
4314 }
4315
4316 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: TimeDuration) {
4317 self.timeline.advance_specific(delta);
4318 let current_timeline_value = self.current_animation_timeline_value();
4319 self.animations
4320 .update_for_new_timeline_value(&self.window, current_timeline_value);
4321 }
4322
4323 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4324 let current_timeline_value = self.current_animation_timeline_value();
4325 self.animations
4326 .mark_animating_nodes_as_dirty(current_timeline_value);
4327 }
4328
4329 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4330 self.timeline
4331 .upcast::<AnimationTimeline>()
4332 .current_time_in_seconds()
4333 }
4334
4335 pub(crate) fn animations(&self) -> &Animations {
4336 &self.animations
4337 }
4338
4339 pub(crate) fn update_animations_post_reflow(&self) {
4340 let current_timeline_value = self.current_animation_timeline_value();
4341 self.animations
4342 .do_post_reflow_update(&self.window, current_timeline_value);
4343 self.image_animation_manager
4344 .borrow_mut()
4345 .do_post_reflow_update(&self.window, current_timeline_value);
4346 }
4347
4348 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4349 self.animations.cancel_animations_for_node(node);
4350 self.image_animation_manager
4351 .borrow_mut()
4352 .cancel_animations_for_node(node);
4353 }
4354
4355 pub(crate) fn update_animations_and_send_events(&self, cx: &mut js::context::JSContext) {
4357 if !self.layout_animations_test_enabled {
4359 self.timeline.update(self.window());
4360 }
4361
4362 let current_timeline_value = self.current_animation_timeline_value();
4369 self.animations
4370 .update_for_new_timeline_value(&self.window, current_timeline_value);
4371 self.maybe_mark_animating_nodes_as_dirty();
4372
4373 self.window().perform_a_microtask_checkpoint(cx);
4375
4376 let _realm = enter_realm(self);
4378 self.animations()
4379 .send_pending_events(self.window(), CanGc::from_cx(cx));
4380 }
4381
4382 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4383 self.image_animation_manager.borrow()
4384 }
4385
4386 pub(crate) fn set_has_pending_animated_image_update(&self) {
4387 self.has_pending_animated_image_update.set(true);
4388 }
4389
4390 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4392 if self.will_declaratively_refresh() {
4394 return;
4395 }
4396
4397 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4399 Regex::new(
4403 r#"(?xs)
4404 ^
4405 \s* # 3
4406 ((?<time>[0-9]+)|\.) # 5-6
4407 [0-9.]* # 8
4408 (
4409 (
4410 (\s*;|\s*,|\s) # 10.3
4411 \s* # 10.4
4412 )
4413 (
4414 (
4415 (U|u)(R|r)(L|l) # 11.2-11.4
4416 \s*=\s* # 11.5-11.7
4417 )?
4418 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4419 |
4420 (?<url4>(?s-u:.)*)
4421 )
4422 )?
4423 $
4424 "#,
4425 )
4426 .unwrap()
4427 });
4428
4429 let mut url_record = self.url();
4431 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4432 captures
4433 } else {
4434 return;
4435 };
4436 let time = if let Some(time_string) = captures.name("time") {
4437 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4438 } else {
4439 0
4440 };
4441 let captured_url = captures.name("url1").or(captures
4442 .name("url2")
4443 .or(captures.name("url3").or(captures.name("url4"))));
4444
4445 if let Some(url_match) = captured_url {
4447 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4448 Some(&url_record),
4449 &String::from_utf8_lossy(url_match.as_bytes()),
4450 ) {
4451 info!("Refresh to {}", url.debug_compact());
4452 url
4453 } else {
4454 return;
4456 }
4457 }
4458 if self.completely_loaded() {
4460 self.window.as_global_scope().schedule_callback(
4462 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4463 window: DomRoot::from_ref(self.window()),
4464 url: url_record,
4465 }),
4466 Duration::from_secs(time),
4467 );
4468 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4469 } else {
4470 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4471 url: url_record,
4472 time,
4473 });
4474 }
4475 }
4476
4477 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4478 self.declarative_refresh.borrow().is_some()
4479 }
4480 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4481 *self.declarative_refresh.borrow_mut() = Some(refresh);
4482 }
4483
4484 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4486 if self.visibility_state.get() == visibility_state {
4488 return;
4489 }
4490 self.visibility_state.set(visibility_state);
4492 let entry = VisibilityStateEntry::new(
4495 &self.global(),
4496 visibility_state,
4497 CrossProcessInstant::now(),
4498 can_gc,
4499 );
4500 self.window
4501 .Performance()
4502 .queue_entry(entry.upcast::<PerformanceEntry>());
4503
4504 #[cfg(feature = "gamepad")]
4515 if visibility_state == DocumentVisibilityState::Hidden {
4516 self.window
4517 .Navigator()
4518 .GetGamepads()
4519 .iter_mut()
4520 .for_each(|gamepad| {
4521 if let Some(g) = gamepad {
4522 g.vibration_actuator().handle_visibility_change();
4523 }
4524 });
4525 }
4526
4527 self.upcast::<EventTarget>()
4529 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4530 }
4531
4532 pub(crate) fn is_initial_about_blank(&self) -> bool {
4534 self.is_initial_about_blank.get()
4535 }
4536
4537 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4539 self.allow_declarative_shadow_roots.get()
4540 }
4541
4542 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4543 self.has_trustworthy_ancestor_origin.get()
4544 }
4545
4546 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4547 self.has_trustworthy_ancestor_origin.get() ||
4548 self.origin().immutable().is_potentially_trustworthy()
4549 }
4550
4551 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4552 self.highlighted_dom_node.set(node);
4553 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4554 }
4555
4556 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4557 self.highlighted_dom_node.get()
4558 }
4559
4560 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4561 self.custom_element_reaction_stack.clone()
4562 }
4563
4564 pub(crate) fn active_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4565 self.active_sandboxing_flag_set.get()
4566 }
4567
4568 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4569 self.active_sandboxing_flag_set.get().contains(flag)
4570 }
4571
4572 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4573 self.active_sandboxing_flag_set.set(flags)
4574 }
4575
4576 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4577 self.creation_sandboxing_flag_set.get()
4578 }
4579
4580 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4581 &self,
4582 ) -> SandboxingFlagSet {
4583 self.window()
4584 .window_proxy()
4585 .frame_element()
4586 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4587 .map(HTMLIFrameElement::sandboxing_flag_set)
4588 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4589 }
4590
4591 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4592 self.window()
4593 .scrolling_box_query(None, flags)
4594 .expect("We should always have a ScrollingBox for the Viewport")
4595 }
4596
4597 pub(crate) fn notify_embedder_favicon(&self) {
4598 if let Some(ref image) = *self.favicon.borrow() {
4599 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4600 }
4601 }
4602
4603 pub(crate) fn set_favicon(&self, favicon: Image) {
4604 *self.favicon.borrow_mut() = Some(favicon);
4605 self.notify_embedder_favicon();
4606 }
4607
4608 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
4609 self.fullscreen_element.get()
4610 }
4611
4612 pub(crate) fn state_override(&self, command_name: &CommandName) -> Option<bool> {
4614 self.state_override.borrow().get(command_name).copied()
4615 }
4616
4617 pub(crate) fn set_state_override(&self, command_name: CommandName, state: Option<bool>) {
4619 if let Some(state) = state {
4620 self.state_override.borrow_mut().insert(command_name, state);
4621 } else {
4622 self.value_override.borrow_mut().remove(&command_name);
4623 }
4624 }
4625
4626 pub(crate) fn value_override(&self, command_name: &CommandName) -> Option<DOMString> {
4628 self.value_override.borrow().get(command_name).cloned()
4629 }
4630
4631 pub(crate) fn set_value_override(&self, command_name: CommandName, value: Option<DOMString>) {
4633 if let Some(value) = value {
4634 self.value_override.borrow_mut().insert(command_name, value);
4635 } else {
4636 self.value_override.borrow_mut().remove(&command_name);
4637 }
4638 }
4639
4640 pub(crate) fn clear_command_overrides(&self) {
4643 self.state_override.borrow_mut().clear();
4644 self.value_override.borrow_mut().clear();
4645 }
4646
4647 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
4649 self.default_single_line_container_name.get()
4650 }
4651
4652 pub(crate) fn set_default_single_line_container_name(
4654 &self,
4655 value: DefaultSingleLineContainerName,
4656 ) {
4657 self.default_single_line_container_name.set(value)
4658 }
4659
4660 pub(crate) fn css_styling_flag(&self) -> bool {
4662 self.css_styling_flag.get()
4663 }
4664
4665 pub(crate) fn set_css_styling_flag(&self, value: bool) {
4667 self.css_styling_flag.set(value)
4668 }
4669}
4670
4671impl DocumentMethods<crate::DomTypeHolder> for Document {
4672 fn Constructor(
4674 window: &Window,
4675 proto: Option<HandleObject>,
4676 can_gc: CanGc,
4677 ) -> Fallible<DomRoot<Document>> {
4678 let doc = window.Document();
4680 let docloader = DocumentLoader::new(&doc.loader());
4681 Ok(Document::new_with_proto(
4682 window,
4683 proto,
4684 HasBrowsingContext::No,
4685 None,
4686 None,
4687 doc.origin().clone(),
4688 IsHTMLDocument::NonHTMLDocument,
4689 None,
4690 None,
4691 DocumentActivity::Inactive,
4692 DocumentSource::NotFromParser,
4693 docloader,
4694 None,
4695 None,
4696 Default::default(),
4697 false,
4698 doc.allow_declarative_shadow_roots(),
4699 Some(doc.insecure_requests_policy()),
4700 doc.has_trustworthy_ancestor_or_current_origin(),
4701 doc.custom_element_reaction_stack(),
4702 doc.active_sandboxing_flag_set.get(),
4703 can_gc,
4704 ))
4705 }
4706
4707 fn ParseHTMLUnsafe(
4709 cx: &mut js::context::JSContext,
4710 window: &Window,
4711 s: TrustedHTMLOrString,
4712 ) -> Fallible<DomRoot<Self>> {
4713 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
4717 cx,
4718 window.as_global_scope(),
4719 s,
4720 "Document parseHTMLUnsafe",
4721 )?;
4722
4723 let url = window.get_url();
4724 let doc = window.Document();
4725 let loader = DocumentLoader::new(&doc.loader());
4726
4727 let content_type = "text/html"
4728 .parse()
4729 .expect("Supported type is not a MIME type");
4730 let document = Document::new(
4733 window,
4734 HasBrowsingContext::No,
4735 Some(ServoUrl::parse("about:blank").unwrap()),
4736 None,
4737 doc.origin().clone(),
4738 IsHTMLDocument::HTMLDocument,
4739 Some(content_type),
4740 None,
4741 DocumentActivity::Inactive,
4742 DocumentSource::FromParser,
4743 loader,
4744 None,
4745 None,
4746 Default::default(),
4747 false,
4748 true,
4749 Some(doc.insecure_requests_policy()),
4750 doc.has_trustworthy_ancestor_or_current_origin(),
4751 doc.custom_element_reaction_stack(),
4752 doc.creation_sandboxing_flag_set(),
4753 CanGc::from_cx(cx),
4754 );
4755 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, cx);
4757 document.set_ready_state(DocumentReadyState::Complete, CanGc::from_cx(cx));
4759 Ok(document)
4760 }
4761
4762 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4764 self.stylesheet_list.or_init(|| {
4765 StyleSheetList::new(
4766 &self.window,
4767 StyleSheetListOwner::Document(Dom::from_ref(self)),
4768 can_gc,
4769 )
4770 })
4771 }
4772
4773 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4775 self.implementation
4776 .or_init(|| DOMImplementation::new(self, can_gc))
4777 }
4778
4779 fn URL(&self) -> USVString {
4781 USVString(String::from(self.url().as_str()))
4782 }
4783
4784 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4786 self.document_or_shadow_root.active_element(self.upcast())
4787 }
4788
4789 fn HasFocus(&self) -> bool {
4791 if self.window().parent_info().is_none() {
4813 self.is_fully_active()
4815 } else {
4816 self.is_fully_active() && self.focus_handler.has_focus()
4818 }
4819 }
4820
4821 fn Domain(&self) -> DOMString {
4823 match self.origin().effective_domain() {
4825 None => DOMString::new(),
4827 Some(Host::Domain(domain)) => DOMString::from(domain),
4829 Some(host) => DOMString::from(host.to_string()),
4830 }
4831 }
4832
4833 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4835 if !self.has_browsing_context {
4837 return Err(Error::Security(None));
4838 }
4839
4840 if self.has_active_sandboxing_flag(
4843 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4844 ) {
4845 return Err(Error::Security(None));
4846 }
4847
4848 let effective_domain = match self.origin().effective_domain() {
4850 Some(effective_domain) => effective_domain,
4851 None => return Err(Error::Security(None)),
4853 };
4854
4855 let host =
4857 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
4858 None => return Err(Error::Security(None)),
4859 Some(host) => host,
4860 };
4861
4862 self.origin().set_domain(host);
4867
4868 Ok(())
4869 }
4870
4871 fn Referrer(&self) -> DOMString {
4873 match self.referrer {
4874 Some(ref referrer) => DOMString::from(referrer.to_string()),
4875 None => DOMString::new(),
4876 }
4877 }
4878
4879 fn DocumentURI(&self) -> USVString {
4881 self.URL()
4882 }
4883
4884 fn CompatMode(&self) -> DOMString {
4886 DOMString::from(match self.quirks_mode.get() {
4887 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4888 QuirksMode::Quirks => "BackCompat",
4889 })
4890 }
4891
4892 fn CharacterSet(&self) -> DOMString {
4894 DOMString::from(self.encoding.get().name())
4895 }
4896
4897 fn Charset(&self) -> DOMString {
4899 self.CharacterSet()
4900 }
4901
4902 fn InputEncoding(&self) -> DOMString {
4904 self.CharacterSet()
4905 }
4906
4907 fn ContentType(&self) -> DOMString {
4909 DOMString::from(self.content_type.to_string())
4910 }
4911
4912 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4914 self.upcast::<Node>().children().find_map(DomRoot::downcast)
4915 }
4916
4917 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4919 self.upcast::<Node>().child_elements().next()
4920 }
4921
4922 fn GetElementsByTagName(
4924 &self,
4925 qualified_name: DOMString,
4926 can_gc: CanGc,
4927 ) -> DomRoot<HTMLCollection> {
4928 let qualified_name = LocalName::from(qualified_name);
4929 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4930 return DomRoot::from_ref(entry);
4931 }
4932 let result = HTMLCollection::by_qualified_name(
4933 &self.window,
4934 self.upcast(),
4935 qualified_name.clone(),
4936 can_gc,
4937 );
4938 self.tag_map
4939 .borrow_mut()
4940 .insert(qualified_name, Dom::from_ref(&*result));
4941 result
4942 }
4943
4944 fn GetElementsByTagNameNS(
4946 &self,
4947 maybe_ns: Option<DOMString>,
4948 tag_name: DOMString,
4949 can_gc: CanGc,
4950 ) -> DomRoot<HTMLCollection> {
4951 let ns = namespace_from_domstring(maybe_ns);
4952 let local = LocalName::from(tag_name);
4953 let qname = QualName::new(None, ns, local);
4954 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4955 return DomRoot::from_ref(collection);
4956 }
4957 let result =
4958 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4959 self.tagns_map
4960 .borrow_mut()
4961 .insert(qname, Dom::from_ref(&*result));
4962 result
4963 }
4964
4965 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4967 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4968 .map(Atom::from)
4969 .collect();
4970 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4971 return DomRoot::from_ref(collection);
4972 }
4973 let result = HTMLCollection::by_atomic_class_name(
4974 &self.window,
4975 self.upcast(),
4976 class_atoms.clone(),
4977 can_gc,
4978 );
4979 self.classes_map
4980 .borrow_mut()
4981 .insert(class_atoms, Dom::from_ref(&*result));
4982 result
4983 }
4984
4985 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4987 self.get_element_by_id(&Atom::from(id))
4988 }
4989
4990 fn CreateElement(
4992 &self,
4993 cx: &mut js::context::JSContext,
4994 mut local_name: DOMString,
4995 options: StringOrElementCreationOptions,
4996 ) -> Fallible<DomRoot<Element>> {
4997 if !is_valid_element_local_name(&local_name.str()) {
5000 debug!("Not a valid element name");
5001 return Err(Error::InvalidCharacter(None));
5002 }
5003
5004 if self.is_html_document {
5005 local_name.make_ascii_lowercase();
5006 }
5007
5008 let ns = if self.is_html_document || self.is_xhtml_document() {
5009 ns!(html)
5010 } else {
5011 ns!()
5012 };
5013
5014 let name = QualName::new(None, ns, LocalName::from(local_name));
5015 let is = match options {
5016 StringOrElementCreationOptions::String(_) => None,
5017 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5018 options.is.as_ref().map(LocalName::from)
5019 },
5020 };
5021 Ok(Element::create(
5022 cx,
5023 name,
5024 is,
5025 self,
5026 ElementCreator::ScriptCreated,
5027 CustomElementCreationMode::Synchronous,
5028 None,
5029 ))
5030 }
5031
5032 fn CreateElementNS(
5034 &self,
5035 cx: &mut js::context::JSContext,
5036 namespace: Option<DOMString>,
5037 qualified_name: DOMString,
5038 options: StringOrElementCreationOptions,
5039 ) -> Fallible<DomRoot<Element>> {
5040 let context = domname::Context::Element;
5043 let (namespace, prefix, local_name) =
5044 domname::validate_and_extract(namespace, &qualified_name, context)?;
5045
5046 let name = QualName::new(prefix, namespace, local_name);
5049 let is = match options {
5050 StringOrElementCreationOptions::String(_) => None,
5051 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5052 options.is.as_ref().map(LocalName::from)
5053 },
5054 };
5055
5056 Ok(Element::create(
5058 cx,
5059 name,
5060 is,
5061 self,
5062 ElementCreator::ScriptCreated,
5063 CustomElementCreationMode::Synchronous,
5064 None,
5065 ))
5066 }
5067
5068 fn CreateAttribute(
5070 &self,
5071 cx: &mut js::context::JSContext,
5072 mut local_name: DOMString,
5073 ) -> Fallible<DomRoot<Attr>> {
5074 if !is_valid_attribute_local_name(&local_name.str()) {
5077 debug!("Not a valid attribute name");
5078 return Err(Error::InvalidCharacter(None));
5079 }
5080 if self.is_html_document {
5081 local_name.make_ascii_lowercase();
5082 }
5083 let name = LocalName::from(local_name);
5084 let value = AttrValue::String("".to_owned());
5085
5086 Ok(Attr::new(
5087 cx,
5088 self,
5089 name.clone(),
5090 value,
5091 name,
5092 ns!(),
5093 None,
5094 None,
5095 ))
5096 }
5097
5098 fn CreateAttributeNS(
5100 &self,
5101 cx: &mut js::context::JSContext,
5102 namespace: Option<DOMString>,
5103 qualified_name: DOMString,
5104 ) -> Fallible<DomRoot<Attr>> {
5105 let context = domname::Context::Attribute;
5108 let (namespace, prefix, local_name) =
5109 domname::validate_and_extract(namespace, &qualified_name, context)?;
5110 let value = AttrValue::String("".to_owned());
5111 let qualified_name = LocalName::from(qualified_name);
5112 Ok(Attr::new(
5113 cx,
5114 self,
5115 local_name,
5116 value,
5117 qualified_name,
5118 namespace,
5119 prefix,
5120 None,
5121 ))
5122 }
5123
5124 fn CreateDocumentFragment(&self, cx: &mut js::context::JSContext) -> DomRoot<DocumentFragment> {
5126 DocumentFragment::new(cx, self)
5127 }
5128
5129 fn CreateTextNode(&self, cx: &mut js::context::JSContext, data: DOMString) -> DomRoot<Text> {
5131 Text::new(cx, data, self)
5132 }
5133
5134 fn CreateCDATASection(
5136 &self,
5137 cx: &mut js::context::JSContext,
5138 data: DOMString,
5139 ) -> Fallible<DomRoot<CDATASection>> {
5140 if self.is_html_document {
5142 return Err(Error::NotSupported(None));
5143 }
5144
5145 if data.contains("]]>") {
5147 return Err(Error::InvalidCharacter(None));
5148 }
5149
5150 Ok(CDATASection::new(cx, data, self))
5152 }
5153
5154 fn CreateComment(&self, cx: &mut js::context::JSContext, data: DOMString) -> DomRoot<Comment> {
5156 Comment::new(cx, data, self, None)
5157 }
5158
5159 fn CreateProcessingInstruction(
5161 &self,
5162 cx: &mut js::context::JSContext,
5163 target: DOMString,
5164 data: DOMString,
5165 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5166 if !matches_name_production(&target.str()) {
5168 return Err(Error::InvalidCharacter(None));
5169 }
5170
5171 if data.contains("?>") {
5173 return Err(Error::InvalidCharacter(None));
5174 }
5175
5176 Ok(ProcessingInstruction::new(cx, target, data, self))
5178 }
5179
5180 fn ImportNode(
5182 &self,
5183 cx: &mut js::context::JSContext,
5184 node: &Node,
5185 options: BooleanOrImportNodeOptions,
5186 ) -> Fallible<DomRoot<Node>> {
5187 if node.is::<Document>() || node.is::<ShadowRoot>() {
5189 return Err(Error::NotSupported(None));
5190 }
5191 let (subtree, registry) = match options {
5193 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5196 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5198 let subtree = (!options.selfOnly).into();
5200 let registry = options.customElementRegistry;
5202 (subtree, registry)
5206 },
5207 };
5208 let registry = registry
5211 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5212
5213 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5216 }
5217
5218 fn AdoptNode(&self, cx: &mut js::context::JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5220 if node.is::<Document>() {
5222 return Err(Error::NotSupported(None));
5223 }
5224
5225 if node.is::<ShadowRoot>() {
5227 return Err(Error::HierarchyRequest(None));
5228 }
5229
5230 Node::adopt(cx, node, self);
5232
5233 Ok(DomRoot::from_ref(node))
5235 }
5236
5237 fn CreateEvent(
5239 &self,
5240 cx: &mut js::context::JSContext,
5241 mut interface: DOMString,
5242 ) -> Fallible<DomRoot<Event>> {
5243 interface.make_ascii_lowercase();
5244 match &*interface.str() {
5245 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5246 &self.window,
5247 CanGc::from_cx(cx),
5248 ))),
5249 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5250 CompositionEvent::new_uninitialized(&self.window, CanGc::from_cx(cx)),
5251 )),
5252 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5253 self.window.upcast(),
5254 CanGc::from_cx(cx),
5255 ))),
5256 "events" | "event" | "htmlevents" | "svgevents" => Ok(Event::new_uninitialized(
5259 self.window.upcast(),
5260 CanGc::from_cx(cx),
5261 )),
5262 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5263 &self.window,
5264 CanGc::from_cx(cx),
5265 ))),
5266 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5267 &self.window,
5268 CanGc::from_cx(cx),
5269 ))),
5270 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5271 cx,
5272 &self.window,
5273 ))),
5274 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5275 self.window.upcast(),
5276 CanGc::from_cx(cx),
5277 ))),
5278 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5279 cx,
5280 &self.window,
5281 ))),
5282 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5283 &self.window,
5284 "".into(),
5285 CanGc::from_cx(cx),
5286 ))),
5287 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5288 &self.window,
5289 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5290 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5291 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5292 CanGc::from_cx(cx),
5293 ))),
5294 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5295 &self.window,
5296 CanGc::from_cx(cx),
5297 ))),
5298 _ => Err(Error::NotSupported(None)),
5299 }
5300 }
5301
5302 fn LastModified(&self) -> DOMString {
5304 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5305 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5311 }))
5312 }
5313
5314 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5316 Range::new_with_doc(self, None, can_gc)
5317 }
5318
5319 fn CreateNodeIterator(
5321 &self,
5322 root: &Node,
5323 what_to_show: u32,
5324 filter: Option<Rc<NodeFilter>>,
5325 can_gc: CanGc,
5326 ) -> DomRoot<NodeIterator> {
5327 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5328 }
5329
5330 fn CreateTreeWalker(
5332 &self,
5333 root: &Node,
5334 what_to_show: u32,
5335 filter: Option<Rc<NodeFilter>>,
5336 ) -> DomRoot<TreeWalker> {
5337 TreeWalker::new(self, root, what_to_show, filter)
5338 }
5339
5340 fn Title(&self) -> DOMString {
5342 self.title().unwrap_or_else(|| DOMString::from(""))
5343 }
5344
5345 fn SetTitle(&self, cx: &mut js::context::JSContext, title: DOMString) {
5347 let root = match self.GetDocumentElement() {
5348 Some(root) => root,
5349 None => return,
5350 };
5351
5352 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5353 let elem = root
5354 .upcast::<Node>()
5355 .child_elements_unrooted(cx.no_gc())
5356 .find(|node| {
5357 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5358 });
5359 match elem {
5360 Some(elem) => UnrootedDom::upcast::<Node>(elem).as_rooted(),
5361 None => {
5362 let name = QualName::new(None, ns!(svg), local_name!("title"));
5363 let elem = Element::create(
5364 cx,
5365 name,
5366 None,
5367 self,
5368 ElementCreator::ScriptCreated,
5369 CustomElementCreationMode::Synchronous,
5370 None,
5371 );
5372 let parent = root.upcast::<Node>();
5373 let child = elem.upcast::<Node>();
5374 parent
5375 .InsertBefore(cx, child, parent.GetFirstChild().as_deref())
5376 .unwrap()
5377 },
5378 }
5379 } else if root.namespace() == &ns!(html) {
5380 let elem = root
5381 .upcast::<Node>()
5382 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
5383 .find(|node| node.is::<HTMLTitleElement>());
5384 match elem {
5385 Some(elem) => elem.as_rooted(),
5386 None => match self.GetHead() {
5387 Some(head) => {
5388 let name = QualName::new(None, ns!(html), local_name!("title"));
5389 let elem = Element::create(
5390 cx,
5391 name,
5392 None,
5393 self,
5394 ElementCreator::ScriptCreated,
5395 CustomElementCreationMode::Synchronous,
5396 None,
5397 );
5398 head.upcast::<Node>()
5399 .AppendChild(cx, elem.upcast())
5400 .unwrap()
5401 },
5402 None => return,
5403 },
5404 }
5405 } else {
5406 return;
5407 };
5408
5409 node.set_text_content_for_element(cx, Some(title));
5410 }
5411
5412 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5414 self.get_html_element()
5415 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5416 }
5417
5418 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5420 self.current_script.get()
5421 }
5422
5423 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5425 self.get_html_element().and_then(|root| {
5428 let node = root.upcast::<Node>();
5429 node.children()
5430 .find(|child| {
5431 matches!(
5432 child.type_id(),
5433 NodeTypeId::Element(ElementTypeId::HTMLElement(
5434 HTMLElementTypeId::HTMLBodyElement,
5435 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5436 HTMLElementTypeId::HTMLFrameSetElement,
5437 ))
5438 )
5439 })
5440 .map(|node| DomRoot::downcast(node).unwrap())
5441 })
5442 }
5443
5444 fn SetBody(
5446 &self,
5447 cx: &mut js::context::JSContext,
5448 new_body: Option<&HTMLElement>,
5449 ) -> ErrorResult {
5450 let new_body = match new_body {
5452 Some(new_body) => new_body,
5453 None => return Err(Error::HierarchyRequest(None)),
5454 };
5455
5456 let node = new_body.upcast::<Node>();
5457 match node.type_id() {
5458 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5459 NodeTypeId::Element(ElementTypeId::HTMLElement(
5460 HTMLElementTypeId::HTMLFrameSetElement,
5461 )) => {},
5462 _ => return Err(Error::HierarchyRequest(None)),
5463 }
5464
5465 let old_body = self.GetBody();
5467 if old_body.as_deref() == Some(new_body) {
5468 return Ok(());
5469 }
5470
5471 match (self.GetDocumentElement(), &old_body) {
5472 (Some(ref root), Some(child)) => {
5475 let root = root.upcast::<Node>();
5476 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
5477 .map(|_| ())
5478 },
5479
5480 (None, _) => Err(Error::HierarchyRequest(None)),
5482
5483 (Some(ref root), &None) => {
5486 let root = root.upcast::<Node>();
5487 root.AppendChild(cx, new_body.upcast()).map(|_| ())
5488 },
5489 }
5490 }
5491
5492 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5494 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5495 }
5496
5497 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5499 self.images.or_init(|| {
5500 HTMLCollection::new_with_filter_fn(
5501 &self.window,
5502 self.upcast(),
5503 |element, _| element.is::<HTMLImageElement>(),
5504 can_gc,
5505 )
5506 })
5507 }
5508
5509 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5511 self.embeds.or_init(|| {
5512 HTMLCollection::new_with_filter_fn(
5513 &self.window,
5514 self.upcast(),
5515 |element, _| element.is::<HTMLEmbedElement>(),
5516 can_gc,
5517 )
5518 })
5519 }
5520
5521 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5523 self.Embeds(can_gc)
5524 }
5525
5526 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5528 self.links.or_init(|| {
5529 HTMLCollection::new_with_filter_fn(
5530 &self.window,
5531 self.upcast(),
5532 |element, _| {
5533 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5534 element.has_attribute(&local_name!("href"))
5535 },
5536 can_gc,
5537 )
5538 })
5539 }
5540
5541 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5543 self.forms.or_init(|| {
5544 HTMLCollection::new_with_filter_fn(
5545 &self.window,
5546 self.upcast(),
5547 |element, _| element.is::<HTMLFormElement>(),
5548 can_gc,
5549 )
5550 })
5551 }
5552
5553 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5555 self.scripts.or_init(|| {
5556 HTMLCollection::new_with_filter_fn(
5557 &self.window,
5558 self.upcast(),
5559 |element, _| element.is::<HTMLScriptElement>(),
5560 can_gc,
5561 )
5562 })
5563 }
5564
5565 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5567 self.anchors.or_init(|| {
5568 HTMLCollection::new_with_filter_fn(
5569 &self.window,
5570 self.upcast(),
5571 |element, _| {
5572 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5573 },
5574 can_gc,
5575 )
5576 })
5577 }
5578
5579 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5581 self.applets
5582 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5583 }
5584
5585 fn GetLocation(&self, cx: &mut js::context::JSContext) -> Option<DomRoot<Location>> {
5587 if self.is_fully_active() {
5588 Some(self.window.Location(cx))
5589 } else {
5590 None
5591 }
5592 }
5593
5594 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5596 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5597 }
5598
5599 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5601 self.upcast::<Node>().child_elements().next()
5602 }
5603
5604 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5606 self.upcast::<Node>()
5607 .rev_children()
5608 .find_map(DomRoot::downcast)
5609 }
5610
5611 fn ChildElementCount(&self) -> u32 {
5613 self.upcast::<Node>().child_elements().count() as u32
5614 }
5615
5616 fn Prepend(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5618 self.upcast::<Node>().prepend(cx, nodes)
5619 }
5620
5621 fn Append(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5623 self.upcast::<Node>().append(cx, nodes)
5624 }
5625
5626 fn ReplaceChildren(
5628 &self,
5629 cx: &mut js::context::JSContext,
5630 nodes: Vec<NodeOrString>,
5631 ) -> ErrorResult {
5632 self.upcast::<Node>().replace_children(cx, nodes)
5633 }
5634
5635 fn MoveBefore(
5637 &self,
5638 cx: &mut js::context::JSContext,
5639 node: &Node,
5640 child: Option<&Node>,
5641 ) -> ErrorResult {
5642 self.upcast::<Node>().move_before(cx, node, child)
5643 }
5644
5645 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5647 self.upcast::<Node>().query_selector(selectors)
5648 }
5649
5650 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5652 self.upcast::<Node>().query_selector_all(selectors)
5653 }
5654
5655 fn ReadyState(&self) -> DocumentReadyState {
5657 self.ready_state.get()
5658 }
5659
5660 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5662 if self.has_browsing_context {
5663 Some(DomRoot::from_ref(&*self.window))
5664 } else {
5665 None
5666 }
5667 }
5668
5669 fn GetCookie(&self) -> Fallible<DOMString> {
5671 if self.is_cookie_averse() {
5672 return Ok(DOMString::new());
5673 }
5674
5675 if !self.origin().is_tuple() {
5676 return Err(Error::Security(None));
5677 }
5678
5679 let url = self.url();
5680 let (tx, rx) =
5681 profile_generic_channel::channel(self.global().time_profiler_chan().clone()).unwrap();
5682 let _ = self
5683 .window
5684 .as_global_scope()
5685 .resource_threads()
5686 .send(GetCookieStringForUrl(url, tx, NonHTTP));
5687 let cookies = rx.recv().unwrap();
5688 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5689 }
5690
5691 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5693 if self.is_cookie_averse() {
5694 return Ok(());
5695 }
5696
5697 if !self.origin().is_tuple() {
5698 return Err(Error::Security(None));
5699 }
5700
5701 if !cookie.is_valid_for_cookie() {
5702 return Ok(());
5703 }
5704
5705 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5706 vec![cookie]
5707 } else {
5708 vec![]
5709 };
5710
5711 let _ = self
5712 .window
5713 .as_global_scope()
5714 .resource_threads()
5715 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5716 Ok(())
5717 }
5718
5719 fn BgColor(&self) -> DOMString {
5721 self.get_body_attribute(&local_name!("bgcolor"))
5722 }
5723
5724 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5726 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5727 }
5728
5729 fn FgColor(&self) -> DOMString {
5731 self.get_body_attribute(&local_name!("text"))
5732 }
5733
5734 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5736 self.set_body_attribute(&local_name!("text"), value, can_gc)
5737 }
5738
5739 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5741 if name.is_empty() {
5742 return None;
5743 }
5744 let name = Atom::from(name);
5745
5746 let elements_with_name = self.get_elements_with_name(&name);
5749 let name_iter = elements_with_name
5750 .iter()
5751 .filter(|elem| is_named_element_with_name_attribute(elem));
5752 let elements_with_id = self.get_elements_with_id(&name);
5753 let id_iter = elements_with_id
5754 .iter()
5755 .filter(|elem| is_named_element_with_id_attribute(elem));
5756 let mut elements = name_iter.chain(id_iter);
5757
5758 let first = elements.next()?;
5765 if elements.all(|other| first == other) {
5766 if let Some(nested_window_proxy) = first
5767 .downcast::<HTMLIFrameElement>()
5768 .and_then(|iframe| iframe.GetContentWindow())
5769 {
5770 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5771 }
5772
5773 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5775 }
5776
5777 #[derive(JSTraceable, MallocSizeOf)]
5780 struct DocumentNamedGetter {
5781 #[no_trace]
5782 name: Atom,
5783 }
5784 impl CollectionFilter for DocumentNamedGetter {
5785 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5786 let type_ = match elem.upcast::<Node>().type_id() {
5787 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5788 _ => return false,
5789 };
5790 match type_ {
5791 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5792 elem.get_name().as_ref() == Some(&self.name)
5793 },
5794 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5795 name == *self.name ||
5796 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5797 }),
5798 _ => false,
5802 }
5803 }
5804 }
5805 let collection = HTMLCollection::create(
5806 self.window(),
5807 self.upcast(),
5808 Box::new(DocumentNamedGetter { name }),
5809 can_gc,
5810 );
5811 Some(NamedPropertyValue::HTMLCollection(collection))
5812 }
5813
5814 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5816 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5817
5818 let name_map = self.name_map.borrow();
5819 for (name, elements) in &(name_map).0 {
5820 if name.is_empty() {
5821 continue;
5822 }
5823 let mut name_iter = elements
5824 .iter()
5825 .filter(|elem| is_named_element_with_name_attribute(elem));
5826 if let Some(first) = name_iter.next() {
5827 names_with_first_named_element_map.insert(name, first);
5828 }
5829 }
5830 let id_map = self.id_map.borrow();
5831 for (id, elements) in &(id_map).0 {
5832 if id.is_empty() {
5833 continue;
5834 }
5835 let mut id_iter = elements
5836 .iter()
5837 .filter(|elem| is_named_element_with_id_attribute(elem));
5838 if let Some(first) = id_iter.next() {
5839 match names_with_first_named_element_map.entry(id) {
5840 Vacant(entry) => drop(entry.insert(first)),
5841 Occupied(mut entry) => {
5842 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5843 *entry.get_mut() = first;
5844 }
5845 },
5846 }
5847 }
5848 }
5849
5850 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5851 names_with_first_named_element_map
5852 .iter()
5853 .map(|(k, v)| (*k, *v))
5854 .collect();
5855 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5856 if a.1 == b.1 {
5857 a.0.cmp(b.0)
5860 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5861 Ordering::Less
5862 } else {
5863 Ordering::Greater
5864 }
5865 });
5866
5867 names_with_first_named_element_vec
5868 .iter()
5869 .map(|(k, _v)| DOMString::from(&***k))
5870 .collect()
5871 }
5872
5873 fn Clear(&self) {
5875 }
5877
5878 fn CaptureEvents(&self) {
5880 }
5882
5883 fn ReleaseEvents(&self) {
5885 }
5887
5888 global_event_handlers!();
5890
5891 event_handler!(
5893 readystatechange,
5894 GetOnreadystatechange,
5895 SetOnreadystatechange
5896 );
5897
5898 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5900 self.document_or_shadow_root.element_from_point(
5901 x,
5902 y,
5903 self.GetDocumentElement(),
5904 self.has_browsing_context,
5905 )
5906 }
5907
5908 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5910 self.document_or_shadow_root.elements_from_point(
5911 x,
5912 y,
5913 self.GetDocumentElement(),
5914 self.has_browsing_context,
5915 )
5916 }
5917
5918 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5920 if self.quirks_mode() == QuirksMode::Quirks {
5922 if let Some(ref body) = self.GetBody() {
5924 let e = body.upcast::<Element>();
5925 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5929 return Some(DomRoot::from_ref(e));
5930 }
5931 }
5932
5933 return None;
5935 }
5936
5937 self.GetDocumentElement()
5940 }
5941
5942 fn Open(
5944 &self,
5945 cx: &mut js::context::JSContext,
5946 _unused1: Option<DOMString>,
5947 _unused2: Option<DOMString>,
5948 ) -> Fallible<DomRoot<Document>> {
5949 if !self.is_html_document() {
5951 return Err(Error::InvalidState(None));
5952 }
5953
5954 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5956 return Err(Error::InvalidState(None));
5957 }
5958
5959 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5961
5962 if !self
5964 .origin()
5965 .same_origin(&entry_responsible_document.origin())
5966 {
5967 return Err(Error::Security(None));
5968 }
5969
5970 if self
5972 .get_current_parser()
5973 .is_some_and(|parser| parser.is_active())
5974 {
5975 return Ok(DomRoot::from_ref(self));
5976 }
5977
5978 if self.is_prompting_or_unloading() {
5980 return Ok(DomRoot::from_ref(self));
5981 }
5982
5983 if self.active_parser_was_aborted.get() {
5985 return Ok(DomRoot::from_ref(self));
5986 }
5987
5988 self.window().set_navigation_start();
5992
5993 if self.has_browsing_context() {
5996 self.abort(cx);
5999 }
6000
6001 for node in self
6003 .upcast::<Node>()
6004 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6005 {
6006 node.upcast::<EventTarget>().remove_all_listeners();
6007 }
6008
6009 if self.window.Document() == DomRoot::from_ref(self) {
6011 self.window.upcast::<EventTarget>().remove_all_listeners();
6012 }
6013
6014 Node::replace_all(cx, None, self.upcast::<Node>());
6016
6017 if self.is_fully_active() {
6024 let mut new_url = entry_responsible_document.url();
6026
6027 if entry_responsible_document != DomRoot::from_ref(self) {
6029 new_url.set_fragment(None);
6030 }
6031
6032 self.set_url(new_url);
6035 }
6036
6037 self.is_initial_about_blank.set(false);
6039
6040 self.set_quirks_mode(QuirksMode::NoQuirks);
6046
6047 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6053 *self.loader.borrow_mut() =
6054 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6055 ServoParser::parse_html_script_input(self, self.url());
6056
6057 self.ready_state.set(DocumentReadyState::Loading);
6063
6064 Ok(DomRoot::from_ref(self))
6066 }
6067
6068 fn Open_(
6070 &self,
6071 cx: &mut js::context::JSContext,
6072 url: USVString,
6073 target: DOMString,
6074 features: DOMString,
6075 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6076 self.browsing_context()
6077 .ok_or(Error::InvalidAccess(None))?
6078 .open(cx, url, target, features)
6079 }
6080
6081 fn Write(
6083 &self,
6084 cx: &mut js::context::JSContext,
6085 text: Vec<TrustedHTMLOrString>,
6086 ) -> ErrorResult {
6087 self.write(cx, text, false, "Document", "write")
6090 }
6091
6092 fn Writeln(
6094 &self,
6095 cx: &mut js::context::JSContext,
6096 text: Vec<TrustedHTMLOrString>,
6097 ) -> ErrorResult {
6098 self.write(cx, text, true, "Document", "writeln")
6101 }
6102
6103 fn Close(&self, cx: &mut js::context::JSContext) -> ErrorResult {
6105 if !self.is_html_document() {
6106 return Err(Error::InvalidState(None));
6108 }
6109
6110 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6113 return Err(Error::InvalidState(None));
6114 }
6115
6116 let parser = match self.get_current_parser() {
6118 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6119 _ => {
6120 return Ok(());
6121 },
6122 };
6123
6124 parser.close(cx);
6126
6127 Ok(())
6128 }
6129
6130 fn ExecCommand(
6132 &self,
6133 cx: &mut js::context::JSContext,
6134 command_id: DOMString,
6135 _show_ui: bool,
6136 value: TrustedHTMLOrString,
6137 ) -> Fallible<bool> {
6138 let value = if command_id == "insertHTML" {
6139 TrustedHTML::get_trusted_type_compliant_string(
6140 cx,
6141 self.window.as_global_scope(),
6142 value,
6143 "Document execCommand",
6144 )?
6145 } else {
6146 match value {
6147 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6148 TrustedHTMLOrString::String(value) => value,
6149 }
6150 };
6151
6152 Ok(self.exec_command_for_command_id(cx, command_id, value))
6153 }
6154
6155 fn QueryCommandEnabled(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6157 self.check_support_and_enabled(cx, &command_id).is_some()
6159 }
6160
6161 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6163 self.is_command_supported(command_id)
6167 }
6168
6169 fn QueryCommandIndeterm(&self, command_id: DOMString) -> bool {
6171 self.is_command_indeterminate(command_id)
6172 }
6173
6174 fn QueryCommandState(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6176 self.command_state_for_command(cx, command_id)
6177 }
6178
6179 fn QueryCommandValue(
6181 &self,
6182 cx: &mut js::context::JSContext,
6183 command_id: DOMString,
6184 ) -> DOMString {
6185 self.command_value_for_command(cx, command_id)
6186 }
6187
6188 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6190
6191 event_handler!(
6193 fullscreenchange,
6194 GetOnfullscreenchange,
6195 SetOnfullscreenchange
6196 );
6197
6198 fn FullscreenEnabled(&self) -> bool {
6200 self.get_allow_fullscreen()
6201 }
6202
6203 fn Fullscreen(&self) -> bool {
6205 self.fullscreen_element.get().is_some()
6206 }
6207
6208 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6210 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6211 }
6212
6213 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6215 self.exit_fullscreen(can_gc)
6216 }
6217
6218 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6222 match self.media_controls.borrow().get(&*id.str()) {
6223 Some(m) => Ok(DomRoot::from_ref(m)),
6224 None => Err(Error::InvalidAccess(None)),
6225 }
6226 }
6227
6228 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6230 if self.has_browsing_context {
6231 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6232 } else {
6233 None
6234 }
6235 }
6236
6237 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6239 self.fonts
6240 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6241 }
6242
6243 fn Hidden(&self) -> bool {
6245 self.visibility_state.get() == DocumentVisibilityState::Hidden
6246 }
6247
6248 fn VisibilityState(&self) -> DocumentVisibilityState {
6250 self.visibility_state.get()
6251 }
6252
6253 fn CreateExpression(
6254 &self,
6255 expression: DOMString,
6256 resolver: Option<Rc<XPathNSResolver>>,
6257 can_gc: CanGc,
6258 ) -> Fallible<DomRoot<crate::dom::types::XPathExpression>> {
6259 let parsed_expression =
6260 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6261 Ok(XPathExpression::new(
6262 &self.window,
6263 None,
6264 can_gc,
6265 parsed_expression,
6266 ))
6267 }
6268
6269 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6270 let global = self.global();
6271 let window = global.as_window();
6272 let evaluator = XPathEvaluator::new(window, None, can_gc);
6273 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6274 }
6275
6276 fn Evaluate(
6277 &self,
6278 expression: DOMString,
6279 context_node: &Node,
6280 resolver: Option<Rc<XPathNSResolver>>,
6281 result_type: u16,
6282 result: Option<&crate::dom::types::XPathResult>,
6283 can_gc: CanGc,
6284 ) -> Fallible<DomRoot<crate::dom::types::XPathResult>> {
6285 let parsed_expression =
6286 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6287 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6288 context_node,
6289 result_type,
6290 result,
6291 can_gc,
6292 )
6293 }
6294
6295 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6297 self.adopted_stylesheets_frozen_types.get_or_init(
6298 || {
6299 self.adopted_stylesheets
6300 .borrow()
6301 .clone()
6302 .iter()
6303 .map(|sheet| sheet.as_rooted())
6304 .collect()
6305 },
6306 context,
6307 retval,
6308 can_gc,
6309 );
6310 }
6311
6312 fn SetAdoptedStyleSheets(
6314 &self,
6315 context: JSContext,
6316 val: HandleValue,
6317 can_gc: CanGc,
6318 ) -> ErrorResult {
6319 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6320 context,
6321 self.adopted_stylesheets.borrow_mut().as_mut(),
6322 val,
6323 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6324 can_gc,
6325 );
6326
6327 if result.is_ok() {
6329 self.adopted_stylesheets_frozen_types.clear()
6330 }
6331
6332 result
6333 }
6334
6335 fn Timeline(&self) -> DomRoot<DocumentTimeline> {
6336 self.timeline.as_rooted()
6337 }
6338}
6339
6340fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6341 if marker.get().is_none() {
6342 marker.set(Some(CrossProcessInstant::now()))
6343 }
6344}
6345
6346#[derive(JSTraceable, MallocSizeOf)]
6347pub(crate) enum AnimationFrameCallback {
6348 DevtoolsFramerateTick {
6349 actor_name: String,
6350 },
6351 FrameRequestCallback {
6352 #[conditional_malloc_size_of]
6353 callback: Rc<FrameRequestCallback>,
6354 },
6355}
6356
6357impl AnimationFrameCallback {
6358 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6359 match *self {
6360 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6361 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6362 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6363 devtools_sender.send(msg).unwrap();
6364 },
6365 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6366 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6369 },
6370 }
6371 }
6372}
6373
6374#[derive(Default, JSTraceable, MallocSizeOf)]
6375#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6376struct PendingInOrderScriptVec {
6377 scripts: DomRefCell<VecDeque<PendingScript>>,
6378}
6379
6380impl PendingInOrderScriptVec {
6381 fn is_empty(&self) -> bool {
6382 self.scripts.borrow().is_empty()
6383 }
6384
6385 fn push(&self, element: &HTMLScriptElement) {
6386 self.scripts
6387 .borrow_mut()
6388 .push_back(PendingScript::new(element));
6389 }
6390
6391 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6392 let mut scripts = self.scripts.borrow_mut();
6393 let entry = scripts
6394 .iter_mut()
6395 .find(|entry| &*entry.element == element)
6396 .unwrap();
6397 entry.loaded(result);
6398 }
6399
6400 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6401 let mut scripts = self.scripts.borrow_mut();
6402 let pair = scripts.front_mut()?.take_result()?;
6403 scripts.pop_front();
6404 Some(pair)
6405 }
6406
6407 fn clear(&self) {
6408 *self.scripts.borrow_mut() = Default::default();
6409 }
6410}
6411
6412#[derive(JSTraceable, MallocSizeOf)]
6413#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6414struct PendingScript {
6415 element: Dom<HTMLScriptElement>,
6416 load: Option<ScriptResult>,
6418}
6419
6420impl PendingScript {
6421 fn new(element: &HTMLScriptElement) -> Self {
6422 Self {
6423 element: Dom::from_ref(element),
6424 load: None,
6425 }
6426 }
6427
6428 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6429 Self {
6430 element: Dom::from_ref(element),
6431 load,
6432 }
6433 }
6434
6435 fn loaded(&mut self, result: ScriptResult) {
6436 assert!(self.load.is_none());
6437 self.load = Some(result);
6438 }
6439
6440 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6441 self.load
6442 .take()
6443 .map(|result| (DomRoot::from_ref(&*self.element), result))
6444 }
6445}
6446
6447fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6448 let type_ = match elem.upcast::<Node>().type_id() {
6449 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6450 _ => return false,
6451 };
6452 match type_ {
6453 HTMLElementTypeId::HTMLFormElement |
6454 HTMLElementTypeId::HTMLIFrameElement |
6455 HTMLElementTypeId::HTMLImageElement => true,
6456 _ => false,
6460 }
6461}
6462
6463fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6464 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6468}
6469
6470impl DocumentHelpers for Document {
6471 fn ensure_safe_to_run_script_or_layout(&self) {
6472 Document::ensure_safe_to_run_script_or_layout(self)
6473 }
6474}
6475
6476pub(crate) struct SameoriginAncestorNavigablesIterator {
6480 document: DomRoot<Document>,
6481}
6482
6483impl SameoriginAncestorNavigablesIterator {
6484 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6485 Self { document }
6486 }
6487}
6488
6489impl Iterator for SameoriginAncestorNavigablesIterator {
6490 type Item = DomRoot<Document>;
6491
6492 fn next(&mut self) -> Option<Self::Item> {
6493 let window_proxy = self.document.browsing_context()?;
6494 self.document = window_proxy.parent()?.document()?;
6495 Some(self.document.clone())
6496 }
6497}
6498
6499pub(crate) struct SameOriginDescendantNavigablesIterator {
6504 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6505}
6506
6507impl SameOriginDescendantNavigablesIterator {
6508 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6509 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6510 Self {
6511 stack: vec![Box::new(iframes.into_iter())],
6512 }
6513 }
6514
6515 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6516 let mut cur_iframe = self.stack.last_mut()?.next();
6517 while cur_iframe.is_none() {
6518 self.stack.pop();
6519 cur_iframe = self.stack.last_mut()?.next();
6520 }
6521 cur_iframe
6522 }
6523}
6524
6525impl Iterator for SameOriginDescendantNavigablesIterator {
6526 type Item = DomRoot<Document>;
6527
6528 fn next(&mut self) -> Option<Self::Item> {
6529 while let Some(iframe) = self.get_next_iframe() {
6530 let Some(pipeline_id) = iframe.pipeline_id() else {
6531 continue;
6532 };
6533
6534 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6535 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6536 document.iframes().iter().collect();
6537 self.stack.push(Box::new(child_iframes.into_iter()));
6538 return Some(document);
6539 } else {
6540 continue;
6541 };
6542 }
6543 None
6544 }
6545}