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::{Arc as StdArc, 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 html5ever::{LocalName, Namespace, QualName, local_name, ns};
29use hyper_serde::Serde;
30use indexmap::IndexSet;
31use js::context::{JSContext, NoGC};
32use js::realm::CurrentRealm;
33use js::rust::{HandleObject, HandleValue, MutableHandleValue};
34use layout_api::{
35 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
36 ScrollContainerQueryFlags, TrustedNodeAddress,
37};
38use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
39use net_traits::CookieSource::NonHTTP;
40use net_traits::CoreResourceMsg::{GetCookieStringForUrl, SetCookiesForUrl};
41use net_traits::image_cache::ImageCache;
42use net_traits::policy_container::PolicyContainer;
43use net_traits::pub_domains::is_pub_domain;
44use net_traits::request::{
45 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
46};
47use net_traits::{ReferrerPolicy, ResourceFetchTiming};
48use percent_encoding::percent_decode;
49use profile_traits::generic_channel as profile_generic_channel;
50use profile_traits::time::TimerMetadataFrameType;
51use regex::bytes::Regex;
52use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
53use script_bindings::cell::{DomRefCell, Ref, RefMut};
54use script_bindings::interfaces::DocumentHelpers;
55use script_bindings::reflector::reflect_dom_object_with_proto_and_cx;
56use script_bindings::trace::CustomTraceable;
57use script_traits::{DocumentActivity, ProgressiveWebMetricType};
58use servo_arc::Arc;
59use servo_base::cross_process_instant::CrossProcessInstant;
60use servo_base::generic_channel::GenericSend;
61use servo_base::id::{PipelineId, WebViewId};
62use servo_base::{Epoch, generic_channel};
63use servo_config::pref;
64use servo_constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
65use servo_media::{ClientContextId, ServoMedia};
66use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
67use style::attr::AttrValue;
68use style::context::QuirksMode;
69use style::dom::OpaqueNode;
70use style::invalidation::element::restyle_hints::RestyleHint;
71use style::selector_parser::Snapshot;
72use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
73use style::str::{split_html_space_chars, str_join};
74use style::stylesheet_set::DocumentStylesheetSet;
75use style::stylesheets::{Origin, OriginSet, Stylesheet};
76use style::stylist::Stylist;
77use stylo_atoms::Atom;
78use time::Duration as TimeDuration;
79use url::{Host, Position};
80
81use crate::animations::Animations;
82use crate::document_loader::{DocumentLoader, LoadType};
83use crate::dom::FlatTreeParent;
84use crate::dom::animationtimeline::AnimationTimeline;
85use crate::dom::attr::Attr;
86use crate::dom::beforeunloadevent::BeforeUnloadEvent;
87use crate::dom::bindings::callback::ExceptionHandling;
88use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
89use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
90 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
91};
92use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
93use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
94use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
95#[cfg(any(feature = "webxr", feature = "gamepad"))]
96use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
97use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
98use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
99use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
100use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
101use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
102 SetHTMLOptions, SetHTMLUnsafeOptions,
103};
104use crate::dom::bindings::codegen::Bindings::WindowBinding::{
105 FrameRequestCallback, ScrollBehavior, WindowMethods,
106};
107use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
108use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
109use crate::dom::bindings::codegen::UnionTypes::{
110 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
111};
112use crate::dom::bindings::domname::{
113 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
114};
115use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
116use crate::dom::bindings::frozenarray::CachedFrozenArray;
117use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
118use crate::dom::bindings::num::Finite;
119use crate::dom::bindings::refcounted::Trusted;
120use crate::dom::bindings::reflector::DomGlobal;
121use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout, UnrootedDom};
122use crate::dom::bindings::str::{DOMString, USVString};
123use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
124use crate::dom::bindings::weakref::DOMTracker;
125use crate::dom::bindings::xmlname::matches_name_production;
126use crate::dom::cdatasection::CDATASection;
127use crate::dom::comment::Comment;
128use crate::dom::compositionevent::CompositionEvent;
129use crate::dom::css::cssstylesheet::CSSStyleSheet;
130use crate::dom::css::fontfaceset::FontFaceSet;
131use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
132use crate::dom::customelementregistry::{
133 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
134};
135use crate::dom::customevent::CustomEvent;
136use crate::dom::document::accessibility_data::AccessibilityData;
137use crate::dom::document::focus::{DocumentFocusHandler, FocusableArea};
138use crate::dom::document::tree_ordered_index_map::TreeOrderedIndexMap;
139use crate::dom::document_embedder_controls::DocumentEmbedderControls;
140use crate::dom::document_event_handler::DocumentEventHandler;
141use crate::dom::documentfragment::DocumentFragment;
142use crate::dom::documentorshadowroot::{
143 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
144};
145use crate::dom::documenttimeline::DocumentTimeline;
146use crate::dom::documenttype::DocumentType;
147use crate::dom::domimplementation::DOMImplementation;
148use crate::dom::element::attributes::storage::AttrRef;
149use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
150use crate::dom::event::{Event, EventBubbles, EventCancelable};
151use crate::dom::eventtarget::EventTarget;
152use crate::dom::execcommand::basecommand::{CommandName, DefaultSingleLineContainerName};
153use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
154use crate::dom::focusevent::FocusEvent;
155use crate::dom::globalscope::GlobalScope;
156use crate::dom::hashchangeevent::HashChangeEvent;
157use crate::dom::history::History;
158use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
159use crate::dom::html::htmlareaelement::HTMLAreaElement;
160use crate::dom::html::htmlbaseelement::HTMLBaseElement;
161use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
162use crate::dom::html::htmlelement::HTMLElement;
163use crate::dom::html::htmlembedelement::HTMLEmbedElement;
164use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
165use crate::dom::html::htmlheadelement::HTMLHeadElement;
166use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
167use crate::dom::html::htmliframeelement::HTMLIFrameElement;
168use crate::dom::html::htmlimageelement::HTMLImageElement;
169use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
170use crate::dom::html::htmltitleelement::HTMLTitleElement;
171use crate::dom::htmldetailselement::DetailsNameGroups;
172use crate::dom::intersectionobserver::IntersectionObserver;
173use crate::dom::iterators::ShadowIncluding;
174use crate::dom::keyboardevent::KeyboardEvent;
175use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
176use crate::dom::location::Location;
177use crate::dom::messageevent::MessageEvent;
178use crate::dom::mouseevent::MouseEvent;
179use crate::dom::node::treewalker::TreeWalker;
180use crate::dom::node::virtualmethods::vtable_for;
181use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits};
182use crate::dom::nodeiterator::NodeIterator;
183use crate::dom::nodelist::NodeList;
184use crate::dom::pagetransitionevent::PageTransitionEvent;
185use crate::dom::performance::performanceentry::PerformanceEntry;
186use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
187use crate::dom::processinginstruction::ProcessingInstruction;
188use crate::dom::promise::Promise;
189use crate::dom::range::Range;
190use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
191use crate::dom::sanitizer::Sanitizer;
192use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
193use crate::dom::selection::Selection;
194use crate::dom::servoparser::ServoParser;
195use crate::dom::shadowroot::ShadowRoot;
196use crate::dom::storageevent::StorageEvent;
197use crate::dom::text::Text;
198use crate::dom::touchevent::TouchEvent as DomTouchEvent;
199use crate::dom::touchlist::TouchList;
200use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
201use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
202use crate::dom::uievent::UIEvent;
203use crate::dom::websocket::WebSocket;
204use crate::dom::window::Window;
205use crate::dom::windowproxy::WindowProxy;
206use crate::dom::xpathevaluator::XPathEvaluator;
207use crate::dom::xpathexpression::XPathExpression;
208use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
209use crate::iframe_collection::IFrameCollection;
210use crate::image_animation::ImageAnimationManager;
211use crate::mime::{APPLICATION, CHARSET};
212use crate::navigation::navigate;
213use crate::network_listener::{FetchResponseListener, NetworkListener};
214use crate::script_thread::{ScriptThread, SharedRwLocks};
215use crate::stylesheet_loader::StylesheetContextId;
216use crate::stylesheet_set::StylesheetSetRef;
217use crate::task::NonSendTaskBox;
218use crate::task_manager::TaskManager;
219use crate::task_source::TaskSourceName;
220use crate::timers::{OneshotTimerCallback, OneshotTimers};
221use crate::xpath::parse_expression;
222
223#[derive(Clone, Copy, PartialEq)]
224pub(crate) enum FireMouseEventType {
225 Move,
226 Over,
227 Out,
228 Enter,
229 Leave,
230}
231
232impl FireMouseEventType {
233 pub(crate) fn as_str(&self) -> &str {
234 match *self {
235 FireMouseEventType::Move => "mousemove",
236 FireMouseEventType::Over => "mouseover",
237 FireMouseEventType::Out => "mouseout",
238 FireMouseEventType::Enter => "mouseenter",
239 FireMouseEventType::Leave => "mouseleave",
240 }
241 }
242}
243
244#[derive(JSTraceable, MallocSizeOf)]
245pub(crate) struct RefreshRedirectDue {
246 #[no_trace]
247 pub(crate) url: ServoUrl,
248 #[ignore_malloc_size_of = "non-owning"]
249 pub(crate) window: DomRoot<Window>,
250 pub(crate) from_meta_element: bool,
252}
253impl RefreshRedirectDue {
254 pub(crate) fn invoke(self, cx: &mut JSContext) {
256 if self.from_meta_element &&
263 self.window.Document().has_active_sandboxing_flag(
264 SandboxingFlagSet::SANDBOXED_AUTOMATIC_FEATURES_BROWSING_CONTEXT_FLAG,
265 )
266 {
267 return;
268 }
269 let load_data = self
270 .window
271 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
272 navigate(
273 cx,
274 &self.window,
275 NavigationHistoryBehavior::Replace,
276 false,
277 load_data,
278 );
279 }
280}
281
282#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
283pub(crate) enum IsHTMLDocument {
284 HTMLDocument,
285 NonHTMLDocument,
286}
287
288#[derive(Clone, Copy, Default, MallocSizeOf, PartialEq)]
289pub(crate) enum TheEndLoadingPhase {
290 #[default]
291 Initial,
292 ProcessingDeferredScripts,
293 ProcessingAsSoonAsPossibleScripts,
294 WaitingForLoadEventBlockers,
295 Done,
296}
297
298#[derive(JSTraceable, MallocSizeOf)]
300pub(crate) enum DeclarativeRefresh {
301 PendingLoad {
302 #[no_trace]
303 url: ServoUrl,
304 time: u64,
305 from_meta_element: bool,
307 },
308 CreatedAfterLoad,
309}
310
311#[derive(JSTraceable, MallocSizeOf, PartialEq)]
312#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
313struct PendingScrollEvent {
314 target: Dom<EventTarget>,
316 #[no_trace]
318 event: Atom,
319}
320
321impl PendingScrollEvent {
322 fn equivalent(&self, target: &EventTarget, event: &Atom) -> bool {
323 &*self.target == target && self.event == *event
324 }
325}
326
327#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
330pub(crate) struct RenderingUpdateReason(u8);
331
332bitflags! {
333 impl RenderingUpdateReason: u8 {
334 const ResizeObserverStartedObservingTarget = 1 << 0;
337 const IntersectionObserverStartedObservingTarget = 1 << 1;
340 const FontReadyPromiseFulfilled = 1 << 2;
344 }
345}
346
347#[derive(Clone, Debug, Default, MallocSizeOf)]
349pub(crate) struct NavigationTiming {
350 pub(crate) unload_event_start: Cell<Option<CrossProcessInstant>>,
352 pub(crate) unload_event_end: Cell<Option<CrossProcessInstant>>,
354 pub(crate) dom_interactive: Cell<Option<CrossProcessInstant>>,
356 pub(crate) dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
358 pub(crate) dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
360 pub(crate) dom_complete: Cell<Option<CrossProcessInstant>>,
362 pub(crate) load_event_start: Cell<Option<CrossProcessInstant>>,
364 pub(crate) load_event_end: Cell<Option<CrossProcessInstant>>,
366 pub(crate) top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
368}
369
370#[dom_struct]
372pub(crate) struct Document {
373 node: Node,
374 document_or_shadow_root: DocumentOrShadowRoot,
375 window: Dom<Window>,
376 implementation: MutNullableDom<DOMImplementation>,
377 #[ignore_malloc_size_of = "type from external crate"]
378 #[no_trace]
379 content_type: Mime,
380 last_modified: Option<String>,
381 #[no_trace]
382 encoding: Cell<&'static Encoding>,
383 has_browsing_context: bool,
384 is_html_document: bool,
385 #[no_trace]
386 activity: Cell<DocumentActivity>,
387 #[no_trace]
389 url: DomRefCell<ServoUrl>,
390 #[no_trace]
392 about_base_url: DomRefCell<Option<ServoUrl>>,
393 #[ignore_malloc_size_of = "defined in selectors"]
394 #[no_trace]
395 quirks_mode: Cell<QuirksMode>,
396 event_handler: DocumentEventHandler,
398 focus_handler: DocumentFocusHandler,
400 embedder_controls: DocumentEmbedderControls,
402 id_map: TreeOrderedIndexMap,
403 name_map: TreeOrderedIndexMap,
404 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
405 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
406 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
407 images: MutNullableDom<HTMLCollection>,
408 embeds: MutNullableDom<HTMLCollection>,
409 links: MutNullableDom<HTMLCollection>,
410 forms: MutNullableDom<HTMLCollection>,
411 scripts: MutNullableDom<HTMLCollection>,
412 anchors: MutNullableDom<HTMLCollection>,
413 applets: MutNullableDom<HTMLCollection>,
414 iframes: RefCell<IFrameCollection>,
416 #[no_trace]
420 shared_style_locks: SharedRwLocks,
421 #[custom_trace]
423 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
424 stylesheet_list: MutNullableDom<StyleSheetList>,
425 ready_state: Cell<DocumentReadyState>,
426 domcontentloaded_dispatched: Cell<bool>,
429 current_script: MutNullableDom<HTMLScriptElement>,
431 #[no_trace]
432 current_the_end_loading_phase: Cell<TheEndLoadingPhase>,
433 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
435 script_blocking_stylesheet_set: DomRefCell<IndexSet<StylesheetContextId>>,
438 render_blocking_element_count: Cell<u32>,
441 deferred_scripts: PendingInOrderScriptVec,
443 asap_in_order_scripts_list: PendingInOrderScriptVec,
445 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
447 animation_frame_ident: Cell<u32>,
450 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
453 running_animation_callbacks: Cell<bool>,
458 loader: DomRefCell<DocumentLoader>,
460 current_parser: MutNullableDom<ServoParser>,
462 base_element: MutNullableDom<HTMLBaseElement>,
464 target_base_element: MutNullableDom<HTMLBaseElement>,
466 appropriate_template_contents_owner_document: MutNullableDom<Document>,
469 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
472 #[no_trace]
476 needs_restyle: Cell<RestyleReason>,
477 #[no_trace]
479 origin: DomRefCell<MutableOrigin>,
480 referrer: Option<String>,
482 target_element: MutNullableDom<Element>,
484 #[no_trace]
486 policy_container: DomRefCell<PolicyContainer>,
487 #[no_trace]
489 preloaded_resources: DomRefCell<PreloadedResources>,
490 ignore_destructive_writes_counter: Cell<u32>,
492 ignore_opens_during_unload_counter: Cell<u32>,
494 spurious_animation_frames: Cell<u8>,
498
499 fullscreen_element: MutNullableDom<Element>,
501 form_id_listener_map:
508 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
509 #[no_trace]
510 interactive_time: DomRefCell<ProgressiveWebMetrics>,
511 #[no_trace]
512 tti_window: DomRefCell<InteractiveWindow>,
513 canceller: FetchCanceller,
515 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
517 page_showing: Cell<bool>,
519 salvageable: Cell<bool>,
521 active_parser_was_aborted: Cell<bool>,
523 fired_unload: Cell<bool>,
525 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
527
528 #[no_trace]
530 navigation_timing: NavigationTiming,
531
532 #[no_trace]
534 resource_fetch_timing: RefCell<Option<ResourceFetchTiming>>,
535
536 script_and_layout_blockers: Cell<u32>,
538 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
540 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
541 completely_loaded: Cell<bool>,
543 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
545 shadow_roots_styles_changed: Cell<bool>,
547 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
553 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
556 has_pending_animated_image_update: Cell<bool>,
558 selection: MutNullableDom<Selection>,
560 timeline: Dom<DocumentTimeline>,
563 animations: Animations,
565 image_animation_manager: DomRefCell<ImageAnimationManager>,
567 dirty_root: MutNullableDom<Element>,
569 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
571 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
580 fonts: MutNullableDom<FontFaceSet>,
583 visibility_state: Cell<DocumentVisibilityState>,
585 status_code: Option<u16>,
587 is_initial_about_blank: Cell<bool>,
589 allow_declarative_shadow_roots: Cell<bool>,
591 #[no_trace]
593 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
594 has_trustworthy_ancestor_origin: Cell<bool>,
596 intersection_observer_task_queued: Cell<bool>,
598 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
610 highlighted_dom_node: MutNullableDom<Node>,
612 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
615 #[ignore_malloc_size_of = "mozjs"]
617 adopted_stylesheets_frozen_types: CachedFrozenArray,
618 pending_scroll_events: DomRefCell<Vec<PendingScrollEvent>>,
622 rendering_update_reasons: Cell<RenderingUpdateReason>,
624 waiting_on_canvas_image_updates: Cell<bool>,
628 root_removal_noted: Cell<bool>,
630 #[no_trace]
638 current_rendering_epoch: Cell<Epoch>,
639 #[conditional_malloc_size_of]
641 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
642 #[no_trace]
643 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
645 #[no_trace]
646 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
653 #[no_trace]
655 favicon: RefCell<Option<Image>>,
656
657 websockets: DOMTracker<WebSocket>,
659
660 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
662
663 #[no_trace]
665 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
666
667 layout_animations_test_enabled: bool,
669
670 #[no_trace]
672 state_override: DomRefCell<FxHashMap<CommandName, bool>>,
673
674 #[no_trace]
676 value_override: DomRefCell<FxHashMap<CommandName, DOMString>>,
677
678 #[no_trace]
680 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
681
682 css_styling_flag: Cell<bool>,
684
685 accessibility_data: DomRefCell<AccessibilityData>,
687
688 iframe_load_in_progress: Cell<bool>,
690 mute_iframe_load: Cell<bool>,
692
693 timers: OneshotTimers,
696
697 #[no_trace]
698 pipeline_id: PipelineId,
699
700 #[conditional_malloc_size_of]
702 task_manager: Rc<TaskManager>,
703
704 #[ignore_malloc_size_of = "ImageCache"]
705 #[no_trace]
706 image_cache: StdArc<dyn ImageCache>,
707
708 history: MutNullableDom<History>,
710}
711
712impl Document {
713 pub(crate) fn history(&self, cx: &mut JSContext) -> DomRoot<History> {
714 self.history.or_init(|| History::new(cx, &self.window))
715 }
716
717 pub(crate) fn image_cache(&self) -> StdArc<dyn ImageCache> {
718 self.image_cache.clone()
719 }
720
721 pub(crate) fn task_manager(&self) -> Rc<TaskManager> {
722 self.task_manager.clone()
723 }
724
725 pub(crate) fn timers(&self) -> &OneshotTimers {
726 &self.timers
727 }
728
729 pub(crate) fn pipeline_id(&self) -> PipelineId {
730 self.pipeline_id
731 }
732
733 fn unloading_cleanup_steps(&self) {
735 if self.close_outstanding_websockets() {
738 self.salvageable.set(false);
740 }
741
742 if !self.salvageable.get() {
747 let global_scope = self.window.as_global_scope();
748
749 global_scope.close_event_sources();
751
752 let msg = ScriptToConstellationMessage::DiscardDocument;
757 let _ = global_scope.script_to_constellation_chan().send(msg);
758 }
759 }
760
761 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
762 self.websockets.track(websocket);
763 }
764
765 fn close_outstanding_websockets(&self) -> bool {
766 let mut closed_any_websocket = false;
767 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
768 if websocket.make_disappear() {
769 closed_any_websocket = true;
770 }
771 });
772 closed_any_websocket
773 }
774
775 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
776 debug_assert!(*node.owner_doc() == *self);
777 if !node.is_connected() {
778 return;
779 }
780
781 let parent = match node.parent_in_flat_tree() {
782 FlatTreeParent::Parent(parent) => parent,
783 FlatTreeParent::NotInFlatTree => return,
784 FlatTreeParent::RootNode => {
785 let Some(document_element) = self.GetDocumentElement() else {
788 if !self.root_removal_noted.get() {
790 self.add_restyle_reason(RestyleReason::DOMChanged);
791 self.root_removal_noted.set(true);
792 }
793 return;
794 };
795 self.root_removal_noted.set(false);
798
799 if let Some(dirty_root) = self.dirty_root.get() &&
800 dirty_root.is_connected()
801 {
802 for ancestor in dirty_root
805 .upcast::<Node>()
806 .inclusive_ancestors_in_flat_tree()
807 {
808 if ancestor.is::<Element>() {
809 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
810 }
811 }
812 }
813 self.dirty_root.set(Some(&document_element));
814 return;
815 },
816 };
817
818 if let Some(parent_element) = parent.downcast::<Element>() {
819 if !parent_element.is_styled() {
820 return;
821 }
822 if parent_element.is_display_none() {
823 return;
824 }
825 }
826
827 let element_parent: DomRoot<Element>;
828 let element = match node.downcast::<Element>() {
829 Some(element) => element,
830 None => {
831 match DomRoot::downcast::<Element>(parent) {
834 Some(parent) => {
835 element_parent = parent;
836 &element_parent
837 },
838 None => {
839 return;
843 },
844 }
845 },
846 };
847
848 let dirty_root = match self.dirty_root.get() {
849 Some(root) if root.is_connected() => root,
850 _ => {
851 element
852 .upcast::<Node>()
853 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
854 self.dirty_root.set(Some(element));
855 return;
856 },
857 };
858
859 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
860 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
861 return;
862 }
863
864 if ancestor.is::<Element>() {
865 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
866 }
867 }
868
869 let new_dirty_root = element
873 .upcast::<Node>()
874 .common_ancestor_in_flat_tree(dirty_root.upcast())
875 .unwrap_or_else(|| DomRoot::from_ref(element.upcast()));
876
877 let mut has_dirty_descendants = true;
878 for ancestor in dirty_root
879 .upcast::<Node>()
880 .inclusive_ancestors_in_flat_tree()
881 {
882 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
883 has_dirty_descendants &= *ancestor != *new_dirty_root;
884 }
885
886 self.dirty_root
887 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
888 }
889
890 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
891 self.dirty_root.take()
892 }
893
894 #[inline]
895 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
896 self.loader.borrow()
897 }
898
899 #[inline]
900 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
901 self.loader.borrow_mut()
902 }
903
904 #[inline]
905 pub(crate) fn has_browsing_context(&self) -> bool {
906 self.has_browsing_context
907 }
908
909 #[inline]
911 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
912 if self.has_browsing_context {
913 self.window.undiscarded_window_proxy()
914 } else {
915 None
916 }
917 }
918
919 pub(crate) fn webview_id(&self) -> WebViewId {
920 self.window.webview_id()
921 }
922
923 #[inline]
924 pub(crate) fn window(&self) -> &Window {
925 &self.window
926 }
927
928 #[inline]
929 pub(crate) fn is_html_document(&self) -> bool {
930 self.is_html_document
931 }
932
933 pub(crate) fn is_xhtml_document(&self) -> bool {
934 self.content_type.matches(APPLICATION, "xhtml+xml")
935 }
936
937 pub(crate) fn is_fully_active(&self) -> bool {
938 self.activity.get() == DocumentActivity::FullyActive
939 }
940
941 pub(crate) fn is_active(&self) -> bool {
942 self.activity.get() != DocumentActivity::Inactive
943 }
944
945 #[inline]
946 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
947 self.current_rendering_epoch.get()
948 }
949
950 pub(crate) fn set_activity(&self, cx: &mut JSContext, activity: DocumentActivity) {
951 assert!(self.has_browsing_context);
953 if activity == self.activity.get() {
954 return;
955 }
956
957 self.activity.set(activity);
959 let media = ServoMedia::get();
960 let pipeline_id = self.window().pipeline_id();
961 let client_context_id =
962 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
963
964 if activity != DocumentActivity::FullyActive {
965 self.window().suspend(cx);
966 media.suspend(&client_context_id);
967 return;
968 }
969
970 self.title_changed();
971 self.notify_embedder_favicon();
972 self.dirty_all_nodes();
973 self.window().resume(cx);
974 media.resume(&client_context_id);
975
976 if self.ready_state.get() != DocumentReadyState::Complete {
977 return;
978 }
979
980 let document = Trusted::new(self);
984 self.owner_global()
985 .task_manager()
986 .dom_manipulation_task_source()
987 .queue(task!(fire_pageshow_event: move |cx| {
988 let document = document.root();
989 let window = document.window();
990 if document.page_showing.get() {
992 return;
993 }
994 document.page_showing.set(true);
996 document.update_visibility_state(cx, DocumentVisibilityState::Visible);
998 let event = PageTransitionEvent::new(
1001 cx,
1002 window,
1003 atom!("pageshow"),
1004 false, false, true, );
1008 let event = event.upcast::<Event>();
1009 event.set_trusted(true);
1010 window.dispatch_event_with_target_override(cx, event);
1011 }))
1012 }
1013
1014 pub(crate) fn origin(&self) -> Ref<'_, MutableOrigin> {
1015 self.origin.borrow()
1016 }
1017
1018 pub(crate) fn mark_as_internal(&self) {
1021 *self.origin.borrow_mut() = MutableOrigin::new(ImmutableOrigin::new_opaque());
1022 }
1023
1024 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
1025 *self.protocol_handler_automation_mode.borrow_mut() = mode;
1026 }
1027
1028 pub(crate) fn url(&self) -> ServoUrl {
1030 self.url.borrow().clone()
1031 }
1032
1033 pub(crate) fn set_url(&self, url: ServoUrl) {
1034 *self.url.borrow_mut() = url;
1035 }
1036
1037 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
1038 self.about_base_url.borrow().clone()
1039 }
1040
1041 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
1042 *self.about_base_url.borrow_mut() = about_base_url;
1043 }
1044
1045 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
1047 let document_url = self.url();
1048 if document_url.as_str() == "about:srcdoc" {
1050 return self
1053 .about_base_url()
1054 .expect("about:srcdoc page should always have an about base URL");
1055 }
1056
1057 if document_url.matches_about_blank() &&
1060 let Some(about_base_url) = self.about_base_url()
1061 {
1062 return about_base_url;
1063 }
1064
1065 document_url
1067 }
1068
1069 pub(crate) fn base_url(&self) -> ServoUrl {
1071 match self.base_element() {
1072 None => self.fallback_base_url(),
1074 Some(base) => base.frozen_base_url(),
1076 }
1077 }
1078
1079 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
1080 self.needs_restyle.set(self.needs_restyle.get() | reason)
1081 }
1082
1083 pub(crate) fn clear_restyle_reasons(&self) {
1084 self.needs_restyle.set(RestyleReason::empty());
1085 }
1086
1087 pub(crate) fn stylesheets_changed_since_last_reflow(&self) -> bool {
1088 self.stylesheets.borrow().has_changed()
1089 }
1090
1091 pub(crate) fn restyle_reason(&self) -> RestyleReason {
1092 let mut condition = self.needs_restyle.get();
1093 if self.stylesheets_changed_since_last_reflow() {
1094 condition.insert(RestyleReason::StylesheetsChanged);
1095 }
1096
1097 if let Some(root) = self.GetDocumentElement() &&
1101 root.upcast::<Node>().has_dirty_descendants()
1102 {
1103 condition.insert(RestyleReason::DOMChanged);
1104 }
1105
1106 if !self.pending_restyles.borrow().is_empty() {
1107 condition.insert(RestyleReason::PendingRestyles);
1108 }
1109
1110 condition
1111 }
1112
1113 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1115 self.base_element.get()
1116 }
1117
1118 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1120 self.target_base_element.get()
1121 }
1122
1123 pub(crate) fn refresh_base_element(&self, cx: &mut JSContext) {
1125 if let Some(base_element) = self.base_element.get() {
1126 base_element.clear_frozen_base_url();
1127 }
1128 let new_base_element = self
1129 .upcast::<Node>()
1130 .traverse_preorder(ShadowIncluding::No)
1131 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1132 .find(|element| {
1133 element
1134 .upcast::<Element>()
1135 .has_attribute(&local_name!("href"))
1136 });
1137 if let Some(ref new_base_element) = new_base_element {
1138 new_base_element.set_frozen_base_url(cx);
1139 }
1140 self.base_element.set(new_base_element.as_deref());
1141
1142 let new_target_base_element = self
1143 .upcast::<Node>()
1144 .traverse_preorder(ShadowIncluding::No)
1145 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1146 .next();
1147 self.target_base_element
1148 .set(new_target_base_element.as_deref());
1149 }
1150
1151 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1152 self.quirks_mode.get()
1153 }
1154
1155 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1156 let old_mode = self.quirks_mode.replace(new_mode);
1157
1158 if old_mode != new_mode {
1159 self.window.layout_mut().set_quirks_mode(new_mode);
1160 }
1161 }
1162
1163 pub(crate) fn encoding(&self) -> &'static Encoding {
1164 self.encoding.get()
1165 }
1166
1167 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1168 self.encoding.set(encoding);
1169 }
1170
1171 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1172 if node.is_connected() {
1173 node.note_dirty_descendants();
1174 }
1175
1176 node.dirty(NodeDamage::ContentOrHeritage);
1179 }
1180
1181 pub(crate) fn unregister_element_id(&self, cx: &mut JSContext, id: &Atom) {
1183 self.id_map.remove(id);
1184 self.reset_form_owner_for_listeners(cx, id);
1185 }
1186
1187 pub(crate) fn register_element_id(&self, cx: &mut JSContext, element: &Element, id: &Atom) {
1189 self.id_map.add(id, element);
1190 self.reset_form_owner_for_listeners(cx, id);
1191 }
1192
1193 pub(crate) fn unregister_element_name(&self, name: &Atom) {
1195 self.name_map.remove(name);
1196 }
1197
1198 pub(crate) fn register_element_name(&self, element: &Element, name: &Atom) {
1200 self.name_map.add(name, element);
1201 }
1202
1203 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1204 &self,
1205 id: DOMString,
1206 listener: &T,
1207 ) {
1208 let mut map = self.form_id_listener_map.borrow_mut();
1209 let listener = listener.to_element();
1210 let set = map.entry(Atom::from(id)).or_default();
1211 set.insert(Dom::from_ref(listener));
1212 }
1213
1214 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1215 &self,
1216 id: DOMString,
1217 listener: &T,
1218 ) {
1219 let mut map = self.form_id_listener_map.borrow_mut();
1220 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1221 entry
1222 .get_mut()
1223 .remove(&Dom::from_ref(listener.to_element()));
1224 if entry.get().is_empty() {
1225 entry.remove();
1226 }
1227 }
1228 }
1229
1230 fn find_a_potential_indicated_element(
1232 &self,
1233 cx: &mut JSContext,
1234 fragment: &str,
1235 ) -> Option<DomRoot<Element>> {
1236 self.get_element_by_id(cx.no_gc(), &Atom::from(fragment))
1240 .or_else(|| self.get_anchor_by_name(cx, fragment))
1244 }
1245
1246 fn select_indicated_part(&self, cx: &mut JSContext, fragment: &str) -> Option<DomRoot<Node>> {
1249 if fragment.is_empty() {
1259 return Some(DomRoot::from_ref(self.upcast()));
1260 }
1261 if let Some(potential_indicated_element) =
1263 self.find_a_potential_indicated_element(cx, fragment)
1264 {
1265 return Some(DomRoot::upcast(potential_indicated_element));
1267 }
1268 let fragment_bytes = percent_decode(fragment.as_bytes());
1270 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1272 return None;
1273 };
1274 if let Some(potential_indicated_element) =
1276 self.find_a_potential_indicated_element(cx, &decoded_fragment)
1277 {
1278 return Some(DomRoot::upcast(potential_indicated_element));
1280 }
1281 if decoded_fragment.eq_ignore_ascii_case("top") {
1283 return Some(DomRoot::from_ref(self.upcast()));
1284 }
1285 None
1287 }
1288
1289 pub(crate) fn scroll_to_the_fragment(&self, cx: &mut JSContext, fragment: &str) {
1291 let Some(indicated_part) = self.select_indicated_part(cx, fragment) else {
1296 self.set_target_element(None);
1297 return;
1298 };
1299 if *indicated_part == *self.upcast() {
1301 self.set_target_element(None);
1303 self.window.scroll(cx, 0.0, 0.0, ScrollBehavior::Instant);
1308 return;
1310 }
1311 let Some(target) = indicated_part.downcast::<Element>() else {
1314 unreachable!("Indicated part should always be an element");
1316 };
1317 self.set_target_element(Some(target));
1319 target.scroll_into_view_with_options(
1323 cx,
1324 ScrollBehavior::Auto,
1325 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1326 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1327 None,
1328 None,
1329 );
1330
1331 indicated_part.run_the_focusing_steps(cx, Some(FocusableArea::Viewport));
1334
1335 self.focus_handler()
1337 .set_sequential_focus_navigation_starting_point(target.upcast());
1338 }
1339
1340 fn get_anchor_by_name(&self, cx: &mut JSContext, name: &str) -> Option<DomRoot<Element>> {
1341 let document_element = self.GetDocumentElement()?;
1342 self.name_map
1343 .get_all(cx.no_gc(), document_element.upcast(), &Atom::from(name))
1344 .iter()
1345 .find(|element| element.is::<HTMLAnchorElement>())
1346 .map(|element| DomRoot::from_ref(&**element))
1347 }
1348
1349 pub(crate) fn set_ready_state(&self, cx: &mut JSContext, state: DocumentReadyState) {
1351 match state {
1352 DocumentReadyState::Loading => {
1353 if self.window().is_top_level() {
1354 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1355 self.webview_id(),
1356 LoadStatus::Started,
1357 ));
1358 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1359 }
1360 },
1361 DocumentReadyState::Complete => {
1362 if self.window().is_top_level() {
1363 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1364 self.webview_id(),
1365 LoadStatus::Complete,
1366 ));
1367 }
1368 update_with_current_instant(&self.navigation_timing.dom_complete);
1369 },
1370 DocumentReadyState::Interactive => {
1371 update_with_current_instant(&self.navigation_timing.dom_interactive)
1372 },
1373 };
1374
1375 self.ready_state.set(state);
1376
1377 self.upcast::<EventTarget>()
1378 .fire_event(cx, atom!("readystatechange"));
1379 }
1380
1381 pub(crate) fn scripting_enabled(&self) -> bool {
1384 self.has_browsing_context() &&
1387 !self.has_active_sandboxing_flag(
1391 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1392 )
1393 }
1394
1395 pub(crate) fn title_changed(&self) {
1397 if self.browsing_context().is_some() {
1398 self.send_title_to_embedder();
1399 let title = String::from(self.Title());
1400 self.window
1401 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1402 self.window.pipeline_id(),
1403 title.clone(),
1404 ));
1405 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1406 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1407 self.window.pipeline_id(),
1408 title,
1409 ));
1410 }
1411 }
1412 }
1413
1414 fn title(&self) -> Option<DOMString> {
1418 let title = self.GetDocumentElement().and_then(|root| {
1419 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1420 root.upcast::<Node>()
1422 .child_elements()
1423 .find(|node| {
1424 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1425 })
1426 .map(DomRoot::upcast::<Node>)
1427 } else {
1428 root.upcast::<Node>()
1430 .traverse_preorder(ShadowIncluding::No)
1431 .find(|node| node.is::<HTMLTitleElement>())
1432 }
1433 });
1434
1435 title.map(|title| {
1436 let value = title.child_text_content();
1438 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1439 })
1440 }
1441
1442 pub(crate) fn send_title_to_embedder(&self) {
1444 let window = self.window();
1445 if window.is_top_level() {
1446 let title = self.title().map(String::from);
1447 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1448 }
1449 }
1450
1451 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1452 let window = self.window();
1453 window.send_to_embedder(msg);
1454 }
1455
1456 pub(crate) fn dirty_all_nodes(&self) {
1457 let root = match self.GetDocumentElement() {
1458 Some(root) => root,
1459 None => return,
1460 };
1461 for node in root
1462 .upcast::<Node>()
1463 .traverse_preorder(ShadowIncluding::Yes)
1464 {
1465 node.dirty(NodeDamage::Other)
1466 }
1467 }
1468
1469 pub(crate) fn run_the_scroll_steps(&self, cx: &mut JSContext) {
1471 let boxes_that_were_scrolled: Vec<_> = self
1479 .pending_scroll_events
1480 .borrow()
1481 .iter()
1482 .filter_map(|pending_event| {
1483 if &*pending_event.event == "scroll" {
1484 Some(pending_event.target.as_rooted())
1485 } else {
1486 None
1487 }
1488 })
1489 .collect();
1490
1491 for target in boxes_that_were_scrolled.into_iter() {
1492 let Some(element) = target.downcast::<Element>() else {
1498 continue;
1499 };
1500 let document = element.owner_document();
1501
1502 let mut pending_scroll_events = document.pending_scroll_events.borrow_mut();
1509 let event = "scrollend".into();
1510 if pending_scroll_events
1511 .iter()
1512 .any(|existing| existing.equivalent(&target, &event))
1513 {
1514 continue;
1515 }
1516
1517 pending_scroll_events.push(PendingScrollEvent {
1519 target: target.as_traced(),
1520 event: "scrollend".into(),
1521 });
1522 }
1523
1524 rooted_vec!(let pending_scroll_events <- self.pending_scroll_events.take().into_iter());
1527 for pending_event in pending_scroll_events.iter() {
1528 let event = pending_event.event.clone();
1531 if pending_event.target.is::<Document>() {
1532 pending_event.target.fire_bubbling_event(cx, event);
1533 }
1534 else {
1543 pending_event.target.fire_event(cx, event);
1544 }
1545 }
1546
1547 }
1550
1551 pub(crate) fn handle_viewport_scroll_event(&self) {
1556 self.finish_handle_scroll_event(self.upcast());
1568 }
1569
1570 pub(crate) fn finish_handle_scroll_event(&self, event_target: &EventTarget) {
1575 let event = "scroll".into();
1578 if self
1579 .pending_scroll_events
1580 .borrow()
1581 .iter()
1582 .any(|existing| existing.equivalent(event_target, &event))
1583 {
1584 return;
1585 }
1586
1587 self.pending_scroll_events
1590 .borrow_mut()
1591 .push(PendingScrollEvent {
1592 target: Dom::from_ref(event_target),
1593 event: "scroll".into(),
1594 });
1595 }
1596
1597 pub(crate) fn node_from_nodes_and_strings(
1599 &self,
1600 cx: &mut JSContext,
1601 mut nodes: Vec<NodeOrString>,
1602 ) -> Fallible<DomRoot<Node>> {
1603 if nodes.len() == 1 {
1604 Ok(match nodes.pop().unwrap() {
1605 NodeOrString::Node(node) => node,
1606 NodeOrString::String(string) => DomRoot::upcast(self.CreateTextNode(cx, string)),
1607 })
1608 } else {
1609 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(cx));
1610 for node in nodes {
1611 match node {
1612 NodeOrString::Node(node) => {
1613 fragment.AppendChild(cx, &node)?;
1614 },
1615 NodeOrString::String(string) => {
1616 let node = DomRoot::upcast::<Node>(self.CreateTextNode(cx, string));
1617 fragment.AppendChild(cx, &node).unwrap();
1620 },
1621 }
1622 }
1623 Ok(fragment)
1624 }
1625 }
1626
1627 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1628 match self.GetBody() {
1629 Some(ref body) if body.is_body_element() => {
1630 body.upcast::<Element>().get_string_attribute(local_name)
1631 },
1632 _ => DOMString::new(),
1633 }
1634 }
1635
1636 pub(crate) fn set_body_attribute(
1637 &self,
1638 cx: &mut JSContext,
1639 local_name: &LocalName,
1640 value: DOMString,
1641 ) {
1642 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1643 let body = body.upcast::<Element>();
1644 let value = body.parse_attribute(&ns!(), local_name, value);
1645 body.set_attribute(cx, local_name, value);
1646 }
1647 }
1648
1649 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1650 self.current_script.set(script);
1651 }
1652
1653 pub(crate) fn has_a_stylesheet_that_is_blocking_scripts(&self) -> bool {
1655 !self.script_blocking_stylesheet_set.borrow().is_empty()
1656 }
1657
1658 pub(crate) fn add_script_blocking_stylesheet(&self, id: StylesheetContextId) {
1659 self.script_blocking_stylesheet_set.borrow_mut().insert(id);
1660 }
1661
1662 pub(crate) fn remove_script_blocking_stylesheet(&self, id: StylesheetContextId) {
1663 self.script_blocking_stylesheet_set
1664 .borrow_mut()
1665 .shift_remove(&id);
1666 }
1667
1668 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1669 self.render_blocking_element_count.get()
1670 }
1671
1672 pub(crate) fn increment_render_blocking_element_count(&self) {
1674 assert!(self.allows_adding_render_blocking_elements());
1681 let count_cell = &self.render_blocking_element_count;
1682 count_cell.set(count_cell.get() + 1);
1683 }
1684
1685 pub(crate) fn decrement_render_blocking_element_count(&self) {
1687 let count_cell = &self.render_blocking_element_count;
1693 assert!(count_cell.get() > 0);
1694 count_cell.set(count_cell.get() - 1);
1695 }
1696
1697 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1699 self.is_html_document && self.GetBody().is_none()
1702 }
1703
1704 pub(crate) fn is_render_blocked(&self) -> bool {
1706 self.render_blocking_element_count() > 0
1710 }
1715
1716 pub(crate) fn invalidate_stylesheets(&self) {
1717 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1718
1719 if let Some(element) = self.GetDocumentElement() {
1723 element.upcast::<Node>().dirty(NodeDamage::Style);
1724 }
1725 }
1726
1727 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1730 !self.animation_frame_list.borrow().is_empty()
1731 }
1732
1733 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1735 let ident = self.animation_frame_ident.get() + 1;
1736 self.animation_frame_ident.set(ident);
1737
1738 let had_animation_frame_callbacks;
1739 {
1740 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1741 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1742 animation_frame_list.push_back((ident, Some(callback)));
1743 }
1744
1745 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1751 self.window().send_to_constellation(
1752 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1753 AnimationState::AnimationCallbacksPresent,
1754 ),
1755 );
1756 }
1757
1758 ident
1759 }
1760
1761 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1763 let mut list = self.animation_frame_list.borrow_mut();
1764 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1765 pair.1 = None;
1766 }
1767 }
1768
1769 pub(crate) fn run_the_animation_frame_callbacks(&self, cx: &mut CurrentRealm) {
1771 self.running_animation_callbacks.set(true);
1772 let timing = self.global().performance(cx).Now();
1773
1774 let num_callbacks = self.animation_frame_list.borrow().len();
1775 for _ in 0..num_callbacks {
1776 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1777 if let Some(callback) = maybe_callback {
1778 callback.call(cx, self, *timing);
1779 }
1780 }
1781 self.running_animation_callbacks.set(false);
1782
1783 if self.animation_frame_list.borrow().is_empty() {
1784 self.window().send_to_constellation(
1785 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1786 AnimationState::NoAnimationCallbacksPresent,
1787 ),
1788 );
1789 }
1790 }
1791
1792 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1793 self.policy_container.borrow()
1794 }
1795
1796 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1797 *self.policy_container.borrow_mut() = policy_container;
1798 }
1799
1800 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1801 self.policy_container.borrow_mut().set_csp_list(csp_list);
1802 }
1803
1804 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
1806 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
1808 csp_list.push(policy);
1809 self.policy_container
1810 .borrow_mut()
1811 .set_csp_list(Some(csp_list));
1812 }
1813
1814 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
1815 Ref::map(self.policy_container.borrow(), |policy_container| {
1816 &policy_container.csp_list
1817 })
1818 }
1819
1820 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1821 self.preloaded_resources.borrow()
1822 }
1823
1824 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1825 self.preloaded_resources
1826 .borrow_mut()
1827 .insert(key, preload_id);
1828 }
1829
1830 pub(crate) fn fetch<Listener: FetchResponseListener>(
1831 &self,
1832 load: LoadType,
1833 request: RequestBuilder,
1834 listener: Listener,
1835 ) {
1836 let callback = NetworkListener {
1837 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1838 task_source: self
1839 .owner_global()
1840 .task_manager()
1841 .networking_task_source()
1842 .into(),
1843 }
1844 .into_callback();
1845 self.loader_mut()
1846 .fetch_async_with_callback(load, request, callback);
1847 }
1848
1849 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1850 &self,
1851 request: RequestBuilder,
1852 listener: Listener,
1853 ) {
1854 let callback = NetworkListener {
1855 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1856 task_source: self
1857 .owner_global()
1858 .task_manager()
1859 .networking_task_source()
1860 .into(),
1861 }
1862 .into_callback();
1863 self.loader_mut().fetch_async_background(request, callback);
1864 }
1865
1866 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
1868 match self.window().window_proxy().frame_element() {
1869 None => DomRoot::from_ref(self),
1872 Some(container) => container.owner_document().deferred_fetch_control_document(),
1874 }
1875 }
1876
1877 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
1879 let control_document = self.deferred_fetch_control_document();
1881 let navigable = control_document.window();
1883 let is_top_level = navigable.is_top_level();
1886 let deferred_fetch_allowed = true;
1890 let deferred_fetch_minimal_allowed = true;
1894 let mut quota = match is_top_level {
1896 true if !deferred_fetch_allowed => 0,
1898 true if !deferred_fetch_minimal_allowed => 640 * 1024,
1900 true => 512 * 1024,
1902 _ if deferred_fetch_allowed => 0,
1906 _ if deferred_fetch_minimal_allowed => 8 * 1024,
1910 _ => 0,
1912 } as isize;
1913 let mut quota_for_request_origin = 64 * 1024_isize;
1915 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
1924 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
1926 continue;
1927 }
1928 let request_length = deferred_fetch.request.total_request_length();
1930 quota -= request_length as isize;
1932 if deferred_fetch.request.url().origin() == origin {
1935 quota_for_request_origin -= request_length as isize;
1936 }
1937 }
1938 if quota <= 0 {
1940 return 0;
1941 }
1942 if quota < quota_for_request_origin {
1944 return quota;
1945 }
1946 quota_for_request_origin
1948 }
1949
1950 pub(crate) fn update_document_for_history_step_application(
1952 &self,
1953 old_url: &ServoUrl,
1954 new_url: &ServoUrl,
1955 ) {
1956 if old_url.as_url()[Position::BeforeFragment..] !=
1986 new_url.as_url()[Position::BeforeFragment..]
1987 {
1988 let window = Trusted::new(self.owner_window().deref());
1989 let old_url = old_url.to_string();
1990 let new_url = new_url.to_string();
1991 self.owner_global()
1992 .task_manager()
1993 .dom_manipulation_task_source()
1994 .queue(task!(hashchange_event: move |cx| {
1995 let window = window.root();
1996 HashChangeEvent::new(
1997 cx,
1998 &window,
1999 atom!("hashchange"),
2000 false,
2001 false,
2002 old_url,
2003 new_url,
2004 )
2005 .upcast::<Event>()
2006 .fire(cx, window.upcast());
2007 }));
2008 }
2009 }
2010
2011 pub(crate) fn finish_load_for_dropped_blocker(&self, load: LoadType) {
2012 let this = Trusted::new(self);
2013 self.owner_global()
2014 .task_manager()
2015 .dom_manipulation_task_source()
2016 .queue(task!(check_finished_load: move |cx| {
2017 this.root().finish_load(load, cx);
2018 }));
2019 }
2020
2021 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut JSContext) {
2024 debug!("Document got finish_load: {:?}", load);
2026 self.loader.borrow_mut().finish_load(&load);
2027
2028 match load {
2029 LoadType::Stylesheet(_) => {
2030 self.process_pending_parsing_blocking_script(cx);
2033
2034 self.process_deferred_scripts(cx);
2036 },
2037 LoadType::PageSource(_) => {
2038 if self.has_browsing_context && self.is_fully_active() {
2041 self.window().allow_layout_if_necessary(cx);
2042 }
2043
2044 self.process_deferred_scripts(cx);
2049 },
2050 _ => {},
2051 }
2052
2053 let loader = self.loader.borrow();
2062
2063 if self
2065 .navigation_timing
2066 .top_level_dom_complete
2067 .get()
2068 .is_none() &&
2069 loader.is_only_blocked_by_iframes()
2070 {
2071 update_with_current_instant(&self.navigation_timing.top_level_dom_complete);
2072 }
2073
2074 if loader.is_blocked() || loader.events_inhibited() {
2075 return;
2077 }
2078
2079 ScriptThread::mark_document_with_no_blocked_loads(self);
2080
2081 let document = Trusted::new(self);
2085 self.owner_global()
2086 .task_manager()
2087 .dom_manipulation_task_source()
2088 .queue(task!(wait_for_load_blockers: move |cx| {
2089 document.root().wait_until_load_blockers_have_resolved(cx);
2090 }));
2091 }
2092
2093 pub(crate) fn check_if_unloading_is_cancelled(
2095 &self,
2096 cx: &mut JSContext,
2097 recursive_flag: bool,
2098 ) -> bool {
2099 self.incr_ignore_opens_during_unload_counter();
2102 let beforeunload_event = BeforeUnloadEvent::new(
2104 cx,
2105 &self.window,
2106 atom!("beforeunload"),
2107 EventBubbles::Bubbles,
2108 EventCancelable::Cancelable,
2109 );
2110 let event = beforeunload_event.upcast::<Event>();
2111 event.set_trusted(true);
2112 let event_target = self.window.upcast::<EventTarget>();
2113 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2114 self.window.dispatch_event_with_target_override(cx, event);
2115 if has_listeners {
2118 self.salvageable.set(false);
2119 }
2120 let mut can_unload = true;
2121 let default_prevented = event.DefaultPrevented();
2123 let return_value_not_empty = !event
2124 .downcast::<BeforeUnloadEvent>()
2125 .unwrap()
2126 .ReturnValue()
2127 .is_empty();
2128 if default_prevented || return_value_not_empty {
2129 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2130 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2131 self.send_to_embedder(msg);
2132 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2133 }
2134 if !recursive_flag {
2136 let iframes: Vec<_> = self.iframes().iter().collect();
2139 for iframe in &iframes {
2140 let document = iframe.owner_document();
2142 can_unload = document.check_if_unloading_is_cancelled(cx, true);
2143 if !document.salvageable() {
2144 self.salvageable.set(false);
2145 }
2146 if !can_unload {
2147 break;
2148 }
2149 }
2150 }
2151 self.decr_ignore_opens_during_unload_counter();
2153 can_unload
2154 }
2155
2156 pub(crate) fn unload(&self, cx: &mut JSContext, recursive_flag: bool) {
2158 self.incr_ignore_opens_during_unload_counter();
2161 if self.page_showing.get() {
2163 self.page_showing.set(false);
2165 let event = PageTransitionEvent::new(
2168 cx,
2169 &self.window,
2170 atom!("pagehide"),
2171 false, false, self.salvageable.get(), );
2175 let event = event.upcast::<Event>();
2176 event.set_trusted(true);
2177 self.window.dispatch_event_with_target_override(cx, event);
2178 self.update_visibility_state(cx, DocumentVisibilityState::Hidden);
2180 }
2181 if !self.fired_unload.get() {
2183 let event = Event::new(
2184 cx,
2185 self.window.upcast(),
2186 atom!("unload"),
2187 EventBubbles::Bubbles,
2188 EventCancelable::Cancelable,
2189 );
2190 event.set_trusted(true);
2191 let event_target = self.window.upcast::<EventTarget>();
2192 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2193 self.window.dispatch_event_with_target_override(cx, &event);
2194 self.fired_unload.set(true);
2195 if has_listeners {
2197 self.salvageable.set(false);
2198 }
2199 }
2200 if !recursive_flag {
2204 let iframes: Vec<_> = self.iframes().iter().collect();
2207 for iframe in &iframes {
2208 let document = iframe.owner_document();
2210 document.unload(cx, true);
2211 if !document.salvageable() {
2212 self.salvageable.set(false);
2213 }
2214 }
2215 }
2216
2217 self.unloading_cleanup_steps();
2219
2220 self.window.as_global_scope().clean_up_all_file_resources();
2222
2223 self.decr_ignore_opens_during_unload_counter();
2225
2226 }
2229
2230 fn completely_finish_loading(&self) {
2232 self.completely_loaded.set(true);
2237 self.notify_constellation_load();
2246
2247 if let Some(DeclarativeRefresh::PendingLoad {
2256 url,
2257 time,
2258 from_meta_element,
2259 }) = &*self.declarative_refresh.borrow()
2260 {
2261 self.window.as_global_scope().schedule_callback(
2262 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2263 window: DomRoot::from_ref(self.window()),
2264 url: url.clone(),
2265 from_meta_element: *from_meta_element,
2266 }),
2267 Duration::from_secs(*time),
2268 );
2269 }
2270 }
2271
2272 pub(crate) fn maybe_queue_document_completion(&self, cx: &mut JSContext) {
2275 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2277 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2278 None => false,
2279 };
2280
2281 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2286 !self.is_fully_active() ||
2287 is_in_delaying_load_events_mode ||
2288 self.loader.borrow().events_inhibited();
2291
2292 if not_ready_for_load {
2293 return;
2295 }
2296
2297 self.queue_document_completion(cx);
2298 }
2299
2300 fn queue_document_completion(&self, cx: &mut JSContext) {
2302 self.loader.borrow_mut().inhibit_events();
2303
2304 debug!("Document loads are complete.");
2309 let document = Trusted::new(self);
2310 self.owner_global()
2311 .task_manager()
2312 .dom_manipulation_task_source()
2313 .queue(task!(fire_load_event: move |cx| {
2314 let document = document.root();
2315 let window = document.window();
2317 if !window.is_alive() {
2318 return;
2319 }
2320
2321 document.set_ready_state(cx,DocumentReadyState::Complete);
2323
2324 if document.browsing_context().is_none() {
2326 return;
2327 }
2328
2329 update_with_current_instant(&document.navigation_timing.load_event_start);
2331
2332 let load_event = Event::new(
2334 cx,
2335 window.upcast(),
2336 atom!("load"),
2337 EventBubbles::DoesNotBubble,
2338 EventCancelable::NotCancelable,
2339 );
2340 load_event.set_trusted(true);
2341 debug!("About to dispatch load for {:?}", document.url());
2342 window.dispatch_event_with_target_override(cx, &load_event);
2343
2344 update_with_current_instant(&document.navigation_timing.load_event_end);
2354
2355 document.page_showing.set(true);
2360
2361 let page_show_event = PageTransitionEvent::new(
2363 cx,
2364 window,
2365 atom!("pageshow"),
2366 false, false, false, );
2370 let page_show_event = page_show_event.upcast::<Event>();
2371 page_show_event.set_trusted(true);
2372 page_show_event.fire(cx, window.upcast());
2373
2374 document.completely_finish_loading();
2376
2377 if let Some(fragment) = document.url().fragment() {
2381 document.scroll_to_the_fragment(cx, fragment);
2382 }
2383 }));
2384
2385 #[cfg(feature = "webxr")]
2400 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2401 self.window.Navigator(cx).Xr(cx).dispatch_sessionavailable();
2402 }
2403 }
2404
2405 pub(crate) fn completely_loaded(&self) -> bool {
2406 self.completely_loaded.get()
2407 }
2408
2409 pub(crate) fn start_the_end_loading_phase(&self) {
2410 self.current_the_end_loading_phase
2411 .set(TheEndLoadingPhase::ProcessingDeferredScripts);
2412 }
2413
2414 pub(crate) fn set_pending_parsing_blocking_script(
2416 &self,
2417 script: &HTMLScriptElement,
2418 load: Option<ScriptResult>,
2419 ) {
2420 assert!(!self.has_pending_parsing_blocking_script());
2421 *self.pending_parsing_blocking_script.borrow_mut() =
2422 Some(PendingScript::new_with_load(script, load));
2423 }
2424
2425 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2427 self.pending_parsing_blocking_script.borrow().is_some()
2428 }
2429
2430 pub(crate) fn pending_parsing_blocking_script_loaded(
2432 &self,
2433 element: &HTMLScriptElement,
2434 result: ScriptResult,
2435 cx: &mut JSContext,
2436 ) {
2437 {
2438 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2439 let entry = blocking_script.as_mut().unwrap();
2440 assert!(&*entry.element == element);
2441 entry.loaded(result);
2442 }
2443 self.process_pending_parsing_blocking_script(cx);
2444 }
2445
2446 fn process_pending_parsing_blocking_script(&self, cx: &mut JSContext) {
2447 if self.has_a_stylesheet_that_is_blocking_scripts() {
2448 return;
2449 }
2450 let pair = self
2451 .pending_parsing_blocking_script
2452 .borrow_mut()
2453 .as_mut()
2454 .and_then(PendingScript::take_result);
2455 if let Some((element, result)) = pair {
2456 *self.pending_parsing_blocking_script.borrow_mut() = None;
2457 self.get_current_parser()
2458 .unwrap()
2459 .resume_with_pending_parsing_blocking_script(cx, &element, result);
2460 }
2461 }
2462
2463 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2465 self.asap_scripts_set
2466 .borrow_mut()
2467 .push(Dom::from_ref(script));
2468 }
2469
2470 pub(crate) fn asap_script_loaded(
2473 &self,
2474 cx: &mut JSContext,
2475 element: &HTMLScriptElement,
2476 result: ScriptResult,
2477 ) {
2478 {
2479 let mut scripts = self.asap_scripts_set.borrow_mut();
2480 let idx = scripts
2481 .iter()
2482 .position(|entry| &**entry == element)
2483 .unwrap();
2484 scripts.swap_remove(idx);
2485 }
2486 element.execute(cx, result);
2487 self.wait_until_asap_scripts_have_executed();
2488 }
2489
2490 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2492 self.asap_in_order_scripts_list.push(script);
2493 }
2494
2495 pub(crate) fn asap_in_order_script_loaded(
2498 &self,
2499 cx: &mut JSContext,
2500 element: &HTMLScriptElement,
2501 result: ScriptResult,
2502 ) {
2503 self.asap_in_order_scripts_list.loaded(element, result);
2504 while let Some((element, result)) = self
2505 .asap_in_order_scripts_list
2506 .take_next_ready_to_be_executed()
2507 {
2508 element.execute(cx, result);
2509 }
2510
2511 self.wait_until_asap_scripts_have_executed();
2512 }
2513
2514 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2516 self.deferred_scripts.push(script);
2517 }
2518
2519 pub(crate) fn deferred_script_loaded(
2522 &self,
2523 cx: &mut JSContext,
2524 element: &HTMLScriptElement,
2525 result: ScriptResult,
2526 ) {
2527 self.deferred_scripts.loaded(element, result);
2528 self.process_deferred_scripts(cx);
2529 }
2530
2531 fn process_deferred_scripts(&self, cx: &mut JSContext) {
2533 if self.current_the_end_loading_phase.get() != TheEndLoadingPhase::ProcessingDeferredScripts
2534 {
2535 return;
2536 }
2537
2538 loop {
2542 if self.has_a_stylesheet_that_is_blocking_scripts() {
2543 return;
2544 }
2545 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2548 {
2549 element.execute(cx, result);
2551 } else {
2552 break;
2553 }
2554 }
2555 if self.deferred_scripts.is_empty() {
2557 self.current_the_end_loading_phase
2558 .set(TheEndLoadingPhase::ProcessingAsSoonAsPossibleScripts);
2559 self.maybe_dispatch_dom_content_loaded();
2561 }
2562 }
2563
2564 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2566 if self.domcontentloaded_dispatched.get() {
2568 return;
2569 }
2570 self.domcontentloaded_dispatched.set(true);
2571
2572 self.dispatch_dom_content_loaded();
2573 }
2574
2575 fn dispatch_dom_content_loaded(&self) {
2577 assert_ne!(
2578 self.ReadyState(),
2579 DocumentReadyState::Complete,
2580 "Complete before DOMContentLoaded?"
2581 );
2582
2583 let document = Trusted::new(self);
2586 self.owner_global()
2587 .task_manager()
2588 .dom_manipulation_task_source()
2589 .queue(task!(fire_dom_content_loaded_event: move |cx| {
2590 let document = document.root();
2593 update_with_current_instant(&document.navigation_timing.dom_content_loaded_event_start);
2594 document.upcast::<EventTarget>().fire_bubbling_event(cx, atom!("DOMContentLoaded"));
2596 update_with_current_instant(&document.navigation_timing.dom_content_loaded_event_end);
2599 }));
2608
2609 self.interactive_time
2611 .borrow()
2612 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2613
2614 self.wait_until_asap_scripts_have_executed();
2615 }
2616
2617 fn has_finished_all_asap_scripts(&self) -> bool {
2618 self.asap_scripts_set.borrow().is_empty() && self.asap_in_order_scripts_list.is_empty()
2619 }
2620
2621 fn wait_until_asap_scripts_have_executed(&self) {
2623 if self.current_the_end_loading_phase.get() !=
2624 TheEndLoadingPhase::ProcessingAsSoonAsPossibleScripts
2625 {
2626 return;
2627 }
2628 if self.has_finished_all_asap_scripts() {
2631 let document = Trusted::new(self);
2632 self.owner_global()
2633 .task_manager()
2634 .dom_manipulation_task_source()
2635 .queue(task!(transition_away_from_asap_scripts: move |cx| {
2636 let document = document.root();
2637 if document.current_the_end_loading_phase.get() !=
2640 TheEndLoadingPhase::ProcessingAsSoonAsPossibleScripts
2641 {
2642 return;
2643 }
2644 if !document.has_finished_all_asap_scripts() {
2646 return;
2647 }
2648 document.current_the_end_loading_phase
2649 .set(TheEndLoadingPhase::WaitingForLoadEventBlockers);
2650 document.wait_until_load_blockers_have_resolved(cx);
2651 }));
2652 }
2653 }
2654
2655 pub(crate) fn wait_until_load_blockers_have_resolved(&self, _cx: &mut JSContext) {
2657 if self.current_the_end_loading_phase.get() !=
2658 TheEndLoadingPhase::WaitingForLoadEventBlockers
2659 {
2660 return;
2661 }
2662 {
2664 let loader = self.loader.borrow();
2665
2666 if self
2668 .navigation_timing
2669 .top_level_dom_complete
2670 .get()
2671 .is_none() &&
2672 loader.is_only_blocked_by_iframes()
2673 {
2674 update_with_current_instant(&self.navigation_timing.top_level_dom_complete);
2675 }
2676
2677 let not_ready_for_load = loader.is_blocked() || loader.events_inhibited();
2678 if not_ready_for_load {
2679 return;
2680 }
2681 }
2682
2683 self.current_the_end_loading_phase
2684 .set(TheEndLoadingPhase::Done);
2685 }
2688
2689 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut JSContext) {
2691 if !self.is_fully_active() {
2693 self.salvageable.set(false);
2698 }
2702 for exited_iframe in self.iframes().iter() {
2715 debug!("Destroying nested iframe document");
2716 exited_iframe.destroy_document_and_its_descendants(cx);
2717 }
2718 self.destroy(cx);
2723 }
2726
2727 pub(crate) fn destroy(&self, cx: &mut JSContext) {
2729 let exited_window = self.window();
2730 self.abort(cx);
2732 self.salvageable.set(false);
2734 self.unloading_cleanup_steps();
2744
2745 exited_window
2748 .as_global_scope()
2749 .task_manager()
2750 .cancel_all_tasks_and_ignore_future_tasks();
2751
2752 exited_window.discard_browsing_context();
2754
2755 }
2767
2768 fn terminate_fetch_group(&self) -> bool {
2770 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2771
2772 for canceller in &mut load_cancellers {
2776 if !canceller.keep_alive() {
2777 canceller.terminate();
2778 }
2779 }
2780 self.owner_global().process_deferred_fetches();
2782
2783 !load_cancellers.is_empty()
2784 }
2785
2786 fn active_parser(&self) -> Option<DomRoot<ServoParser>> {
2788 self.get_current_parser()
2791 .filter(|parser| !(parser.has_stopped() || parser.has_aborted()))
2792 }
2793
2794 pub(crate) fn abort(&self, cx: &mut JSContext) {
2796 self.loader.borrow_mut().inhibit_events();
2798
2799 self.script_blocking_stylesheet_set.borrow_mut().clear();
2808 *self.pending_parsing_blocking_script.borrow_mut() = None;
2809 *self.asap_scripts_set.borrow_mut() = vec![];
2810 self.asap_in_order_scripts_list.clear();
2811 self.deferred_scripts.clear();
2812 let loads_cancelled = self.terminate_fetch_group();
2813 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2814 if loads_cancelled || event_sources_canceled {
2815 self.salvageable.set(false);
2817 };
2818
2819 self.owner_global()
2824 .task_manager()
2825 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2826
2827 if let Some(parser) = self.active_parser() {
2832 self.active_parser_was_aborted.set(true);
2834 parser.abort(cx);
2836 self.salvageable.set(false);
2838 }
2839 }
2840
2841 pub(crate) fn abort_a_document_and_its_descendants(&self, cx: &mut JSContext) {
2843 for iframe in self.iframes().iter() {
2851 if let Some(descendant_document) = iframe.GetContentDocument() {
2852 let trusted_descendant_document = Trusted::new(&*descendant_document);
2853 let document = Trusted::new(self);
2854 descendant_document
2855 .owner_global()
2856 .task_manager()
2857 .navigation_and_traversal_task_source()
2858 .queue(task!(abort_iframe_document: move |cx| {
2859 let descendant_document = trusted_descendant_document.root();
2860 descendant_document.abort(cx);
2862 if !descendant_document.salvageable.get() {
2864 document.root().salvageable.set(false);
2865 }
2866 }));
2867 }
2868 }
2869
2870 self.abort(cx);
2872 }
2873
2874 pub(crate) fn notify_constellation_load(&self) {
2875 self.window()
2876 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2877 }
2878
2879 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2880 self.current_parser.set(script);
2881 }
2882
2883 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2884 self.current_parser.get()
2885 }
2886
2887 pub(crate) fn get_current_parser_line(&self) -> u32 {
2888 self.get_current_parser()
2889 .map(|parser| parser.get_current_line())
2890 .unwrap_or(0)
2891 }
2892
2893 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2896 self.iframes.borrow()
2897 }
2898
2899 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2902 self.iframes.borrow_mut()
2903 }
2904
2905 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2906 self.interactive_time
2907 .borrow_mut()
2908 .set_navigation_start(navigation_start);
2909 }
2910
2911 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2912 self.interactive_time.borrow()
2913 }
2914
2915 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2916 self.get_interactive_metrics().get_tti().is_some()
2917 }
2918
2919 pub(crate) fn start_tti(&self) {
2920 if self.get_interactive_metrics().needs_tti() {
2921 self.tti_window.borrow_mut().start_window();
2922 }
2923 }
2924
2925 pub(crate) fn record_tti_if_necessary(&self) {
2929 if self.has_recorded_tti_metric() {
2930 return;
2931 }
2932 if self.tti_window.borrow().needs_check() {
2933 self.get_interactive_metrics()
2934 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2935 self.tti_window.borrow().get_start(),
2936 ));
2937 }
2938 }
2939
2940 pub(crate) fn is_cookie_averse(&self) -> bool {
2942 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2943 }
2944
2945 pub(crate) fn lookup_custom_element_definition(
2947 &self,
2948 namespace: &Namespace,
2949 local_name: &LocalName,
2950 is: Option<&LocalName>,
2951 ) -> Option<Rc<CustomElementDefinition>> {
2952 if *namespace != ns!(html) {
2954 return None;
2955 }
2956
2957 if !self.has_browsing_context {
2959 return None;
2960 }
2961
2962 let registry = self.custom_element_registry()?;
2964
2965 registry.lookup_definition(local_name, is)
2966 }
2967
2968 pub(crate) fn custom_element_registry(&self) -> Option<DomRoot<CustomElementRegistry>> {
2969 self.document_or_shadow_root.custom_element_registry()
2970 }
2971
2972 pub(crate) fn set_custom_element_registry(&self, registry: &CustomElementRegistry) {
2973 self.document_or_shadow_root
2974 .set_custom_element_registry(Some(registry));
2975 }
2976
2977 pub(crate) fn teardown_custom_element_registry(&self) {
2980 if let Some(custom_elements) = self.custom_element_registry() {
2981 custom_elements.teardown();
2982 }
2983 }
2984
2985 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2986 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2987 self.throw_on_dynamic_markup_insertion_counter
2988 .set(counter + 1);
2989 }
2990
2991 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2992 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2993 self.throw_on_dynamic_markup_insertion_counter
2994 .set(counter - 1);
2995 }
2996
2997 pub(crate) fn react_to_environment_changes(&self, cx: &JSContext) {
2998 for image in self.responsive_images.borrow().iter() {
2999 image.react_to_environment_changes(cx);
3000 }
3001 }
3002
3003 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3004 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3005 }
3006
3007 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3008 let index = self
3009 .responsive_images
3010 .borrow()
3011 .iter()
3012 .position(|x| **x == *img);
3013 if let Some(i) = index {
3014 self.responsive_images.borrow_mut().remove(i);
3015 }
3016 }
3017
3018 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3019 let did_have_these_media_controls = self
3020 .media_controls
3021 .borrow_mut()
3022 .insert(id.to_string(), Dom::from_ref(controls))
3023 .is_some();
3024 debug_assert!(
3025 !did_have_these_media_controls,
3026 "Trying to register known media controls"
3027 );
3028 }
3029
3030 pub(crate) fn unregister_media_controls(&self, id: &str) {
3031 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3032 debug_assert!(
3033 did_have_these_media_controls,
3034 "Trying to unregister unknown media controls"
3035 );
3036 }
3037
3038 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3039 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3040 if dirty_canvases
3041 .iter()
3042 .any(|dirty_canvas| dirty_canvas == canvas)
3043 {
3044 return;
3045 }
3046 dirty_canvases.push(canvas.clone());
3047 }
3048
3049 pub(crate) fn needs_rendering_update(&self) -> bool {
3053 if !self.is_fully_active() {
3054 return false;
3055 }
3056 if !self.window().layout_blocked() &&
3057 (!self.restyle_reason().is_empty() ||
3058 self.window().layout().needs_new_display_list() ||
3059 self.window().layout().needs_accessibility_update())
3060 {
3061 return true;
3062 }
3063 if !self.rendering_update_reasons.get().is_empty() {
3064 return true;
3065 }
3066 if self.event_handler.has_pending_input_events() {
3067 return true;
3068 }
3069 if self.has_pending_scroll_events() {
3070 return true;
3071 }
3072 if self.window().has_unhandled_resize_event() {
3073 return true;
3074 }
3075 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3076 {
3077 return true;
3078 }
3079 if self.window().has_pending_media_query_evaluation() {
3080 return true;
3081 }
3082
3083 false
3084 }
3085
3086 pub(crate) fn update_the_rendering(
3094 &self,
3095 cx: &mut JSContext,
3096 ) -> (ReflowPhasesRun, ReflowStatistics) {
3097 assert!(!self.is_render_blocked());
3098
3099 let mut phases = ReflowPhasesRun::empty();
3100 if self.has_pending_animated_image_update.get() {
3101 self.image_animation_manager
3102 .borrow()
3103 .update_active_frames(&self.window, self.current_animation_timeline_value());
3104 self.has_pending_animated_image_update.set(false);
3105 phases.insert(ReflowPhasesRun::UpdatedImageData);
3106 }
3107
3108 self.current_rendering_epoch
3109 .set(self.current_rendering_epoch.get().next());
3110 let current_rendering_epoch = self.current_rendering_epoch.get();
3111
3112 let image_keys: Vec<_> = self
3114 .dirty_canvases
3115 .borrow_mut()
3116 .drain(..)
3117 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3118 .collect();
3119
3120 let pipeline_id = self.window().pipeline_id();
3123 if !image_keys.is_empty() {
3124 phases.insert(ReflowPhasesRun::UpdatedImageData);
3125 self.waiting_on_canvas_image_updates.set(true);
3126 self.window().paint_api().delay_new_frame_for_canvas(
3127 self.webview_id(),
3128 self.window().pipeline_id(),
3129 current_rendering_epoch,
3130 image_keys,
3131 );
3132 }
3133
3134 let (reflow_phases, statistics) = self.window().reflow(cx, ReflowGoal::UpdateTheRendering);
3135 let phases = phases.union(reflow_phases);
3136
3137 self.window().paint_api().update_epoch(
3138 self.webview_id(),
3139 pipeline_id,
3140 current_rendering_epoch,
3141 );
3142
3143 (phases, statistics)
3144 }
3145
3146 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3147 self.waiting_on_canvas_image_updates.set(false);
3148 }
3149
3150 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3151 self.waiting_on_canvas_image_updates.get()
3152 }
3153
3154 pub(crate) fn maybe_fulfill_font_ready_promise(&self, cx: &mut JSContext) -> bool {
3164 if !self.is_fully_active() {
3165 return false;
3166 }
3167
3168 let fonts = self.Fonts(cx);
3169 if !fonts.waiting_to_fullfill_promise() {
3170 return false;
3171 }
3172 if self.window().font_context().web_fonts_still_loading() != 0 {
3173 return false;
3174 }
3175 if self.ReadyState() != DocumentReadyState::Complete {
3176 return false;
3177 }
3178 if !self.restyle_reason().is_empty() {
3179 return false;
3180 }
3181 if !self.rendering_update_reasons.get().is_empty() {
3182 return false;
3183 }
3184
3185 let result = fonts.fulfill_ready_promise_if_needed(cx);
3186
3187 if result {
3191 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3192 }
3193
3194 result
3195 }
3196
3197 pub(crate) fn id_map(&self) -> &TreeOrderedIndexMap {
3198 &self.id_map
3199 }
3200
3201 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3203 self.resize_observers
3204 .borrow_mut()
3205 .push(Dom::from_ref(resize_observer));
3206 }
3207
3208 pub(crate) fn gather_active_resize_observations_at_depth(
3211 &self,
3212 depth: &ResizeObservationDepth,
3213 ) -> bool {
3214 let mut has_active_resize_observations = false;
3215 for observer in self.resize_observers.borrow_mut().iter_mut() {
3216 observer.gather_active_resize_observations_at_depth(
3217 depth,
3218 &mut has_active_resize_observations,
3219 );
3220 }
3221 has_active_resize_observations
3222 }
3223
3224 #[expect(clippy::redundant_iter_cloned)]
3226 pub(crate) fn broadcast_active_resize_observations(
3227 &self,
3228 cx: &mut JSContext,
3229 ) -> ResizeObservationDepth {
3230 let mut shallowest = ResizeObservationDepth::max();
3231 let iterator: Vec<DomRoot<ResizeObserver>> = self
3235 .resize_observers
3236 .borrow()
3237 .iter()
3238 .cloned()
3239 .map(|obs| DomRoot::from_ref(&*obs))
3240 .collect();
3241 for observer in iterator {
3242 observer.broadcast_active_resize_observations(cx, &mut shallowest);
3243 }
3244 shallowest
3245 }
3246
3247 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3249 self.resize_observers
3250 .borrow()
3251 .iter()
3252 .any(|observer| observer.has_skipped_resize_observations())
3253 }
3254
3255 pub(crate) fn deliver_resize_loop_error_notification(&self, cx: &mut JSContext) {
3257 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3258 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3259 ..Default::default()
3260 };
3261 self.window
3262 .as_global_scope()
3263 .report_an_error(cx, error_info, HandleValue::null());
3264 }
3265
3266 pub(crate) fn status_code(&self) -> Option<u16> {
3267 self.status_code
3268 }
3269
3270 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3272 let encoding = self.encoding.get();
3278
3279 let base_url = self.base_url();
3285
3286 url::Url::options()
3288 .base_url(Some(base_url.as_url()))
3289 .encoding_override(Some(&|input| {
3290 servo_url::encoding::encode_as_url_query_string(input, encoding)
3291 }))
3292 .parse(url)
3293 .map(ServoUrl::from)
3294 }
3295
3296 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3298 if !self.has_browsing_context {
3300 return false;
3301 }
3302
3303 if !self.is_fully_active() {
3305 return false;
3306 }
3307
3308 true
3314 }
3315
3316 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3319 self.intersection_observers
3320 .borrow_mut()
3321 .push(Dom::from_ref(intersection_observer));
3322 }
3323
3324 pub(crate) fn remove_intersection_observer(
3328 &self,
3329 intersection_observer: &IntersectionObserver,
3330 ) {
3331 self.intersection_observers
3332 .borrow_mut()
3333 .retain(|observer| *observer != intersection_observer)
3334 }
3335
3336 pub(crate) fn update_intersection_observer_steps(
3338 &self,
3339 cx: &mut JSContext,
3340 time: CrossProcessInstant,
3341 ) {
3342 if self.intersection_observers.borrow().is_empty() {
3343 return;
3344 }
3345 self.window()
3347 .reflow_for_non_flushing_update_the_rendering_queries(cx);
3348
3349 for intersection_observer in &*self.intersection_observers.borrow() {
3351 self.update_single_intersection_observer_steps(cx, intersection_observer, time);
3352 }
3353 }
3354
3355 fn update_single_intersection_observer_steps(
3357 &self,
3358 cx: &mut JSContext,
3359 intersection_observer: &IntersectionObserver,
3360 time: CrossProcessInstant,
3361 ) {
3362 let root_bounds = intersection_observer.root_intersection_rectangle();
3365
3366 intersection_observer.update_intersection_observations_steps(cx, self, time, root_bounds);
3370 }
3371
3372 pub(crate) fn notify_intersection_observers(&self, cx: &mut JSContext) {
3374 self.intersection_observer_task_queued.set(false);
3377
3378 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3383
3384 for intersection_observer in notify_list.iter() {
3387 intersection_observer.invoke_callback_if_necessary(cx);
3389 }
3390 }
3391
3392 pub(crate) fn queue_an_intersection_observer_task(&self) {
3394 if self.intersection_observer_task_queued.get() {
3397 return;
3398 }
3399
3400 self.intersection_observer_task_queued.set(true);
3403
3404 let document = Trusted::new(self);
3408 self.owner_global()
3409 .task_manager()
3410 .intersection_observer_task_source()
3411 .queue(task!(notify_intersection_observers: move |cx| {
3412 document.root().notify_intersection_observers(cx);
3413 }));
3414 }
3415
3416 pub(crate) fn handle_paint_metric(
3417 &self,
3418 cx: &mut JSContext,
3419 metric_type: ProgressiveWebMetricType,
3420 metric_value: CrossProcessInstant,
3421 first_reflow: bool,
3422 ) {
3423 let metrics = self.interactive_time.borrow();
3424 match metric_type {
3425 ProgressiveWebMetricType::FirstPaint |
3426 ProgressiveWebMetricType::FirstContentfulPaint => {
3427 let binding = PerformancePaintTiming::new(
3428 cx,
3429 self.window.as_global_scope(),
3430 metric_type.clone(),
3431 metric_value,
3432 );
3433 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3434 let entry = binding.upcast::<PerformanceEntry>();
3435 self.window.Performance(cx).queue_entry(entry);
3436 },
3437 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3438 let binding = LargestContentfulPaint::new(
3439 cx,
3440 self.window.as_global_scope(),
3441 metric_value,
3442 area,
3443 url,
3444 );
3445 metrics.set_largest_contentful_paint(metric_value, area);
3446 let entry = binding.upcast::<PerformanceEntry>();
3447 self.window.Performance(cx).queue_entry(entry);
3448 },
3449 ProgressiveWebMetricType::TimeToInteractive => {
3450 unreachable!("Unexpected non-paint metric.")
3451 },
3452 }
3453 }
3454
3455 fn write(
3457 &self,
3458 cx: &mut JSContext,
3459 text: Vec<TrustedHTMLOrString>,
3460 line_feed: bool,
3461 containing_class: &str,
3462 field: &str,
3463 ) -> ErrorResult {
3464 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3466 let mut is_trusted = true;
3468 for value in text {
3470 match value {
3471 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3473 strings.push(trusted_html.to_string());
3474 },
3475 TrustedHTMLOrString::String(str_) => {
3476 is_trusted = false;
3478 strings.push(str_.into());
3480 },
3481 };
3482 }
3483 let mut string = itertools::join(strings, "");
3484 if !is_trusted {
3488 string = TrustedHTML::get_trusted_type_compliant_string(
3489 cx,
3490 &self.global(),
3491 TrustedHTMLOrString::String(string.into()),
3492 &format!("{} {}", containing_class, field),
3493 )?
3494 .str()
3495 .to_owned();
3496 }
3497 if line_feed {
3499 string.push('\n');
3500 }
3501 if !self.is_html_document() {
3503 return Err(Error::InvalidState(None));
3504 }
3505
3506 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3509 return Err(Error::InvalidState(None));
3510 }
3511
3512 if self.active_parser_was_aborted.get() {
3514 return Ok(());
3515 }
3516
3517 let parser = match self.get_current_parser() {
3518 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3519 _ => {
3521 if self.is_prompting_or_unloading() ||
3524 self.ignore_destructive_writes_counter.get() > 0
3525 {
3526 return Ok(());
3527 }
3528 self.Open(cx, None, None)?;
3530 self.get_current_parser().unwrap()
3531 },
3532 };
3533
3534 parser.write(cx, string.into());
3536
3537 Ok(())
3538 }
3539
3540 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3541 RefMut::map(
3542 self.details_name_groups.borrow_mut(),
3543 |details_name_groups| details_name_groups.get_or_insert_default(),
3544 )
3545 }
3546
3547 pub(crate) fn accessibility_data_mut(&self) -> RefMut<'_, AccessibilityData> {
3548 self.accessibility_data.borrow_mut()
3549 }
3550
3551 pub(crate) fn accessibility_active(&self) -> bool {
3552 self.window().layout().accessibility_active()
3553 }
3554
3555 pub(crate) fn rooted_nodes_for_accessibility_integrity_check(
3556 &self,
3557 ) -> Option<FxHashSet<OpaqueNode>> {
3558 if !self.accessibility_active() {
3559 return None;
3560 }
3561
3562 let mut accessibility_data = self.accessibility_data_mut();
3563
3564 if pref!(expensive_accessibility_test_assertions_enabled) {
3565 return Some(accessibility_data.unroot_and_drain_all_removed_nodes());
3566 }
3567
3568 accessibility_data.unroot_all_removed_nodes();
3569 None
3570 }
3571}
3572
3573#[derive(MallocSizeOf, PartialEq)]
3574pub(crate) enum DocumentSource {
3575 FromParser,
3576 NotFromParser,
3577}
3578
3579impl<'dom> LayoutDom<'dom, Document> {
3580 #[inline]
3581 pub(crate) fn is_html_document_for_layout(&self) -> bool {
3582 self.unsafe_get().is_html_document
3583 }
3584
3585 #[inline]
3586 pub(crate) fn quirks_mode(self) -> QuirksMode {
3587 self.unsafe_get().quirks_mode.get()
3588 }
3589
3590 #[inline]
3591 pub(crate) fn shared_style_locks(self) -> &'dom SharedRwLocks {
3592 self.unsafe_get().shared_style_locks()
3593 }
3594
3595 #[inline]
3596 pub(crate) fn flush_shadow_root_stylesheets_if_necessary(
3597 self,
3598 stylist: &mut Stylist,
3599 guard: &SharedRwLockReadGuard,
3600 ) {
3601 (*self.unsafe_get()).flush_shadow_root_stylesheets_if_necessary_for_layout(stylist, guard)
3602 }
3603
3604 pub(crate) fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3605 self.unsafe_get().id_map.get_all_for_layout(id)
3606 }
3607
3608 #[expect(unsafe_code)]
3609 pub(crate) fn url_for_layout(self) -> ServoUrl {
3610 unsafe { self.unsafe_get().url.borrow_for_layout() }.clone()
3611 }
3612}
3613
3614pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3618 host_suffix_string: &str,
3619 original_host: Host,
3620) -> Option<Host> {
3621 if host_suffix_string.is_empty() {
3623 return None;
3624 }
3625
3626 let host = match Host::parse(host_suffix_string) {
3628 Ok(host) => host,
3629 Err(_) => return None,
3630 };
3631
3632 if host != original_host {
3634 let host = match host {
3636 Host::Domain(ref host) => host,
3637 _ => return None,
3638 };
3639 let original_host = match original_host {
3640 Host::Domain(ref original_host) => original_host,
3641 _ => return None,
3642 };
3643
3644 let index = original_host.len().checked_sub(host.len())?;
3646 let (prefix, suffix) = original_host.split_at(index);
3647
3648 if !prefix.ends_with('.') {
3649 return None;
3650 }
3651 if suffix != host {
3652 return None;
3653 }
3654
3655 if is_pub_domain(host) {
3657 return None;
3658 }
3659 }
3660
3661 Some(host)
3663}
3664
3665fn url_has_network_scheme(url: &ServoUrl) -> bool {
3667 matches!(url.scheme(), "ftp" | "http" | "https")
3668}
3669
3670#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3671pub(crate) enum HasBrowsingContext {
3672 No,
3673 Yes,
3674}
3675
3676impl Document {
3677 #[allow(clippy::too_many_arguments)]
3678 pub(crate) fn new_inherited(
3679 window: &Window,
3680 has_browsing_context: HasBrowsingContext,
3681 url: Option<ServoUrl>,
3682 about_base_url: Option<ServoUrl>,
3683 origin: MutableOrigin,
3684 is_html_document: IsHTMLDocument,
3685 content_type: Option<Mime>,
3686 last_modified: Option<String>,
3687 activity: DocumentActivity,
3688 source: DocumentSource,
3689 doc_loader: DocumentLoader,
3690 referrer: Option<String>,
3691 status_code: Option<u16>,
3692 canceller: FetchCanceller,
3693 is_initial_about_blank: bool,
3694 allow_declarative_shadow_roots: bool,
3695 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3696 has_trustworthy_ancestor_origin: bool,
3697 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3698 creation_sandboxing_flag_set: SandboxingFlagSet,
3699 timeline: &DocumentTimeline,
3700 pipeline_id: PipelineId,
3701 image_cache: StdArc<dyn ImageCache>,
3702 ) -> Document {
3703 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3704
3705 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3706 (DocumentReadyState::Loading, false)
3707 } else {
3708 (DocumentReadyState::Complete, true)
3709 };
3710
3711 let frame_type = match window.is_top_level() {
3712 true => TimerMetadataFrameType::RootWindow,
3713 false => TimerMetadataFrameType::IFrame,
3714 };
3715 let interactive_time = ProgressiveWebMetrics::new(
3716 window.time_profiler_chan().clone(),
3717 url.clone(),
3718 frame_type,
3719 );
3720
3721 let content_type = content_type.unwrap_or_else(|| {
3722 match is_html_document {
3723 IsHTMLDocument::HTMLDocument => "text/html",
3725 IsHTMLDocument::NonHTMLDocument => "application/xml",
3727 }
3728 .parse()
3729 .unwrap()
3730 });
3731
3732 let encoding = content_type
3733 .get_parameter(CHARSET)
3734 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3735 .unwrap_or(UTF_8);
3736
3737 let has_focus = window.parent_info().is_none();
3738 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3739 let shared_style_locks = window.script_thread().shared_style_locks().clone();
3740
3741 Document {
3742 node: Node::new_document_node(),
3743 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3744 window: Dom::from_ref(window),
3745 has_browsing_context,
3746 implementation: Default::default(),
3747 content_type,
3748 last_modified,
3749 url: DomRefCell::new(url),
3750 about_base_url: DomRefCell::new(about_base_url),
3751 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3753 event_handler: DocumentEventHandler::new(window),
3754 focus_handler: DocumentFocusHandler::new(window, has_focus),
3755 embedder_controls: DocumentEmbedderControls::new(window),
3756 id_map: TreeOrderedIndexMap::id(),
3757 name_map: TreeOrderedIndexMap::name(),
3758 encoding: Cell::new(encoding),
3760 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3761 activity: Cell::new(activity),
3762 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3763 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3764 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3765 images: Default::default(),
3766 embeds: Default::default(),
3767 links: Default::default(),
3768 forms: Default::default(),
3769 scripts: Default::default(),
3770 anchors: Default::default(),
3771 applets: Default::default(),
3772 iframes: RefCell::new(IFrameCollection::new()),
3773 shared_style_locks,
3774 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3775 stylesheet_list: MutNullableDom::new(None),
3776 ready_state: Cell::new(ready_state),
3777 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3778 current_script: Default::default(),
3779 current_the_end_loading_phase: Default::default(),
3780 pending_parsing_blocking_script: Default::default(),
3781 script_blocking_stylesheet_set: Default::default(),
3782 render_blocking_element_count: Default::default(),
3783 deferred_scripts: Default::default(),
3784 asap_in_order_scripts_list: Default::default(),
3785 asap_scripts_set: Default::default(),
3786 animation_frame_ident: Cell::new(0),
3787 animation_frame_list: DomRefCell::new(VecDeque::new()),
3788 running_animation_callbacks: Cell::new(false),
3789 loader: DomRefCell::new(doc_loader),
3790 current_parser: Default::default(),
3791 base_element: Default::default(),
3792 target_base_element: Default::default(),
3793 appropriate_template_contents_owner_document: Default::default(),
3794 pending_restyles: DomRefCell::new(FxHashMap::default()),
3795 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3796 origin: DomRefCell::new(origin),
3797 referrer,
3798 target_element: MutNullableDom::new(None),
3799 policy_container: DomRefCell::new(PolicyContainer::default()),
3800 preloaded_resources: Default::default(),
3801 ignore_destructive_writes_counter: Default::default(),
3802 ignore_opens_during_unload_counter: Default::default(),
3803 spurious_animation_frames: Cell::new(0),
3804 fullscreen_element: MutNullableDom::new(None),
3805 form_id_listener_map: Default::default(),
3806 interactive_time: DomRefCell::new(interactive_time),
3807 tti_window: DomRefCell::new(InteractiveWindow::default()),
3808 canceller,
3809 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3810 page_showing: Cell::new(false),
3811 salvageable: Cell::new(true),
3812 active_parser_was_aborted: Cell::new(false),
3813 fired_unload: Cell::new(false),
3814 responsive_images: Default::default(),
3815 navigation_timing: Default::default(),
3816 resource_fetch_timing: RefCell::new(None),
3817 completely_loaded: Cell::new(false),
3818 script_and_layout_blockers: Cell::new(0),
3819 delayed_tasks: Default::default(),
3820 shadow_roots: DomRefCell::new(HashSet::new()),
3821 shadow_roots_styles_changed: Cell::new(false),
3822 media_controls: DomRefCell::new(HashMap::new()),
3823 dirty_canvases: DomRefCell::new(Default::default()),
3824 has_pending_animated_image_update: Cell::new(false),
3825 selection: MutNullableDom::new(None),
3826 timeline: Dom::from_ref(timeline),
3827 animations: Animations::new(),
3828 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3829 dirty_root: Default::default(),
3830 declarative_refresh: Default::default(),
3831 resize_observers: Default::default(),
3832 fonts: Default::default(),
3833 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3834 status_code,
3835 is_initial_about_blank: Cell::new(is_initial_about_blank),
3836 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3837 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3838 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3839 intersection_observer_task_queued: Cell::new(false),
3840 intersection_observers: Default::default(),
3841 highlighted_dom_node: Default::default(),
3842 adopted_stylesheets: Default::default(),
3843 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3844 pending_scroll_events: Default::default(),
3845 rendering_update_reasons: Default::default(),
3846 waiting_on_canvas_image_updates: Cell::new(false),
3847 root_removal_noted: Cell::new(true),
3848 current_rendering_epoch: Default::default(),
3849 custom_element_reaction_stack,
3850 active_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3851 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3852 favicon: RefCell::new(None),
3853 websockets: DOMTracker::new(),
3854 details_name_groups: Default::default(),
3855 protocol_handler_automation_mode: Default::default(),
3856 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3857 state_override: Default::default(),
3858 value_override: Default::default(),
3859 default_single_line_container_name: Default::default(),
3860 css_styling_flag: Default::default(),
3861 accessibility_data: Default::default(),
3862 iframe_load_in_progress: Default::default(),
3863 mute_iframe_load: Default::default(),
3864 timers: OneshotTimers::new(window.upcast()),
3865 pipeline_id,
3866 task_manager: Rc::new(TaskManager::new(
3867 Some(window.event_loop_sender()),
3868 pipeline_id,
3869 None,
3870 )),
3871 image_cache,
3872 history: Default::default(),
3873 }
3874 }
3875
3876 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3878 if let Some(csp_list) = self.get_csp_list().as_ref() {
3879 for policy in &csp_list.0 {
3880 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3881 policy.disposition == PolicyDisposition::Enforce
3882 {
3883 return InsecureRequestsPolicy::Upgrade;
3884 }
3885 }
3886 }
3887
3888 self.inherited_insecure_requests_policy
3889 .get()
3890 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3891 }
3892
3893 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3895 &self.event_handler
3896 }
3897
3898 pub(crate) fn focus_handler(&self) -> &DocumentFocusHandler {
3900 &self.focus_handler
3901 }
3902
3903 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3905 &self.embedder_controls
3906 }
3907
3908 fn has_pending_scroll_events(&self) -> bool {
3911 !self.pending_scroll_events.borrow().is_empty()
3912 }
3913
3914 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3917 self.rendering_update_reasons
3918 .set(self.rendering_update_reasons.get().union(reason));
3919 }
3920
3921 pub(crate) fn clear_rendering_update_reasons(&self) {
3923 self.rendering_update_reasons
3924 .set(RenderingUpdateReason::empty())
3925 }
3926
3927 pub(crate) fn add_script_and_layout_blocker(&self) {
3934 self.script_and_layout_blockers
3935 .set(self.script_and_layout_blockers.get() + 1);
3936 }
3937
3938 pub(crate) fn remove_script_and_layout_blocker(&self, cx: &mut JSContext) {
3942 assert!(self.script_and_layout_blockers.get() > 0);
3943 self.script_and_layout_blockers
3944 .set(self.script_and_layout_blockers.get() - 1);
3945 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3946 {
3947 let task = self.delayed_tasks.borrow_mut().remove(0);
3948 task.run_box(cx);
3949 }
3950 }
3951
3952 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3954 self.delayed_tasks.borrow_mut().push(Box::new(task));
3955 }
3956
3957 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3960 assert_eq!(
3961 self.script_and_layout_blockers.get(),
3962 0,
3963 "Attempt to use script or layout while DOM not in a stable state"
3964 );
3965 }
3966
3967 #[allow(clippy::too_many_arguments)]
3968 pub(crate) fn new(
3969 cx: &mut JSContext,
3970 window: &Window,
3971 has_browsing_context: HasBrowsingContext,
3972 url: Option<ServoUrl>,
3973 about_base_url: Option<ServoUrl>,
3974 origin: MutableOrigin,
3975 doctype: IsHTMLDocument,
3976 content_type: Option<Mime>,
3977 last_modified: Option<String>,
3978 activity: DocumentActivity,
3979 source: DocumentSource,
3980 doc_loader: DocumentLoader,
3981 referrer: Option<String>,
3982 status_code: Option<u16>,
3983 canceller: FetchCanceller,
3984 is_initial_about_blank: bool,
3985 allow_declarative_shadow_roots: bool,
3986 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3987 has_trustworthy_ancestor_origin: bool,
3988 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3989 creation_sandboxing_flag_set: SandboxingFlagSet,
3990 pipeline_id: PipelineId,
3991 image_cache: StdArc<dyn ImageCache>,
3992 ) -> DomRoot<Document> {
3993 Self::new_with_proto(
3994 cx,
3995 window,
3996 None,
3997 has_browsing_context,
3998 url,
3999 about_base_url,
4000 origin,
4001 doctype,
4002 content_type,
4003 last_modified,
4004 activity,
4005 source,
4006 doc_loader,
4007 referrer,
4008 status_code,
4009 canceller,
4010 is_initial_about_blank,
4011 allow_declarative_shadow_roots,
4012 inherited_insecure_requests_policy,
4013 has_trustworthy_ancestor_origin,
4014 custom_element_reaction_stack,
4015 creation_sandboxing_flag_set,
4016 pipeline_id,
4017 image_cache,
4018 )
4019 }
4020
4021 #[allow(clippy::too_many_arguments)]
4022 fn new_with_proto(
4023 cx: &mut JSContext,
4024 window: &Window,
4025 proto: Option<HandleObject>,
4026 has_browsing_context: HasBrowsingContext,
4027 url: Option<ServoUrl>,
4028 about_base_url: Option<ServoUrl>,
4029 origin: MutableOrigin,
4030 doctype: IsHTMLDocument,
4031 content_type: Option<Mime>,
4032 last_modified: Option<String>,
4033 activity: DocumentActivity,
4034 source: DocumentSource,
4035 doc_loader: DocumentLoader,
4036 referrer: Option<String>,
4037 status_code: Option<u16>,
4038 canceller: FetchCanceller,
4039 is_initial_about_blank: bool,
4040 allow_declarative_shadow_roots: bool,
4041 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4042 has_trustworthy_ancestor_origin: bool,
4043 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4044 creation_sandboxing_flag_set: SandboxingFlagSet,
4045 pipeline_id: PipelineId,
4046 image_cache: StdArc<dyn ImageCache>,
4047 ) -> DomRoot<Document> {
4048 let timeline = DocumentTimeline::new(cx, window);
4049 let document = reflect_dom_object_with_proto_and_cx(
4050 Box::new(Document::new_inherited(
4051 window,
4052 has_browsing_context,
4053 url,
4054 about_base_url,
4055 origin,
4056 doctype,
4057 content_type,
4058 last_modified,
4059 activity,
4060 source,
4061 doc_loader,
4062 referrer,
4063 status_code,
4064 canceller,
4065 is_initial_about_blank,
4066 allow_declarative_shadow_roots,
4067 inherited_insecure_requests_policy,
4068 has_trustworthy_ancestor_origin,
4069 custom_element_reaction_stack,
4070 creation_sandboxing_flag_set,
4071 &timeline,
4072 pipeline_id,
4073 image_cache,
4074 )),
4075 window,
4076 proto,
4077 cx,
4078 );
4079 {
4080 let node = document.upcast::<Node>();
4081 node.set_owner_doc(&document);
4082 }
4083 document
4084 }
4085
4086 pub(crate) fn get_redirect_count(&self) -> u16 {
4087 self.resource_fetch_timing()
4088 .as_ref()
4089 .map_or(0, |resource_fetch_timing| {
4090 resource_fetch_timing.redirect_count
4091 })
4092 }
4093
4094 pub(crate) fn set_resource_fetch_timing(&self, timing: ResourceFetchTiming) {
4095 self.resource_fetch_timing.replace(Some(timing));
4096 }
4097
4098 pub(crate) fn resource_fetch_timing(&self) -> Ref<'_, Option<ResourceFetchTiming>> {
4099 self.resource_fetch_timing.borrow()
4100 }
4101
4102 pub(crate) fn navigation_timing(&self) -> &NavigationTiming {
4103 &self.navigation_timing
4104 }
4105
4106 pub(crate) fn performance_timing_attribute(
4107 &self,
4108 name: &str,
4109 ) -> Fallible<Option<CrossProcessInstant>> {
4110 Ok(match name {
4111 "unloadEventStart" => self.navigation_timing().unload_event_start.get(),
4112 "unloadEventEnd" => self.navigation_timing().unload_event_end.get(),
4113 "domInteractive" => self.navigation_timing().dom_interactive.get(),
4114 "domContentLoadedEventStart" => self
4115 .navigation_timing()
4116 .dom_content_loaded_event_start
4117 .get(),
4118 "domContentLoadedEventEnd" => {
4119 self.navigation_timing().dom_content_loaded_event_end.get()
4120 },
4121 "domComplete" => self.navigation_timing().dom_complete.get(),
4122 "loadEventStart" => self.navigation_timing().load_event_start.get(),
4123 "loadEventEnd" => self.navigation_timing().load_event_end.get(),
4124 "redirectStart" | "redirectEnd" | "secureConnectionStart" | "responseEnd" => self
4125 .resource_fetch_timing()
4126 .as_ref()
4127 .and_then(|resource_fetch_timing| match name {
4128 "redirectStart" => resource_fetch_timing.redirect_start,
4129 "redirectEnd" => resource_fetch_timing.redirect_end,
4130 "secureConnectionStart" => resource_fetch_timing.secure_connection_start,
4131 "responseEnd" => resource_fetch_timing.response_end,
4132 _ => None,
4133 }),
4134 _ => {
4135 return Err(Error::Operation(Some(format!(
4136 "{name} hasn't been implemented."
4137 ))));
4138 },
4139 })
4140 }
4141
4142 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4143 if name.is_empty() {
4144 return 0;
4145 }
4146 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4147 }
4148
4149 pub(crate) fn nth_element_by_name(
4150 &self,
4151 index: u32,
4152 name: &DOMString,
4153 ) -> Option<DomRoot<Node>> {
4154 if name.is_empty() {
4155 return None;
4156 }
4157 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4158 }
4159
4160 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4163 let element = match node.downcast::<Element>() {
4164 Some(element) => element,
4165 None => return false,
4166 };
4167 if element.namespace() != &ns!(html) {
4168 return false;
4169 }
4170 element.get_name().is_some_and(|n| &*n == name)
4171 }
4172
4173 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4174 let doc = self.GetDocumentElement();
4175 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4176 maybe_node
4177 .iter()
4178 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4179 .filter(|node| callback(node))
4180 .count() as u32
4181 }
4182
4183 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4184 &self,
4185 index: u32,
4186 callback: F,
4187 ) -> Option<DomRoot<Node>> {
4188 let doc = self.GetDocumentElement();
4189 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4190 maybe_node
4191 .iter()
4192 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4193 .filter(|node| callback(node))
4194 .nth(index as usize)
4195 .map(|n| DomRoot::from_ref(&*n))
4196 }
4197
4198 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4199 self.GetDocumentElement().and_then(DomRoot::downcast)
4200 }
4201
4202 pub(crate) fn shared_style_locks(&self) -> &SharedRwLocks {
4204 &self.shared_style_locks
4205 }
4206
4207 pub(crate) fn style_shared_author_lock(&self) -> &SharedRwLock {
4209 &self.shared_style_locks.author
4210 }
4211
4212 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4214 let mut stylesheets = self.stylesheets.borrow_mut();
4221 let have_changed = stylesheets.has_changed();
4222 stylesheets.flush_without_invalidation();
4223 have_changed
4224 }
4225
4226 pub(crate) fn salvageable(&self) -> bool {
4227 self.salvageable.get()
4228 }
4229
4230 pub(crate) fn make_document_unsalvageable(&self) {
4232 self.salvageable.set(false);
4238 }
4239
4240 pub(crate) fn appropriate_template_contents_owner_document(
4242 &self,
4243 cx: &mut JSContext,
4244 ) -> DomRoot<Document> {
4245 self.appropriate_template_contents_owner_document
4246 .or_init(|| {
4247 let doctype = if self.is_html_document {
4248 IsHTMLDocument::HTMLDocument
4249 } else {
4250 IsHTMLDocument::NonHTMLDocument
4251 };
4252 let new_doc = Document::new(
4253 cx,
4254 self.window(),
4255 HasBrowsingContext::No,
4256 None,
4257 None,
4258 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4260 doctype,
4261 None,
4262 None,
4263 DocumentActivity::Inactive,
4264 DocumentSource::NotFromParser,
4265 DocumentLoader::new(&self.loader()),
4266 None,
4267 None,
4268 Default::default(),
4269 false,
4270 self.allow_declarative_shadow_roots(),
4271 Some(self.insecure_requests_policy()),
4272 self.has_trustworthy_ancestor_or_current_origin(),
4273 self.custom_element_reaction_stack.clone(),
4274 self.creation_sandboxing_flag_set(),
4275 self.pipeline_id(),
4276 self.image_cache.clone(),
4277 );
4278 new_doc
4279 .appropriate_template_contents_owner_document
4280 .set(Some(&new_doc));
4281 new_doc
4282 })
4283 }
4284
4285 pub(crate) fn get_element_by_id(&self, no_gc: &NoGC, id: &Atom) -> Option<DomRoot<Element>> {
4286 self.id_map.get(no_gc, self.upcast(), id)
4287 }
4288
4289 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4290 let map = self.pending_restyles.borrow_mut();
4291 RefMut::map(map, |m| {
4292 &mut m
4293 .entry(Dom::from_ref(el))
4294 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4295 .0
4296 })
4297 }
4298
4299 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: AttrRef<'_>) {
4300 let mut entry = self.ensure_pending_restyle(el);
4306 if entry.snapshot.is_none() {
4307 entry.snapshot = Some(Snapshot::new());
4308 }
4309 if attr.local_name() == &local_name!("style") {
4310 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4311 }
4312
4313 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) ||
4314 el.check_style_on_self_or_eager_pseudos(|style| {
4315 if let Some(ref attribute_references) = style.attribute_references {
4316 return attribute_references.contains_key(attr.local_name());
4317 }
4318 false
4319 })
4320 {
4321 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4322 }
4323
4324 let snapshot = entry.snapshot.as_mut().unwrap();
4325 if attr.local_name() == &local_name!("id") {
4326 if snapshot.id_changed {
4327 return;
4328 }
4329 snapshot.id_changed = true;
4330 } else if attr.local_name() == &local_name!("class") {
4331 if snapshot.class_changed {
4332 return;
4333 }
4334 snapshot.class_changed = true;
4335 } else {
4336 snapshot.other_attributes_changed = true;
4337 }
4338 let local_name = style::LocalName::cast(attr.local_name());
4339 if !snapshot.changed_attrs.contains(local_name) {
4340 snapshot.changed_attrs.push(local_name.clone());
4341 }
4342 if snapshot.attrs.is_none() {
4343 let attrs = el
4344 .attrs()
4345 .borrow()
4346 .iter()
4347 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4348 .collect();
4349 snapshot.attrs = Some(attrs);
4350 }
4351 }
4352
4353 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4354 self.policy_container
4355 .borrow_mut()
4356 .set_referrer_policy(policy);
4357 }
4358
4359 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4360 self.policy_container.borrow().get_referrer_policy()
4361 }
4362
4363 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4364 if let Some(ref element) = self.target_element.get() {
4365 element.set_target_state(false);
4366 }
4367
4368 self.target_element.set(node);
4369
4370 if let Some(ref element) = self.target_element.get() {
4371 element.set_target_state(true);
4372 }
4373 }
4374
4375 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4376 self.ignore_destructive_writes_counter
4377 .set(self.ignore_destructive_writes_counter.get() + 1);
4378 }
4379
4380 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4381 self.ignore_destructive_writes_counter
4382 .set(self.ignore_destructive_writes_counter.get() - 1);
4383 }
4384
4385 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4386 self.ignore_opens_during_unload_counter.get() > 0
4387 }
4388
4389 fn incr_ignore_opens_during_unload_counter(&self) {
4390 self.ignore_opens_during_unload_counter
4391 .set(self.ignore_opens_during_unload_counter.get() + 1);
4392 }
4393
4394 fn decr_ignore_opens_during_unload_counter(&self) {
4395 self.ignore_opens_during_unload_counter
4396 .set(self.ignore_opens_during_unload_counter.get() - 1);
4397 }
4398
4399 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4400 self.fullscreen_element.set(element);
4401 }
4402
4403 fn reset_form_owner_for_listeners(&self, cx: &mut JSContext, id: &Atom) {
4404 let map = self.form_id_listener_map.borrow();
4405 if let Some(listeners) = map.get(id) {
4406 for listener in listeners {
4407 listener
4408 .as_maybe_form_control()
4409 .expect("Element must be a form control")
4410 .reset_form_owner(cx);
4411 }
4412 }
4413 }
4414
4415 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4416 self.shadow_roots
4417 .borrow_mut()
4418 .insert(Dom::from_ref(shadow_root));
4419 self.invalidate_shadow_roots_stylesheets();
4420 }
4421
4422 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4423 let mut shadow_roots = self.shadow_roots.borrow_mut();
4424 shadow_roots.remove(&Dom::from_ref(shadow_root));
4425 }
4426
4427 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4428 self.shadow_roots_styles_changed.set(true);
4429 }
4430
4431 pub(crate) fn flush_shadow_root_stylesheets_if_necessary_for_layout(
4432 &self,
4433 stylist: &mut Stylist,
4434 guard: &SharedRwLockReadGuard,
4435 ) {
4436 if !self.shadow_roots_styles_changed.get() {
4437 return;
4438 }
4439 #[expect(unsafe_code)]
4440 unsafe {
4441 for shadow_root in self.shadow_roots.borrow_for_layout().iter() {
4442 let layout: LayoutDom<'_, _> = shadow_root.to_layout();
4443 layout.flush_stylesheets_for_layout(stylist, guard);
4444 }
4445 }
4446 self.shadow_roots_styles_changed.set(false);
4447 }
4448
4449 pub(crate) fn stylesheet_count(&self) -> usize {
4450 self.stylesheets.borrow().len()
4451 }
4452
4453 pub(crate) fn stylesheet_at(
4454 &self,
4455 cx: &mut JSContext,
4456 index: usize,
4457 ) -> Option<DomRoot<CSSStyleSheet>> {
4458 let stylesheets = self.stylesheets.borrow();
4459
4460 stylesheets
4461 .get(Origin::Author, index)
4462 .and_then(|s| s.owner.get_cssom_object(cx))
4463 }
4464
4465 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(
4472 &self,
4473 cx: &mut JSContext,
4474 owner_node: &Element,
4475 sheet: Arc<Stylesheet>,
4476 ) {
4477 let insertion_point = {
4478 let stylesheets = &mut *self.stylesheets.borrow_mut();
4479
4480 stylesheets
4482 .iter()
4483 .map(|(sheet, _origin)| sheet)
4484 .find(|sheet_in_doc| {
4485 match &sheet_in_doc.owner {
4486 StylesheetSource::Element(other_node) => {
4487 owner_node.upcast::<Node>().is_before(other_node.upcast())
4488 },
4489 StylesheetSource::Constructed(_) => true,
4492 }
4493 })
4494 .cloned()
4495 };
4496
4497 if self.has_browsing_context() {
4498 self.add_stylesheet_to_stylist(
4499 cx,
4500 sheet.clone(),
4501 insertion_point.as_ref().map(|s| s.sheet.clone()),
4502 );
4503 }
4504
4505 let stylesheets = &mut *self.stylesheets.borrow_mut();
4506 DocumentOrShadowRoot::add_stylesheet(
4507 StylesheetSource::Element(Dom::from_ref(owner_node)),
4508 StylesheetSetRef::Document(stylesheets),
4509 sheet,
4510 insertion_point,
4511 self.style_shared_author_lock(),
4512 );
4513 }
4514
4515 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4520 pub(crate) fn append_constructed_stylesheet(
4521 &self,
4522 cx: &mut JSContext,
4523 cssom_stylesheet: &CSSStyleSheet,
4524 ) {
4525 debug_assert!(cssom_stylesheet.is_constructed());
4526
4527 let sheet = cssom_stylesheet.style_stylesheet().clone();
4528 let insertion_point = {
4529 let stylesheets = &mut *self.stylesheets.borrow_mut();
4530
4531 stylesheets
4532 .iter()
4533 .last()
4534 .map(|(sheet, _origin)| sheet)
4535 .cloned()
4536 };
4537
4538 if self.has_browsing_context() {
4539 self.add_stylesheet_to_stylist(
4540 cx,
4541 sheet.clone(),
4542 insertion_point.as_ref().map(|s| s.sheet.clone()),
4543 );
4544 }
4545
4546 let stylesheets = &mut *self.stylesheets.borrow_mut();
4547 DocumentOrShadowRoot::add_stylesheet(
4548 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4549 StylesheetSetRef::Document(stylesheets),
4550 sheet,
4551 insertion_point,
4552 self.style_shared_author_lock(),
4553 );
4554 }
4555
4556 pub(crate) fn switch_font_face_set_to_loading_if_needed(&self, cx: &mut JSContext) {
4557 if self.window.font_context().web_fonts_still_loading() != 0 &&
4558 let Some(font_face_set) = self.fonts.get()
4559 {
4560 font_face_set.switch_to_loading(cx);
4561 }
4562 }
4563
4564 pub(crate) fn add_stylesheet_to_stylist(
4565 &self,
4566 cx: &mut JSContext,
4567 stylesheet: Arc<Stylesheet>,
4568 before_stylesheet: Option<Arc<Stylesheet>>,
4569 ) {
4570 self.window
4571 .layout_mut()
4572 .add_stylesheet(stylesheet, before_stylesheet);
4573 self.switch_font_face_set_to_loading_if_needed(cx);
4574 }
4575
4576 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4579 if self.has_browsing_context() {
4580 self.window
4581 .layout_mut()
4582 .remove_stylesheet(stylesheet.clone());
4583 }
4584
4585 DocumentOrShadowRoot::remove_stylesheet(
4586 owner,
4587 stylesheet,
4588 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4589 )
4590 }
4591
4592 pub(crate) fn get_elements_with_id(
4593 &self,
4594 cx: &mut JSContext,
4595 id: &Atom,
4596 ) -> Ref<'_, [Dom<Element>]> {
4597 self.id_map.get_all(cx.no_gc(), self.upcast(), id)
4598 }
4599
4600 pub(crate) fn get_elements_with_name(
4601 &self,
4602 cx: &mut JSContext,
4603 name: &Atom,
4604 ) -> Ref<'_, [Dom<Element>]> {
4605 self.name_map.get_all(cx.no_gc(), self.upcast(), name)
4606 }
4607
4608 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4609 self.pending_restyles
4610 .borrow_mut()
4611 .drain()
4612 .filter_map(|(elem, restyle)| {
4613 let node = elem.upcast::<Node>();
4614 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4615 return None;
4616 }
4617 node.note_dirty_descendants();
4618 Some((node.to_trusted_node_address(), restyle.0))
4619 })
4620 .collect()
4621 }
4622
4623 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: TimeDuration) {
4624 self.timeline.advance_specific(delta);
4625 let current_timeline_value = self.current_animation_timeline_value();
4626 self.animations
4627 .update_for_new_timeline_value(&self.window, current_timeline_value);
4628 }
4629
4630 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4631 let current_timeline_value = self.current_animation_timeline_value();
4632 self.animations
4633 .mark_animating_nodes_as_dirty(current_timeline_value);
4634 }
4635
4636 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4637 self.timeline
4638 .upcast::<AnimationTimeline>()
4639 .current_time_in_seconds()
4640 }
4641
4642 pub(crate) fn animations(&self) -> &Animations {
4643 &self.animations
4644 }
4645
4646 pub(crate) fn update_animations_post_reflow(&self) {
4647 let current_timeline_value = self.current_animation_timeline_value();
4648 self.animations
4649 .do_post_reflow_update(&self.window, current_timeline_value);
4650 self.image_animation_manager
4651 .borrow_mut()
4652 .do_post_reflow_update(&self.window, current_timeline_value);
4653 }
4654
4655 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4656 self.animations.cancel_animations_for_node(node);
4657 self.image_animation_manager
4658 .borrow_mut()
4659 .cancel_animations_for_node(node);
4660 }
4661
4662 pub(crate) fn update_animations_and_send_events(&self, cx: &mut CurrentRealm) {
4664 if !self.layout_animations_test_enabled {
4666 self.timeline.update(self.window());
4667 }
4668
4669 let current_timeline_value = self.current_animation_timeline_value();
4676 self.animations
4677 .update_for_new_timeline_value(&self.window, current_timeline_value);
4678 self.maybe_mark_animating_nodes_as_dirty();
4679
4680 self.window().perform_a_microtask_checkpoint(cx);
4682
4683 self.animations().send_pending_events(self.window(), cx);
4685 }
4686
4687 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4688 self.image_animation_manager.borrow()
4689 }
4690
4691 pub(crate) fn set_has_pending_animated_image_update(&self) {
4692 self.has_pending_animated_image_update.set(true);
4693 }
4694
4695 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8], from_meta_element: bool) {
4697 if self.will_declaratively_refresh() {
4699 return;
4700 }
4701
4702 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4704 Regex::new(
4708 r#"(?xs)
4709 ^
4710 \s* # 3
4711 ((?<time>[0-9]+)|\.) # 5-6
4712 [0-9.]* # 8
4713 (
4714 (
4715 (\s*;|\s*,|\s) # 10.3
4716 \s* # 10.4
4717 )
4718 (
4719 (
4720 (U|u)(R|r)(L|l) # 11.2-11.4
4721 \s*=\s* # 11.5-11.7
4722 )?
4723 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4724 |
4725 (?<url4>(?s-u:.)*)
4726 )
4727 )?
4728 $
4729 "#,
4730 )
4731 .unwrap()
4732 });
4733
4734 let mut url_record = self.url();
4736 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4737 captures
4738 } else {
4739 return;
4740 };
4741 let time = if let Some(time_string) = captures.name("time") {
4742 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4743 } else {
4744 0
4745 };
4746 let captured_url = captures.name("url1").or(captures
4747 .name("url2")
4748 .or(captures.name("url3").or(captures.name("url4"))));
4749
4750 if let Some(url_match) = captured_url {
4752 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4753 Some(&url_record),
4754 &String::from_utf8_lossy(url_match.as_bytes()),
4755 ) {
4756 info!("Refresh to {}", url.debug_compact());
4757 url
4758 } else {
4759 return;
4761 };
4762 if url_record.scheme() == "javascript" {
4764 return;
4765 }
4766 }
4767 if self.completely_loaded() {
4769 self.window.as_global_scope().schedule_callback(
4770 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4771 window: DomRoot::from_ref(self.window()),
4772 url: url_record,
4773 from_meta_element,
4774 }),
4775 Duration::from_secs(time),
4776 );
4777 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4778 } else {
4779 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4780 url: url_record,
4781 time,
4782 from_meta_element,
4783 });
4784 }
4785 }
4786
4787 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4788 self.declarative_refresh.borrow().is_some()
4789 }
4790 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4791 *self.declarative_refresh.borrow_mut() = Some(refresh);
4792 }
4793
4794 fn update_visibility_state(
4796 &self,
4797 cx: &mut JSContext,
4798 visibility_state: DocumentVisibilityState,
4799 ) {
4800 if self.visibility_state.get() == visibility_state {
4802 return;
4803 }
4804 self.visibility_state.set(visibility_state);
4806 let entry = VisibilityStateEntry::new(
4809 cx,
4810 &self.global(),
4811 visibility_state,
4812 CrossProcessInstant::now(),
4813 );
4814 self.window
4815 .Performance(cx)
4816 .queue_entry(entry.upcast::<PerformanceEntry>());
4817
4818 #[cfg(feature = "gamepad")]
4829 if visibility_state == DocumentVisibilityState::Hidden {
4830 self.window
4831 .Navigator(cx)
4832 .GetGamepads(cx)
4833 .unwrap_or_default()
4834 .iter_mut()
4835 .for_each(|gamepad| {
4836 if let Some(g) = gamepad {
4837 g.vibration_actuator().handle_visibility_change();
4838 }
4839 });
4840 }
4841
4842 self.upcast::<EventTarget>()
4844 .fire_bubbling_event(cx, atom!("visibilitychange"));
4845 }
4846
4847 pub(crate) fn is_initial_about_blank(&self) -> bool {
4849 self.is_initial_about_blank.get()
4850 }
4851
4852 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4854 self.allow_declarative_shadow_roots.get()
4855 }
4856
4857 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4858 self.has_trustworthy_ancestor_origin.get()
4859 }
4860
4861 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4862 self.has_trustworthy_ancestor_origin.get() ||
4863 self.origin().immutable().is_potentially_trustworthy()
4864 }
4865
4866 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4867 self.highlighted_dom_node.set(node);
4868 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4869 }
4870
4871 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4872 self.highlighted_dom_node.get()
4873 }
4874
4875 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4876 self.custom_element_reaction_stack.clone()
4877 }
4878
4879 pub(crate) fn active_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4880 self.active_sandboxing_flag_set.get()
4881 }
4882
4883 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4884 self.active_sandboxing_flag_set.get().contains(flag)
4885 }
4886
4887 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4888 self.active_sandboxing_flag_set.set(flags)
4889 }
4890
4891 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4892 self.creation_sandboxing_flag_set.get()
4893 }
4894
4895 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4896 &self,
4897 ) -> SandboxingFlagSet {
4898 self.window()
4899 .window_proxy()
4900 .frame_element()
4901 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4902 .map(HTMLIFrameElement::sandboxing_flag_set)
4903 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4904 }
4905
4906 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4907 self.window()
4908 .scrolling_box_query(None, flags)
4909 .expect("We should always have a ScrollingBox for the Viewport")
4910 }
4911
4912 pub(crate) fn notify_embedder_favicon(&self) {
4913 if let Some(ref image) = *self.favicon.borrow() {
4914 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4915 }
4916 }
4917
4918 pub(crate) fn set_favicon(&self, favicon: Image) {
4919 *self.favicon.borrow_mut() = Some(favicon);
4920 self.notify_embedder_favicon();
4921 }
4922
4923 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
4924 self.fullscreen_element.get()
4925 }
4926
4927 pub(crate) fn state_override(&self, command_name: &CommandName) -> Option<bool> {
4929 self.state_override.borrow().get(command_name).copied()
4930 }
4931
4932 pub(crate) fn set_state_override(&self, command_name: CommandName, state: Option<bool>) {
4934 if let Some(state) = state {
4935 self.state_override.borrow_mut().insert(command_name, state);
4936 } else {
4937 self.value_override.borrow_mut().remove(&command_name);
4938 }
4939 }
4940
4941 pub(crate) fn value_override(&self, command_name: &CommandName) -> Option<DOMString> {
4943 self.value_override.borrow().get(command_name).cloned()
4944 }
4945
4946 pub(crate) fn set_value_override(&self, command_name: CommandName, value: Option<DOMString>) {
4948 if let Some(value) = value {
4949 self.value_override.borrow_mut().insert(command_name, value);
4950 } else {
4951 self.value_override.borrow_mut().remove(&command_name);
4952 }
4953 }
4954
4955 pub(crate) fn clear_command_overrides(&self) {
4958 self.state_override.borrow_mut().clear();
4959 self.value_override.borrow_mut().clear();
4960 }
4961
4962 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
4964 self.default_single_line_container_name.get()
4965 }
4966
4967 pub(crate) fn set_default_single_line_container_name(
4969 &self,
4970 value: DefaultSingleLineContainerName,
4971 ) {
4972 self.default_single_line_container_name.set(value)
4973 }
4974
4975 pub(crate) fn css_styling_flag(&self) -> bool {
4977 self.css_styling_flag.get()
4978 }
4979
4980 pub(crate) fn set_css_styling_flag(&self, value: bool) {
4982 self.css_styling_flag.set(value)
4983 }
4984
4985 pub(crate) fn mute_iframe_load_flag(&self) -> bool {
4986 self.mute_iframe_load.get()
4987 }
4988
4989 pub(crate) fn set_iframe_load_in_progress(&self, value: bool) {
4990 self.iframe_load_in_progress.set(value)
4991 }
4992}
4993
4994impl DocumentMethods<crate::DomTypeHolder> for Document {
4995 fn Constructor(
4997 cx: &mut JSContext,
4998 window: &Window,
4999 proto: Option<HandleObject>,
5000 ) -> Fallible<DomRoot<Document>> {
5001 let doc = window.Document();
5003 let docloader = DocumentLoader::new(&doc.loader());
5004 Ok(Document::new_with_proto(
5005 cx,
5006 window,
5007 proto,
5008 HasBrowsingContext::No,
5009 None,
5010 None,
5011 doc.origin().clone(),
5012 IsHTMLDocument::NonHTMLDocument,
5013 None,
5014 None,
5015 DocumentActivity::Inactive,
5016 DocumentSource::NotFromParser,
5017 docloader,
5018 None,
5019 None,
5020 Default::default(),
5021 false,
5022 doc.allow_declarative_shadow_roots(),
5023 Some(doc.insecure_requests_policy()),
5024 doc.has_trustworthy_ancestor_or_current_origin(),
5025 doc.custom_element_reaction_stack(),
5026 doc.active_sandboxing_flag_set.get(),
5027 doc.pipeline_id(),
5028 doc.image_cache(),
5029 ))
5030 }
5031
5032 fn ParseHTMLUnsafe(
5034 cx: &mut JSContext,
5035 window: &Window,
5036 s: TrustedHTMLOrString,
5037 options: &SetHTMLUnsafeOptions,
5038 ) -> Fallible<DomRoot<Self>> {
5039 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
5043 cx,
5044 window.as_global_scope(),
5045 s,
5046 "Document parseHTMLUnsafe",
5047 )?;
5048
5049 let url = window.get_url();
5050 let doc = window.Document();
5051 let loader = DocumentLoader::new(&doc.loader());
5052
5053 let content_type = "text/html"
5054 .parse()
5055 .expect("Supported type is not a MIME type");
5056 let document = Document::new(
5059 cx,
5060 window,
5061 HasBrowsingContext::No,
5062 Some(ServoUrl::parse("about:blank").unwrap()),
5063 None,
5064 doc.origin().clone(),
5065 IsHTMLDocument::HTMLDocument,
5066 Some(content_type),
5067 None,
5068 DocumentActivity::Inactive,
5069 DocumentSource::FromParser,
5070 loader,
5071 None,
5072 None,
5073 Default::default(),
5074 false,
5075 true,
5076 Some(doc.insecure_requests_policy()),
5077 doc.has_trustworthy_ancestor_or_current_origin(),
5078 doc.custom_element_reaction_stack(),
5079 doc.creation_sandboxing_flag_set(),
5080 doc.pipeline_id(),
5081 doc.image_cache(),
5082 );
5083 ServoParser::parse_html_document(cx, &document, Some(compliant_html), url, None, None);
5085
5086 let sanitizer = Sanitizer::get_sanitizer_instance_from_options(cx, window, options, false)?;
5089
5090 sanitizer.sanitize(cx, document.upcast(), false)?;
5092
5093 document.set_ready_state(cx, DocumentReadyState::Complete);
5095 Ok(document)
5096 }
5097
5098 fn ParseHTML(
5100 cx: &mut JSContext,
5101 window: &Window,
5102 html: DOMString,
5103 options: &SetHTMLOptions,
5104 ) -> Fallible<DomRoot<Document>> {
5105 let url = window.get_url();
5108 let doc = window.Document();
5109 let loader = DocumentLoader::new(&doc.loader());
5110 let content_type = "text/html"
5111 .parse()
5112 .expect("Supported type is not a MIME type");
5113 let document = Document::new(
5114 cx,
5115 window,
5116 HasBrowsingContext::No,
5117 Some(ServoUrl::parse("about:blank").unwrap()),
5118 None,
5119 doc.origin().clone(),
5120 IsHTMLDocument::HTMLDocument,
5121 Some(content_type),
5122 None,
5123 DocumentActivity::Inactive,
5124 DocumentSource::FromParser,
5125 loader,
5126 None,
5127 None,
5128 Default::default(),
5129 false,
5130 true,
5131 Some(doc.insecure_requests_policy()),
5132 doc.has_trustworthy_ancestor_or_current_origin(),
5133 doc.custom_element_reaction_stack(),
5134 doc.creation_sandboxing_flag_set(),
5135 doc.pipeline_id(),
5136 doc.image_cache(),
5137 );
5138
5139 ServoParser::parse_html_document(cx, &document, Some(html), url, None, None);
5141
5142 let sanitizer = Sanitizer::get_sanitizer_instance_from_options(cx, window, options, true)?;
5145
5146 sanitizer.sanitize(cx, document.upcast(), true)?;
5148
5149 Ok(document)
5151 }
5152
5153 fn StyleSheets(&self, cx: &mut JSContext) -> DomRoot<StyleSheetList> {
5155 self.stylesheet_list.or_init(|| {
5156 StyleSheetList::new(
5157 cx,
5158 &self.window,
5159 StyleSheetListOwner::Document(Dom::from_ref(self)),
5160 )
5161 })
5162 }
5163
5164 fn Implementation(&self, cx: &mut JSContext) -> DomRoot<DOMImplementation> {
5166 self.implementation
5167 .or_init(|| DOMImplementation::new(cx, self))
5168 }
5169
5170 fn URL(&self) -> USVString {
5172 USVString(String::from(self.url().as_str()))
5173 }
5174
5175 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5177 self.document_or_shadow_root.active_element(self.upcast())
5178 }
5179
5180 fn GetCustomElementRegistry(&self) -> Option<DomRoot<CustomElementRegistry>> {
5182 self.custom_element_registry()
5183 }
5184
5185 fn HasFocus(&self) -> bool {
5187 if self.window().parent_info().is_none() {
5209 self.is_fully_active()
5211 } else {
5212 self.is_fully_active() && self.focus_handler.has_focus()
5214 }
5215 }
5216
5217 fn Domain(&self) -> DOMString {
5219 match self.origin().effective_domain() {
5221 None => DOMString::new(),
5223 Some(Host::Domain(domain)) => DOMString::from(domain),
5225 Some(host) => DOMString::from(host.to_string()),
5226 }
5227 }
5228
5229 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5231 if !self.has_browsing_context {
5233 return Err(Error::Security(None));
5234 }
5235
5236 if self.has_active_sandboxing_flag(
5239 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5240 ) {
5241 return Err(Error::Security(None));
5242 }
5243
5244 let effective_domain = match self.origin().effective_domain() {
5246 Some(effective_domain) => effective_domain,
5247 None => return Err(Error::Security(None)),
5249 };
5250
5251 let host =
5253 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5254 None => return Err(Error::Security(None)),
5255 Some(host) => host,
5256 };
5257
5258 self.origin().set_domain(host);
5263
5264 Ok(())
5265 }
5266
5267 fn Referrer(&self) -> DOMString {
5269 match self.referrer {
5270 Some(ref referrer) => DOMString::from(referrer.to_string()),
5271 None => DOMString::new(),
5272 }
5273 }
5274
5275 fn DocumentURI(&self) -> USVString {
5277 self.URL()
5278 }
5279
5280 fn CompatMode(&self) -> DOMString {
5282 DOMString::from(match self.quirks_mode.get() {
5283 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5284 QuirksMode::Quirks => "BackCompat",
5285 })
5286 }
5287
5288 fn CharacterSet(&self) -> DOMString {
5290 DOMString::from(self.encoding.get().name())
5291 }
5292
5293 fn Charset(&self) -> DOMString {
5295 self.CharacterSet()
5296 }
5297
5298 fn InputEncoding(&self) -> DOMString {
5300 self.CharacterSet()
5301 }
5302
5303 fn ContentType(&self) -> DOMString {
5305 DOMString::from(self.content_type.to_string())
5306 }
5307
5308 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5310 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5311 }
5312
5313 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5315 self.upcast::<Node>().child_elements().next()
5316 }
5317
5318 fn GetElementsByTagName(
5320 &self,
5321 cx: &mut JSContext,
5322 qualified_name: DOMString,
5323 ) -> DomRoot<HTMLCollection> {
5324 let qualified_name = LocalName::from(qualified_name);
5325 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5326 return DomRoot::from_ref(entry);
5327 }
5328 let result = HTMLCollection::by_qualified_name(
5329 cx,
5330 &self.window,
5331 self.upcast(),
5332 qualified_name.clone(),
5333 );
5334 self.tag_map
5335 .borrow_mut()
5336 .insert(qualified_name, Dom::from_ref(&*result));
5337 result
5338 }
5339
5340 fn GetElementsByTagNameNS(
5342 &self,
5343 cx: &mut JSContext,
5344 maybe_ns: Option<DOMString>,
5345 tag_name: DOMString,
5346 ) -> DomRoot<HTMLCollection> {
5347 let ns = namespace_from_domstring(maybe_ns);
5348 let local = LocalName::from(tag_name);
5349 let qname = QualName::new(None, ns, local);
5350 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5351 return DomRoot::from_ref(collection);
5352 }
5353 let result =
5354 HTMLCollection::by_qual_tag_name(cx, &self.window, self.upcast(), qname.clone());
5355 self.tagns_map
5356 .borrow_mut()
5357 .insert(qname, Dom::from_ref(&*result));
5358 result
5359 }
5360
5361 fn GetElementsByClassName(
5363 &self,
5364 cx: &mut JSContext,
5365 classes: DOMString,
5366 ) -> DomRoot<HTMLCollection> {
5367 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5368 .map(Atom::from)
5369 .collect();
5370 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5371 return DomRoot::from_ref(collection);
5372 }
5373 let result = HTMLCollection::by_atomic_class_name(
5374 cx,
5375 &self.window,
5376 self.upcast(),
5377 class_atoms.clone(),
5378 );
5379 self.classes_map
5380 .borrow_mut()
5381 .insert(class_atoms, Dom::from_ref(&*result));
5382 result
5383 }
5384
5385 fn GetElementById(
5387 &self,
5388 cx: &js::context::JSContext,
5389 id: DOMString,
5390 ) -> Option<DomRoot<Element>> {
5391 self.get_element_by_id(cx, &Atom::from(id))
5392 }
5393
5394 fn CreateElement(
5396 &self,
5397 cx: &mut JSContext,
5398 mut local_name: DOMString,
5399 options: StringOrElementCreationOptions,
5400 ) -> Fallible<DomRoot<Element>> {
5401 if !is_valid_element_local_name(&local_name.str()) {
5404 debug!("Not a valid element name");
5405 return Err(Error::InvalidCharacter(None));
5406 }
5407
5408 if self.is_html_document {
5409 local_name.make_ascii_lowercase();
5410 }
5411
5412 let ns = if self.is_html_document || self.is_xhtml_document() {
5413 ns!(html)
5414 } else {
5415 ns!()
5416 };
5417
5418 let name = QualName::new(None, ns, LocalName::from(local_name));
5419 let is = match options {
5420 StringOrElementCreationOptions::String(_) => None,
5421 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5422 options.is.as_ref().map(LocalName::from)
5423 },
5424 };
5425 Ok(Element::create(
5426 cx,
5427 name,
5428 is,
5429 self,
5430 ElementCreator::ScriptCreated,
5431 CustomElementCreationMode::Synchronous,
5432 None,
5433 ))
5434 }
5435
5436 fn CreateElementNS(
5438 &self,
5439 cx: &mut JSContext,
5440 namespace: Option<DOMString>,
5441 qualified_name: DOMString,
5442 options: StringOrElementCreationOptions,
5443 ) -> Fallible<DomRoot<Element>> {
5444 let context = domname::Context::Element;
5447 let (namespace, prefix, local_name) =
5448 domname::validate_and_extract(namespace, &qualified_name, context)?;
5449
5450 let name = QualName::new(prefix, namespace, local_name);
5453 let is = match options {
5454 StringOrElementCreationOptions::String(_) => None,
5455 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5456 options.is.as_ref().map(LocalName::from)
5457 },
5458 };
5459
5460 Ok(Element::create(
5462 cx,
5463 name,
5464 is,
5465 self,
5466 ElementCreator::ScriptCreated,
5467 CustomElementCreationMode::Synchronous,
5468 None,
5469 ))
5470 }
5471
5472 fn CreateAttribute(
5474 &self,
5475 cx: &mut JSContext,
5476 mut local_name: DOMString,
5477 ) -> Fallible<DomRoot<Attr>> {
5478 if !is_valid_attribute_local_name(&local_name.str()) {
5481 debug!("Not a valid attribute name");
5482 return Err(Error::InvalidCharacter(None));
5483 }
5484 if self.is_html_document {
5485 local_name.make_ascii_lowercase();
5486 }
5487 let name = LocalName::from(local_name);
5488 let value = AttrValue::String("".to_owned());
5489
5490 Ok(Attr::new(
5491 cx,
5492 self,
5493 name.clone(),
5494 value,
5495 name,
5496 ns!(),
5497 None,
5498 None,
5499 ))
5500 }
5501
5502 fn CreateAttributeNS(
5504 &self,
5505 cx: &mut JSContext,
5506 namespace: Option<DOMString>,
5507 qualified_name: DOMString,
5508 ) -> Fallible<DomRoot<Attr>> {
5509 let context = domname::Context::Attribute;
5512 let (namespace, prefix, local_name) =
5513 domname::validate_and_extract(namespace, &qualified_name, context)?;
5514 let value = AttrValue::String("".to_owned());
5515 let qualified_name = LocalName::from(qualified_name);
5516 Ok(Attr::new(
5517 cx,
5518 self,
5519 local_name,
5520 value,
5521 qualified_name,
5522 namespace,
5523 prefix,
5524 None,
5525 ))
5526 }
5527
5528 fn CreateDocumentFragment(&self, cx: &mut JSContext) -> DomRoot<DocumentFragment> {
5530 DocumentFragment::new(cx, self)
5531 }
5532
5533 fn CreateTextNode(&self, cx: &mut JSContext, data: DOMString) -> DomRoot<Text> {
5535 Text::new(cx, data, self)
5536 }
5537
5538 fn CreateCDATASection(
5540 &self,
5541 cx: &mut JSContext,
5542 data: DOMString,
5543 ) -> Fallible<DomRoot<CDATASection>> {
5544 if self.is_html_document {
5546 return Err(Error::NotSupported(None));
5547 }
5548
5549 if data.contains("]]>") {
5551 return Err(Error::InvalidCharacter(None));
5552 }
5553
5554 Ok(CDATASection::new(cx, data, self))
5556 }
5557
5558 fn CreateComment(&self, cx: &mut JSContext, data: DOMString) -> DomRoot<Comment> {
5560 Comment::new(cx, data, self, None)
5561 }
5562
5563 fn CreateProcessingInstruction(
5565 &self,
5566 cx: &mut JSContext,
5567 target: DOMString,
5568 data: DOMString,
5569 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5570 if !matches_name_production(&target.str()) {
5572 return Err(Error::InvalidCharacter(None));
5573 }
5574
5575 if data.contains("?>") {
5577 return Err(Error::InvalidCharacter(None));
5578 }
5579
5580 Ok(ProcessingInstruction::new(cx, target, data, self))
5582 }
5583
5584 fn ImportNode(
5586 &self,
5587 cx: &mut JSContext,
5588 node: &Node,
5589 options: BooleanOrImportNodeOptions,
5590 ) -> Fallible<DomRoot<Node>> {
5591 if node.is::<Document>() || node.is::<ShadowRoot>() {
5593 return Err(Error::NotSupported(None));
5594 }
5595 let (subtree, registry) = match options {
5597 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5600 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5602 let subtree = (!options.selfOnly).into();
5604 let registry = if let Some(registry) = options.customElementRegistry {
5606 let this_registry = self
5609 .custom_element_registry()
5610 .expect("Document must have a custom element registry");
5611 if !registry.is_scoped() && registry != this_registry {
5612 return Err(Error::NotSupported(Some(
5613 "Imported customElementRegistry is not scoped and does not match existing registry.".into()
5614 )));
5615 }
5616 Some(registry)
5617 } else {
5618 None
5619 };
5620 (subtree, registry)
5621 },
5622 };
5623 let registry = registry
5626 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5627
5628 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5631 }
5632
5633 fn AdoptNode(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5635 if node.is::<Document>() {
5637 return Err(Error::NotSupported(None));
5638 }
5639
5640 if node.is::<ShadowRoot>() {
5642 return Err(Error::HierarchyRequest(None));
5643 }
5644
5645 Node::adopt(cx, node, self);
5647
5648 Ok(DomRoot::from_ref(node))
5650 }
5651
5652 fn CreateEvent(
5654 &self,
5655 cx: &mut JSContext,
5656 mut interface: DOMString,
5657 ) -> Fallible<DomRoot<Event>> {
5658 interface.make_ascii_lowercase();
5659 match &*interface.str() {
5660 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5661 cx,
5662 &self.window,
5663 ))),
5664 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5665 CompositionEvent::new_uninitialized(cx, &self.window),
5666 )),
5667 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5668 cx,
5669 self.window.upcast(),
5670 ))),
5671 "events" | "event" | "htmlevents" | "svgevents" => {
5674 Ok(Event::new_uninitialized(cx, self.window.upcast()))
5675 },
5676 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5677 cx,
5678 &self.window,
5679 ))),
5680 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5681 cx,
5682 &self.window,
5683 ))),
5684 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5685 cx,
5686 &self.window,
5687 ))),
5688 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5689 cx,
5690 self.window.upcast(),
5691 ))),
5692 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5693 cx,
5694 &self.window,
5695 ))),
5696 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5697 cx,
5698 &self.window,
5699 "".into(),
5700 ))),
5701 "touchevent" => {
5702 let touches = TouchList::new(cx, &self.window, &[]);
5703 let changed_touches = TouchList::new(cx, &self.window, &[]);
5704 let target_touches = TouchList::new(cx, &self.window, &[]);
5705
5706 Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5707 cx,
5708 &self.window,
5709 &touches,
5710 &changed_touches,
5711 &target_touches,
5712 )))
5713 },
5714 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5715 cx,
5716 &self.window,
5717 ))),
5718 _ => Err(Error::NotSupported(None)),
5719 }
5720 }
5721
5722 fn LastModified(&self) -> DOMString {
5724 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5725 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5731 }))
5732 }
5733
5734 fn CreateRange(&self, cx: &mut JSContext) -> DomRoot<Range> {
5736 Range::new_with_doc(cx, self, None)
5737 }
5738
5739 fn CreateNodeIterator(
5741 &self,
5742 cx: &mut js::context::JSContext,
5743 root: &Node,
5744 what_to_show: u32,
5745 filter: Option<Rc<NodeFilter>>,
5746 ) -> DomRoot<NodeIterator> {
5747 NodeIterator::new(cx, self, root, what_to_show, filter)
5748 }
5749
5750 fn CreateTreeWalker(
5752 &self,
5753 cx: &mut JSContext,
5754 root: &Node,
5755 what_to_show: u32,
5756 filter: Option<Rc<NodeFilter>>,
5757 ) -> DomRoot<TreeWalker> {
5758 TreeWalker::new(cx, self, root, what_to_show, filter)
5759 }
5760
5761 fn Title(&self) -> DOMString {
5763 self.title().unwrap_or_else(|| DOMString::from(""))
5764 }
5765
5766 fn SetTitle(&self, cx: &mut JSContext, title: DOMString) {
5768 let root = match self.GetDocumentElement() {
5769 Some(root) => root,
5770 None => return,
5771 };
5772
5773 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5774 let elem = root
5775 .upcast::<Node>()
5776 .child_elements_unrooted(cx.no_gc())
5777 .find(|node| {
5778 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5779 });
5780 match elem {
5781 Some(elem) => UnrootedDom::upcast::<Node>(elem).as_rooted(),
5782 None => {
5783 let name = QualName::new(None, ns!(svg), local_name!("title"));
5784 let elem = Element::create(
5785 cx,
5786 name,
5787 None,
5788 self,
5789 ElementCreator::ScriptCreated,
5790 CustomElementCreationMode::Synchronous,
5791 None,
5792 );
5793 let parent = root.upcast::<Node>();
5794 let child = elem.upcast::<Node>();
5795 parent
5796 .InsertBefore(cx, child, parent.GetFirstChild().as_deref())
5797 .unwrap()
5798 },
5799 }
5800 } else if root.namespace() == &ns!(html) {
5801 let elem = root
5802 .upcast::<Node>()
5803 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
5804 .find(|node| node.is::<HTMLTitleElement>());
5805 match elem {
5806 Some(elem) => elem.as_rooted(),
5807 None => match self.GetHead() {
5808 Some(head) => {
5809 let name = QualName::new(None, ns!(html), local_name!("title"));
5810 let elem = Element::create(
5811 cx,
5812 name,
5813 None,
5814 self,
5815 ElementCreator::ScriptCreated,
5816 CustomElementCreationMode::Synchronous,
5817 None,
5818 );
5819 head.upcast::<Node>()
5820 .AppendChild(cx, elem.upcast())
5821 .unwrap()
5822 },
5823 None => return,
5824 },
5825 }
5826 } else {
5827 return;
5828 };
5829
5830 node.set_text_content_for_element(cx, Some(title));
5831 }
5832
5833 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5835 self.get_html_element()
5836 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5837 }
5838
5839 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5841 self.current_script.get()
5842 }
5843
5844 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5846 self.get_html_element().and_then(|root| {
5849 let node = root.upcast::<Node>();
5850 node.children()
5851 .find(|child| {
5852 matches!(
5853 child.type_id(),
5854 NodeTypeId::Element(ElementTypeId::HTMLElement(
5855 HTMLElementTypeId::HTMLBodyElement,
5856 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5857 HTMLElementTypeId::HTMLFrameSetElement,
5858 ))
5859 )
5860 })
5861 .map(|node| DomRoot::downcast(node).unwrap())
5862 })
5863 }
5864
5865 fn SetBody(&self, cx: &mut JSContext, new_body: Option<&HTMLElement>) -> ErrorResult {
5867 let new_body = match new_body {
5869 Some(new_body) => new_body,
5870 None => return Err(Error::HierarchyRequest(None)),
5871 };
5872
5873 let node = new_body.upcast::<Node>();
5874 match node.type_id() {
5875 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5876 NodeTypeId::Element(ElementTypeId::HTMLElement(
5877 HTMLElementTypeId::HTMLFrameSetElement,
5878 )) => {},
5879 _ => return Err(Error::HierarchyRequest(None)),
5880 }
5881
5882 let old_body = self.GetBody();
5884 if old_body.as_deref() == Some(new_body) {
5885 return Ok(());
5886 }
5887
5888 match (self.GetDocumentElement(), &old_body) {
5889 (Some(ref root), Some(child)) => {
5892 let root = root.upcast::<Node>();
5893 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
5894 .map(|_| ())
5895 },
5896
5897 (None, _) => Err(Error::HierarchyRequest(None)),
5899
5900 (Some(ref root), &None) => {
5903 let root = root.upcast::<Node>();
5904 root.AppendChild(cx, new_body.upcast()).map(|_| ())
5905 },
5906 }
5907 }
5908
5909 fn GetElementsByName(&self, cx: &mut JSContext, name: DOMString) -> DomRoot<NodeList> {
5911 NodeList::new_elements_by_name_list(cx, self.window(), self, name)
5912 }
5913
5914 fn Images(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5916 self.images.or_init(|| {
5917 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5918 element.is::<HTMLImageElement>()
5919 })
5920 })
5921 }
5922
5923 fn Embeds(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5925 self.embeds.or_init(|| {
5926 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5927 element.is::<HTMLEmbedElement>()
5928 })
5929 })
5930 }
5931
5932 fn Plugins(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5934 self.Embeds(cx)
5935 }
5936
5937 fn Links(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5939 self.links.or_init(|| {
5940 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5941 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5942 element.has_attribute(&local_name!("href"))
5943 })
5944 })
5945 }
5946
5947 fn Forms(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5949 self.forms.or_init(|| {
5950 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5951 element.is::<HTMLFormElement>()
5952 })
5953 })
5954 }
5955
5956 fn Scripts(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5958 self.scripts.or_init(|| {
5959 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5960 element.is::<HTMLScriptElement>()
5961 })
5962 })
5963 }
5964
5965 fn Anchors(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5967 self.anchors.or_init(|| {
5968 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5969 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5970 })
5971 })
5972 }
5973
5974 fn Applets(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5976 self.applets
5977 .or_init(|| HTMLCollection::always_empty(cx, &self.window, self.upcast()))
5978 }
5979
5980 fn GetLocation(&self, cx: &mut JSContext) -> Option<DomRoot<Location>> {
5982 if self.is_fully_active() {
5983 Some(self.window.Location(cx))
5984 } else {
5985 None
5986 }
5987 }
5988
5989 fn Children(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5991 HTMLCollection::children(cx, &self.window, self.upcast())
5992 }
5993
5994 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5996 self.upcast::<Node>().child_elements().next()
5997 }
5998
5999 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
6001 self.upcast::<Node>()
6002 .rev_children()
6003 .find_map(DomRoot::downcast)
6004 }
6005
6006 fn ChildElementCount(&self) -> u32 {
6008 self.upcast::<Node>().child_elements().count() as u32
6009 }
6010
6011 fn Prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
6013 self.upcast::<Node>().prepend(cx, nodes)
6014 }
6015
6016 fn Append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
6018 self.upcast::<Node>().append(cx, nodes)
6019 }
6020
6021 fn ReplaceChildren(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
6023 self.upcast::<Node>().replace_children(cx, nodes)
6024 }
6025
6026 fn MoveBefore(&self, cx: &mut JSContext, node: &Node, child: Option<&Node>) -> ErrorResult {
6028 self.upcast::<Node>().move_before(cx, node, child)
6029 }
6030
6031 fn QuerySelector(
6033 &self,
6034 cx: &mut JSContext,
6035 selectors: DOMString,
6036 ) -> Fallible<Option<DomRoot<Element>>> {
6037 self.upcast::<Node>().query_selector(cx.no_gc(), selectors)
6038 }
6039
6040 fn QuerySelectorAll(
6042 &self,
6043 cx: &mut JSContext,
6044 selectors: DOMString,
6045 ) -> Fallible<DomRoot<NodeList>> {
6046 self.upcast::<Node>().query_selector_all(cx, selectors)
6047 }
6048
6049 fn ReadyState(&self) -> DocumentReadyState {
6051 self.ready_state.get()
6052 }
6053
6054 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
6056 if self.has_browsing_context {
6057 Some(DomRoot::from_ref(&*self.window))
6058 } else {
6059 None
6060 }
6061 }
6062
6063 fn GetCookie(&self) -> Fallible<DOMString> {
6065 if self.is_cookie_averse() {
6066 return Ok(DOMString::new());
6067 }
6068
6069 if !self.origin().is_tuple() {
6070 return Err(Error::Security(None));
6071 }
6072
6073 let url = self.url();
6074 let (tx, rx) =
6075 profile_generic_channel::channel(self.global().time_profiler_chan().clone()).unwrap();
6076 let _ = self
6077 .window
6078 .as_global_scope()
6079 .resource_threads()
6080 .send(GetCookieStringForUrl(url, tx, NonHTTP));
6081 let cookies = rx.recv().unwrap();
6082 Ok(cookies.map_or(DOMString::new(), DOMString::from))
6083 }
6084
6085 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
6087 if self.is_cookie_averse() {
6088 return Ok(());
6089 }
6090
6091 if !self.origin().is_tuple() {
6092 return Err(Error::Security(None));
6093 }
6094
6095 if !cookie.is_valid_for_cookie() {
6096 return Ok(());
6097 }
6098
6099 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6100 vec![cookie]
6101 } else {
6102 vec![]
6103 };
6104
6105 let _ = self
6106 .window
6107 .as_global_scope()
6108 .resource_threads()
6109 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6110 Ok(())
6111 }
6112
6113 fn BgColor(&self) -> DOMString {
6115 self.get_body_attribute(&local_name!("bgcolor"))
6116 }
6117
6118 fn SetBgColor(&self, cx: &mut JSContext, value: DOMString) {
6120 self.set_body_attribute(cx, &local_name!("bgcolor"), value)
6121 }
6122
6123 fn FgColor(&self) -> DOMString {
6125 self.get_body_attribute(&local_name!("text"))
6126 }
6127
6128 fn SetFgColor(&self, cx: &mut JSContext, value: DOMString) {
6130 self.set_body_attribute(cx, &local_name!("text"), value)
6131 }
6132
6133 fn NamedGetter(&self, cx: &mut JSContext, name: DOMString) -> Option<NamedPropertyValue> {
6135 if name.is_empty() {
6136 return None;
6137 }
6138 let name = Atom::from(name);
6139
6140 let elements_with_name = self.get_elements_with_name(cx, &name);
6143 let name_iter = elements_with_name
6144 .iter()
6145 .filter(|elem| is_named_element_with_name_attribute(elem));
6146 let elements_with_id = self.id_map.get_all(cx.no_gc(), self.upcast(), &name);
6147 let id_iter = elements_with_id
6148 .iter()
6149 .filter(|elem| is_named_element_with_id_attribute(elem));
6150 let mut elements = name_iter.chain(id_iter);
6151
6152 let first = elements.next()?;
6159 if elements.all(|other| first == other) {
6160 if let Some(nested_window_proxy) = first
6161 .downcast::<HTMLIFrameElement>()
6162 .and_then(|iframe| iframe.GetContentWindow())
6163 {
6164 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6165 }
6166
6167 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6169 }
6170
6171 #[derive(JSTraceable, MallocSizeOf)]
6174 struct DocumentNamedGetter {
6175 #[no_trace]
6176 name: Atom,
6177 }
6178 impl CollectionFilter for DocumentNamedGetter {
6179 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6180 let type_ = match elem.upcast::<Node>().type_id() {
6181 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6182 _ => return false,
6183 };
6184 match type_ {
6185 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6186 elem.get_name().as_ref() == Some(&self.name)
6187 },
6188 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6189 name == *self.name ||
6190 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6191 }),
6192 _ => false,
6196 }
6197 }
6198 }
6199 let collection = HTMLCollection::create(
6200 cx,
6201 self.window(),
6202 self.upcast(),
6203 Box::new(DocumentNamedGetter { name }),
6204 );
6205 Some(NamedPropertyValue::HTMLCollection(collection))
6206 }
6207
6208 fn SupportedPropertyNames(&self, no_gc: &NoGC) -> Vec<DOMString> {
6210 let mut names_with_first_named_element_map = HashMap::new();
6211 self.name_map
6212 .for_each(no_gc, self.upcast(), |name, elements| {
6213 if name.is_empty() {
6214 return;
6215 }
6216 let mut name_iter = elements
6217 .iter()
6218 .filter(|elem| is_named_element_with_name_attribute(elem));
6219 if let Some(first) = name_iter.next() {
6220 names_with_first_named_element_map.insert(name.clone(), first.as_rooted());
6221 }
6222 });
6223
6224 self.id_map.for_each(no_gc, self.upcast(), |id, elements| {
6225 if id.is_empty() {
6226 return;
6227 }
6228 let mut id_iter = elements
6229 .iter()
6230 .filter(|elem| is_named_element_with_id_attribute(elem));
6231 if let Some(first) = id_iter.next() {
6232 match names_with_first_named_element_map.entry(id.clone()) {
6233 Vacant(entry) => drop(entry.insert(first.as_rooted())),
6234 Occupied(mut entry) => {
6235 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6236 *entry.get_mut() = first.as_rooted();
6237 }
6238 },
6239 }
6240 }
6241 });
6242
6243 let mut names_with_first_named_element_vec: Vec<_> =
6244 names_with_first_named_element_map.into_iter().collect();
6245 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6246 if a.1 == b.1 {
6247 a.0.cmp(&b.0)
6250 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6251 Ordering::Less
6252 } else {
6253 Ordering::Greater
6254 }
6255 });
6256
6257 names_with_first_named_element_vec
6258 .into_iter()
6259 .map(|(k, _)| DOMString::from(&*k))
6260 .collect()
6261 }
6262
6263 fn Clear(&self) {
6265 }
6267
6268 fn CaptureEvents(&self) {
6270 }
6272
6273 fn ReleaseEvents(&self) {
6275 }
6277
6278 global_event_handlers!();
6280
6281 event_handler!(
6283 readystatechange,
6284 GetOnreadystatechange,
6285 SetOnreadystatechange
6286 );
6287
6288 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6290 self.document_or_shadow_root.element_from_point(
6291 self.upcast(),
6292 x,
6293 y,
6294 self.GetDocumentElement(),
6295 self.has_browsing_context,
6296 )
6297 }
6298
6299 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6301 self.document_or_shadow_root.elements_from_point(
6302 self.upcast(),
6303 x,
6304 y,
6305 self.GetDocumentElement(),
6306 self.has_browsing_context,
6307 )
6308 }
6309
6310 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6312 if self.quirks_mode() == QuirksMode::Quirks {
6314 if let Some(ref body) = self.GetBody() {
6316 let e = body.upcast::<Element>();
6317 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6321 return Some(DomRoot::from_ref(e));
6322 }
6323 }
6324
6325 return None;
6327 }
6328
6329 self.GetDocumentElement()
6332 }
6333
6334 fn Open(
6336 &self,
6337 cx: &mut JSContext,
6338 _unused1: Option<DOMString>,
6339 _unused2: Option<DOMString>,
6340 ) -> Fallible<DomRoot<Document>> {
6341 if !self.is_html_document() {
6343 return Err(Error::InvalidState(None));
6344 }
6345
6346 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6349 return Err(Error::InvalidState(None));
6350 }
6351
6352 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6354
6355 if !self
6358 .origin()
6359 .same_origin(&entry_responsible_document.origin())
6360 {
6361 return Err(Error::Security(None));
6362 }
6363
6364 if self
6367 .active_parser()
6368 .is_some_and(|parser| parser.script_nesting_level() > 0)
6369 {
6370 return Ok(DomRoot::from_ref(self));
6371 }
6372
6373 if self.is_prompting_or_unloading() {
6375 return Ok(DomRoot::from_ref(self));
6376 }
6377
6378 if self.active_parser_was_aborted.get() {
6380 return Ok(DomRoot::from_ref(self));
6381 }
6382
6383 self.window().set_navigation_start();
6387
6388 if self.has_browsing_context() {
6392 self.abort(cx);
6395 }
6396
6397 for node in self
6400 .upcast::<Node>()
6401 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6402 {
6403 node.upcast::<EventTarget>().remove_all_listeners();
6404 }
6405
6406 if self.window.Document() == DomRoot::from_ref(self) {
6409 self.window.upcast::<EventTarget>().remove_all_listeners();
6410 }
6411
6412 Node::replace_all(cx, None, self.upcast::<Node>());
6414
6415 if self.is_fully_active() {
6422 let mut new_url = entry_responsible_document.url();
6424
6425 if entry_responsible_document != DomRoot::from_ref(self) {
6427 new_url.set_fragment(None);
6428 }
6429
6430 self.set_url(new_url);
6433 }
6434
6435 self.is_initial_about_blank.set(false);
6437
6438 if self.iframe_load_in_progress.get() {
6441 self.mute_iframe_load.set(true);
6442 }
6443
6444 self.set_quirks_mode(QuirksMode::NoQuirks);
6446
6447 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6453 *self.loader.borrow_mut() =
6454 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6455 ServoParser::parse_html_script_input(cx, self, self.url());
6456
6457 self.ready_state.set(DocumentReadyState::Loading);
6463
6464 Ok(DomRoot::from_ref(self))
6466 }
6467
6468 fn Open_(
6470 &self,
6471 cx: &mut JSContext,
6472 url: USVString,
6473 target: DOMString,
6474 features: DOMString,
6475 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6476 self.browsing_context()
6477 .ok_or(Error::InvalidAccess(None))?
6478 .open(cx, url, target, features)
6479 }
6480
6481 fn Write(&self, cx: &mut JSContext, text: Vec<TrustedHTMLOrString>) -> ErrorResult {
6483 self.write(cx, text, false, "Document", "write")
6486 }
6487
6488 fn Writeln(&self, cx: &mut JSContext, text: Vec<TrustedHTMLOrString>) -> ErrorResult {
6490 self.write(cx, text, true, "Document", "writeln")
6493 }
6494
6495 fn Close(&self, cx: &mut JSContext) -> ErrorResult {
6497 if !self.is_html_document() {
6498 return Err(Error::InvalidState(None));
6500 }
6501
6502 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6505 return Err(Error::InvalidState(None));
6506 }
6507
6508 let parser = match self.get_current_parser() {
6510 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6511 _ => {
6512 return Ok(());
6513 },
6514 };
6515
6516 parser.close(cx);
6518
6519 Ok(())
6520 }
6521
6522 fn ExecCommand(
6524 &self,
6525 cx: &mut JSContext,
6526 command_id: DOMString,
6527 _show_ui: bool,
6528 value: TrustedHTMLOrString,
6529 ) -> Fallible<bool> {
6530 let value = if command_id == "insertHTML" {
6531 TrustedHTML::get_trusted_type_compliant_string(
6532 cx,
6533 self.window.as_global_scope(),
6534 value,
6535 "Document execCommand",
6536 )?
6537 } else {
6538 match value {
6539 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6540 TrustedHTMLOrString::String(value) => value,
6541 }
6542 };
6543
6544 Ok(self.exec_command_for_command_id(cx, command_id, value))
6545 }
6546
6547 fn QueryCommandEnabled(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6549 self.check_support_and_enabled(cx, &command_id).is_some()
6551 }
6552
6553 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6555 self.is_command_supported(command_id)
6559 }
6560
6561 fn QueryCommandIndeterm(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6563 self.is_command_indeterminate(cx, command_id)
6564 }
6565
6566 fn QueryCommandState(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6568 self.command_state_for_command(cx, command_id)
6569 }
6570
6571 fn QueryCommandValue(&self, cx: &mut JSContext, command_id: DOMString) -> DOMString {
6573 self.command_value_for_command(cx, command_id)
6574 }
6575
6576 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6578
6579 event_handler!(
6581 fullscreenchange,
6582 GetOnfullscreenchange,
6583 SetOnfullscreenchange
6584 );
6585
6586 fn FullscreenEnabled(&self) -> bool {
6588 self.get_allow_fullscreen()
6589 }
6590
6591 fn Fullscreen(&self) -> bool {
6593 self.fullscreen_element.get().is_some()
6594 }
6595
6596 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6598 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6599 }
6600
6601 fn ExitFullscreen(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
6603 self.exit_fullscreen(cx)
6604 }
6605
6606 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6610 match self.media_controls.borrow().get(&*id.str()) {
6611 Some(m) => Ok(DomRoot::from_ref(m)),
6612 None => Err(Error::InvalidAccess(None)),
6613 }
6614 }
6615
6616 fn GetSelection(&self, cx: &mut JSContext) -> Option<DomRoot<Selection>> {
6618 if self.has_browsing_context {
6619 Some(self.selection.or_init(|| Selection::new(cx, self)))
6620 } else {
6621 None
6622 }
6623 }
6624
6625 fn Fonts(&self, cx: &mut JSContext) -> DomRoot<FontFaceSet> {
6627 self.fonts
6628 .or_init(|| FontFaceSet::new(cx, &self.global(), None))
6629 }
6630
6631 fn Hidden(&self) -> bool {
6633 self.visibility_state.get() == DocumentVisibilityState::Hidden
6634 }
6635
6636 fn VisibilityState(&self) -> DocumentVisibilityState {
6638 self.visibility_state.get()
6639 }
6640
6641 fn CreateExpression(
6642 &self,
6643 cx: &mut JSContext,
6644 expression: DOMString,
6645 resolver: Option<Rc<XPathNSResolver>>,
6646 ) -> Fallible<DomRoot<crate::dom::types::XPathExpression>> {
6647 let parsed_expression =
6648 parse_expression(cx, &expression.str(), resolver, self.is_html_document())?;
6649 Ok(XPathExpression::new(
6650 cx,
6651 &self.window,
6652 None,
6653 parsed_expression,
6654 ))
6655 }
6656
6657 fn CreateNSResolver(&self, cx: &mut JSContext, node_resolver: &Node) -> DomRoot<Node> {
6658 let global = self.global();
6659 let window = global.as_window();
6660 let evaluator = XPathEvaluator::new(cx, window, None);
6661 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6662 }
6663
6664 fn Evaluate(
6665 &self,
6666 cx: &mut JSContext,
6667 expression: DOMString,
6668 context_node: &Node,
6669 resolver: Option<Rc<XPathNSResolver>>,
6670 result_type: u16,
6671 result: Option<&crate::dom::types::XPathResult>,
6672 ) -> Fallible<DomRoot<crate::dom::types::XPathResult>> {
6673 let parsed_expression =
6674 parse_expression(cx, &expression.str(), resolver, self.is_html_document())?;
6675 XPathExpression::new(cx, &self.window, None, parsed_expression).evaluate_internal(
6676 cx,
6677 context_node,
6678 result_type,
6679 result,
6680 )
6681 }
6682
6683 fn AdoptedStyleSheets(&self, cx: &mut JSContext, retval: MutableHandleValue) {
6685 self.adopted_stylesheets_frozen_types.get_or_init(
6686 cx,
6687 || {
6688 self.adopted_stylesheets
6689 .borrow()
6690 .clone()
6691 .iter()
6692 .map(|sheet| sheet.as_rooted())
6693 .collect()
6694 },
6695 retval,
6696 );
6697 }
6698
6699 fn SetAdoptedStyleSheets(&self, cx: &mut JSContext, val: HandleValue) -> ErrorResult {
6701 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6702 cx,
6703 self.adopted_stylesheets.borrow_mut().as_mut(),
6704 val,
6705 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6706 );
6707
6708 if result.is_ok() {
6710 self.adopted_stylesheets_frozen_types.clear()
6711 }
6712
6713 result
6714 }
6715
6716 fn Timeline(&self) -> DomRoot<DocumentTimeline> {
6717 self.timeline.as_rooted()
6718 }
6719}
6720
6721fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6722 if marker.get().is_none() {
6723 marker.set(Some(CrossProcessInstant::now()))
6724 }
6725}
6726
6727#[derive(JSTraceable, MallocSizeOf)]
6728pub(crate) enum AnimationFrameCallback {
6729 DevtoolsFramerateTick {
6730 actor_name: String,
6731 },
6732 FrameRequestCallback {
6733 #[conditional_malloc_size_of]
6734 callback: Rc<FrameRequestCallback>,
6735 },
6736}
6737
6738impl AnimationFrameCallback {
6739 fn call(&self, cx: &mut JSContext, document: &Document, now: f64) {
6740 match *self {
6741 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6742 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6743 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6744 devtools_sender.send(msg).unwrap();
6745 },
6746 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6747 let _ = callback.Call__(cx, Finite::wrap(now), ExceptionHandling::Report);
6750 },
6751 }
6752 }
6753}
6754
6755#[derive(Default, JSTraceable, MallocSizeOf)]
6756#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6757struct PendingInOrderScriptVec {
6758 scripts: DomRefCell<VecDeque<PendingScript>>,
6759}
6760
6761impl PendingInOrderScriptVec {
6762 fn is_empty(&self) -> bool {
6763 self.scripts.borrow().is_empty()
6764 }
6765
6766 fn push(&self, element: &HTMLScriptElement) {
6767 self.scripts
6768 .borrow_mut()
6769 .push_back(PendingScript::new(element));
6770 }
6771
6772 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6773 let mut scripts = self.scripts.borrow_mut();
6774 let entry = scripts
6775 .iter_mut()
6776 .find(|entry| &*entry.element == element)
6777 .unwrap();
6778 entry.loaded(result);
6779 }
6780
6781 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6782 let mut scripts = self.scripts.borrow_mut();
6783 let pair = scripts.front_mut()?.take_result()?;
6784 scripts.pop_front();
6785 Some(pair)
6786 }
6787
6788 fn clear(&self) {
6789 *self.scripts.borrow_mut() = Default::default();
6790 }
6791}
6792
6793#[derive(JSTraceable, MallocSizeOf)]
6794#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6795struct PendingScript {
6796 element: Dom<HTMLScriptElement>,
6797 load: Option<ScriptResult>,
6799}
6800
6801impl PendingScript {
6802 fn new(element: &HTMLScriptElement) -> Self {
6803 Self {
6804 element: Dom::from_ref(element),
6805 load: None,
6806 }
6807 }
6808
6809 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6810 Self {
6811 element: Dom::from_ref(element),
6812 load,
6813 }
6814 }
6815
6816 fn loaded(&mut self, result: ScriptResult) {
6817 assert!(self.load.is_none());
6818 self.load = Some(result);
6819 }
6820
6821 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6822 self.load
6823 .take()
6824 .map(|result| (DomRoot::from_ref(&*self.element), result))
6825 }
6826}
6827
6828fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6829 let type_ = match elem.upcast::<Node>().type_id() {
6830 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6831 _ => return false,
6832 };
6833 match type_ {
6834 HTMLElementTypeId::HTMLFormElement |
6835 HTMLElementTypeId::HTMLIFrameElement |
6836 HTMLElementTypeId::HTMLImageElement => true,
6837 _ => false,
6841 }
6842}
6843
6844fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6845 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6849}
6850
6851impl DocumentHelpers for Document {
6852 fn ensure_safe_to_run_script_or_layout(&self) {
6853 Document::ensure_safe_to_run_script_or_layout(self)
6854 }
6855}
6856
6857pub(crate) struct SameoriginAncestorNavigablesIterator {
6861 document: DomRoot<Document>,
6862}
6863
6864impl SameoriginAncestorNavigablesIterator {
6865 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6866 Self { document }
6867 }
6868}
6869
6870impl Iterator for SameoriginAncestorNavigablesIterator {
6871 type Item = DomRoot<Document>;
6872
6873 fn next(&mut self) -> Option<Self::Item> {
6874 let window_proxy = self.document.browsing_context()?;
6875 self.document = window_proxy.parent()?.document()?;
6876 Some(self.document.clone())
6877 }
6878}
6879
6880pub(crate) struct SameOriginDescendantNavigablesIterator {
6885 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6886}
6887
6888impl SameOriginDescendantNavigablesIterator {
6889 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6890 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6891 Self {
6892 stack: vec![Box::new(iframes.into_iter())],
6893 }
6894 }
6895
6896 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6897 let mut cur_iframe = self.stack.last_mut()?.next();
6898 while cur_iframe.is_none() {
6899 self.stack.pop();
6900 cur_iframe = self.stack.last_mut()?.next();
6901 }
6902 cur_iframe
6903 }
6904}
6905
6906impl Iterator for SameOriginDescendantNavigablesIterator {
6907 type Item = DomRoot<Document>;
6908
6909 fn next(&mut self) -> Option<Self::Item> {
6910 while let Some(iframe) = self.get_next_iframe() {
6911 let Some(pipeline_id) = iframe.pipeline_id() else {
6912 continue;
6913 };
6914
6915 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6916 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6917 document.iframes().iter().collect();
6918 self.stack.push(Box::new(child_iframes.into_iter()));
6919 return Some(document);
6920 } else {
6921 continue;
6922 };
6923 }
6924 None
6925 }
6926}