1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use base::cross_process_instant::CrossProcessInstant;
17use base::generic_channel::GenericSend;
18use base::id::WebViewId;
19use base::{Epoch, generic_channel};
20use bitflags::bitflags;
21use chrono::Local;
22use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
23use content_security_policy::sandboxing_directive::SandboxingFlagSet;
24use content_security_policy::{CspList, Policy as CspPolicy, PolicyDisposition};
25use cookie::Cookie;
26use data_url::mime::Mime;
27use devtools_traits::ScriptToDevtoolsControlMsg;
28use dom_struct::dom_struct;
29use embedder_traits::{
30 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
31 Image, LoadStatus,
32};
33use encoding_rs::{Encoding, UTF_8};
34use fonts::WebFontDocumentContext;
35use html5ever::{LocalName, Namespace, QualName, local_name, ns};
36use hyper_serde::Serde;
37use js::rust::{HandleObject, HandleValue, MutableHandleValue};
38use layout_api::{
39 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
40 ScrollContainerQueryFlags, TrustedNodeAddress,
41};
42use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
43use net_traits::CookieSource::NonHTTP;
44use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
45use net_traits::ReferrerPolicy;
46use net_traits::policy_container::PolicyContainer;
47use net_traits::pub_domains::is_pub_domain;
48use net_traits::request::{
49 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
50};
51use net_traits::response::HttpsState;
52use percent_encoding::percent_decode;
53use profile_traits::ipc as profile_ipc;
54use profile_traits::time::TimerMetadataFrameType;
55use regex::bytes::Regex;
56use rustc_hash::{FxBuildHasher, FxHashMap};
57use script_bindings::interfaces::DocumentHelpers;
58use script_bindings::script_runtime::JSContext;
59use script_traits::{DocumentActivity, ProgressiveWebMetricType};
60use servo_arc::Arc;
61use servo_config::pref;
62use servo_media::{ClientContextId, ServoMedia};
63use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
64use style::attr::AttrValue;
65use style::context::QuirksMode;
66use style::invalidation::element::restyle_hints::RestyleHint;
67use style::selector_parser::Snapshot;
68use style::shared_lock::SharedRwLock as StyleSharedRwLock;
69use style::str::{split_html_space_chars, str_join};
70use style::stylesheet_set::DocumentStylesheetSet;
71use style::stylesheets::{Origin, OriginSet, Stylesheet};
72use stylo_atoms::Atom;
73use url::{Host, Position};
74
75use crate::animation_timeline::AnimationTimeline;
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::attr::Attr;
79use crate::dom::beforeunloadevent::BeforeUnloadEvent;
80use crate::dom::bindings::callback::ExceptionHandling;
81use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
82use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
83use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
84 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
85};
86use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
87use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
88use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
90#[cfg(any(feature = "webxr", feature = "gamepad"))]
91use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
92use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
93use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
94use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
95use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
96use crate::dom::bindings::codegen::Bindings::WindowBinding::{
97 FrameRequestCallback, ScrollBehavior, WindowMethods,
98};
99use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
100use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
101use crate::dom::bindings::codegen::UnionTypes::{
102 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
103};
104use crate::dom::bindings::domname::{
105 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
106};
107use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
108use crate::dom::bindings::frozenarray::CachedFrozenArray;
109use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
110use crate::dom::bindings::num::Finite;
111use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
112use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
113use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
114use crate::dom::bindings::str::{DOMString, USVString};
115use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
116use crate::dom::bindings::weakref::DOMTracker;
117use crate::dom::bindings::xmlname::matches_name_production;
118use crate::dom::cdatasection::CDATASection;
119use crate::dom::comment::Comment;
120use crate::dom::compositionevent::CompositionEvent;
121use crate::dom::css::cssstylesheet::CSSStyleSheet;
122use crate::dom::css::fontfaceset::FontFaceSet;
123use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
124use crate::dom::customelementregistry::{
125 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
126};
127use crate::dom::customevent::CustomEvent;
128use crate::dom::document_embedder_controls::DocumentEmbedderControls;
129use crate::dom::document_event_handler::DocumentEventHandler;
130use crate::dom::documentfragment::DocumentFragment;
131use crate::dom::documentorshadowroot::{
132 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
133};
134use crate::dom::documenttype::DocumentType;
135use crate::dom::domimplementation::DOMImplementation;
136use crate::dom::element::{
137 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
138 ElementPerformFullscreenExit,
139};
140use crate::dom::event::{Event, EventBubbles, EventCancelable};
141use crate::dom::eventtarget::EventTarget;
142use crate::dom::execcommand::basecommand::DefaultSingleLineContainerName;
143use crate::dom::execcommand::contenteditable::ContentEditableRange;
144use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
145use crate::dom::focusevent::FocusEvent;
146use crate::dom::globalscope::GlobalScope;
147use crate::dom::hashchangeevent::HashChangeEvent;
148use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
149use crate::dom::html::htmlareaelement::HTMLAreaElement;
150use crate::dom::html::htmlbaseelement::HTMLBaseElement;
151use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
152use crate::dom::html::htmlelement::HTMLElement;
153use crate::dom::html::htmlembedelement::HTMLEmbedElement;
154use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
155use crate::dom::html::htmlheadelement::HTMLHeadElement;
156use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
157use crate::dom::html::htmliframeelement::HTMLIFrameElement;
158use crate::dom::html::htmlimageelement::HTMLImageElement;
159use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
160use crate::dom::html::htmltitleelement::HTMLTitleElement;
161use crate::dom::htmldetailselement::DetailsNameGroups;
162use crate::dom::intersectionobserver::IntersectionObserver;
163use crate::dom::keyboardevent::KeyboardEvent;
164use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
165use crate::dom::location::Location;
166use crate::dom::messageevent::MessageEvent;
167use crate::dom::mouseevent::MouseEvent;
168use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
169use crate::dom::nodeiterator::NodeIterator;
170use crate::dom::nodelist::NodeList;
171use crate::dom::pagetransitionevent::PageTransitionEvent;
172use crate::dom::performance::performanceentry::PerformanceEntry;
173use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
174use crate::dom::processinginstruction::ProcessingInstruction;
175use crate::dom::promise::Promise;
176use crate::dom::range::Range;
177use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
178use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
179use crate::dom::selection::Selection;
180use crate::dom::servoparser::ServoParser;
181use crate::dom::shadowroot::ShadowRoot;
182use crate::dom::storageevent::StorageEvent;
183use crate::dom::text::Text;
184use crate::dom::touchevent::TouchEvent as DomTouchEvent;
185use crate::dom::touchlist::TouchList;
186use crate::dom::treewalker::TreeWalker;
187use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
188use crate::dom::types::{HTMLCanvasElement, HTMLDialogElement, VisibilityStateEntry};
189use crate::dom::uievent::UIEvent;
190use crate::dom::virtualmethods::vtable_for;
191use crate::dom::websocket::WebSocket;
192use crate::dom::window::Window;
193use crate::dom::windowproxy::WindowProxy;
194use crate::dom::xpathevaluator::XPathEvaluator;
195use crate::dom::xpathexpression::XPathExpression;
196use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
197use crate::iframe_collection::IFrameCollection;
198use crate::image_animation::ImageAnimationManager;
199use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
200use crate::mime::{APPLICATION, CHARSET};
201use crate::network_listener::{FetchResponseListener, NetworkListener};
202use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
203use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
204use crate::script_thread::ScriptThread;
205use crate::stylesheet_set::StylesheetSetRef;
206use crate::task::NonSendTaskBox;
207use crate::task_source::TaskSourceName;
208use crate::timers::OneshotTimerCallback;
209use crate::xpath::parse_expression;
210
211#[derive(Clone, Copy, PartialEq)]
212pub(crate) enum FireMouseEventType {
213 Move,
214 Over,
215 Out,
216 Enter,
217 Leave,
218}
219
220impl FireMouseEventType {
221 pub(crate) fn as_str(&self) -> &str {
222 match *self {
223 FireMouseEventType::Move => "mousemove",
224 FireMouseEventType::Over => "mouseover",
225 FireMouseEventType::Out => "mouseout",
226 FireMouseEventType::Enter => "mouseenter",
227 FireMouseEventType::Leave => "mouseleave",
228 }
229 }
230}
231
232#[derive(JSTraceable, MallocSizeOf)]
233pub(crate) struct RefreshRedirectDue {
234 #[no_trace]
235 pub(crate) url: ServoUrl,
236 #[ignore_malloc_size_of = "non-owning"]
237 pub(crate) window: DomRoot<Window>,
238}
239impl RefreshRedirectDue {
240 pub(crate) fn invoke(self, can_gc: CanGc) {
242 let load_data = self
252 .window
253 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
254 self.window
255 .load_url(NavigationHistoryBehavior::Replace, false, load_data, can_gc);
256 }
257}
258
259#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
260pub(crate) enum IsHTMLDocument {
261 HTMLDocument,
262 NonHTMLDocument,
263}
264
265#[derive(JSTraceable, MallocSizeOf)]
266#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
267struct FocusTransaction {
268 element: Option<Dom<Element>>,
270 has_focus: bool,
272 focus_options: FocusOptions,
274}
275
276#[derive(JSTraceable, MallocSizeOf)]
278pub(crate) enum DeclarativeRefresh {
279 PendingLoad {
280 #[no_trace]
281 url: ServoUrl,
282 time: u64,
283 },
284 CreatedAfterLoad,
285}
286
287#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
290pub(crate) struct RenderingUpdateReason(u8);
291
292bitflags! {
293 impl RenderingUpdateReason: u8 {
294 const ResizeObserverStartedObservingTarget = 1 << 0;
297 const IntersectionObserverStartedObservingTarget = 1 << 1;
300 const FontReadyPromiseFulfilled = 1 << 2;
304 }
305}
306
307#[dom_struct]
309pub(crate) struct Document {
310 node: Node,
311 document_or_shadow_root: DocumentOrShadowRoot,
312 window: Dom<Window>,
313 implementation: MutNullableDom<DOMImplementation>,
314 #[ignore_malloc_size_of = "type from external crate"]
315 #[no_trace]
316 content_type: Mime,
317 last_modified: Option<String>,
318 #[no_trace]
319 encoding: Cell<&'static Encoding>,
320 has_browsing_context: bool,
321 is_html_document: bool,
322 #[no_trace]
323 activity: Cell<DocumentActivity>,
324 #[no_trace]
326 url: DomRefCell<ServoUrl>,
327 #[no_trace]
329 about_base_url: DomRefCell<Option<ServoUrl>>,
330 #[ignore_malloc_size_of = "defined in selectors"]
331 #[no_trace]
332 quirks_mode: Cell<QuirksMode>,
333 event_handler: DocumentEventHandler,
335 embedder_controls: DocumentEmbedderControls,
337 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
340 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
341 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
342 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
343 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
344 images: MutNullableDom<HTMLCollection>,
345 embeds: MutNullableDom<HTMLCollection>,
346 links: MutNullableDom<HTMLCollection>,
347 forms: MutNullableDom<HTMLCollection>,
348 scripts: MutNullableDom<HTMLCollection>,
349 anchors: MutNullableDom<HTMLCollection>,
350 applets: MutNullableDom<HTMLCollection>,
351 iframes: RefCell<IFrameCollection>,
353 #[no_trace]
356 style_shared_lock: StyleSharedRwLock,
357 #[custom_trace]
359 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
360 stylesheet_list: MutNullableDom<StyleSheetList>,
361 ready_state: Cell<DocumentReadyState>,
362 domcontentloaded_dispatched: Cell<bool>,
364 focus_transaction: DomRefCell<Option<FocusTransaction>>,
366 focused: MutNullableDom<Element>,
368 #[no_trace]
370 focus_sequence: Cell<FocusSequenceNumber>,
371 has_focus: Cell<bool>,
375 current_script: MutNullableDom<HTMLScriptElement>,
377 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
379 script_blocking_stylesheets_count: Cell<u32>,
381 render_blocking_element_count: Cell<u32>,
384 deferred_scripts: PendingInOrderScriptVec,
386 asap_in_order_scripts_list: PendingInOrderScriptVec,
388 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
390 animation_frame_ident: Cell<u32>,
393 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
396 running_animation_callbacks: Cell<bool>,
401 loader: DomRefCell<DocumentLoader>,
403 current_parser: MutNullableDom<ServoParser>,
405 base_element: MutNullableDom<HTMLBaseElement>,
407 target_base_element: MutNullableDom<HTMLBaseElement>,
409 appropriate_template_contents_owner_document: MutNullableDom<Document>,
412 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
415 #[no_trace]
419 needs_restyle: Cell<RestyleReason>,
420 #[no_trace]
423 dom_interactive: Cell<Option<CrossProcessInstant>>,
424 #[no_trace]
426 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
427 #[no_trace]
429 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
430 #[no_trace]
431 dom_complete: Cell<Option<CrossProcessInstant>>,
432 #[no_trace]
433 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
434 #[no_trace]
435 load_event_start: Cell<Option<CrossProcessInstant>>,
436 #[no_trace]
437 load_event_end: Cell<Option<CrossProcessInstant>>,
438 #[no_trace]
439 unload_event_start: Cell<Option<CrossProcessInstant>>,
440 #[no_trace]
441 unload_event_end: Cell<Option<CrossProcessInstant>>,
442 #[no_trace]
444 https_state: Cell<HttpsState>,
445 #[no_trace]
447 origin: MutableOrigin,
448 referrer: Option<String>,
450 target_element: MutNullableDom<Element>,
452 #[no_trace]
454 policy_container: DomRefCell<PolicyContainer>,
455 #[no_trace]
457 preloaded_resources: DomRefCell<PreloadedResources>,
458 ignore_destructive_writes_counter: Cell<u32>,
460 ignore_opens_during_unload_counter: Cell<u32>,
462 spurious_animation_frames: Cell<u8>,
466
467 dom_count: Cell<u32>,
473 fullscreen_element: MutNullableDom<Element>,
475 form_id_listener_map:
482 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
483 #[no_trace]
484 interactive_time: DomRefCell<ProgressiveWebMetrics>,
485 #[no_trace]
486 tti_window: DomRefCell<InteractiveWindow>,
487 canceller: FetchCanceller,
489 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
491 page_showing: Cell<bool>,
493 salvageable: Cell<bool>,
495 active_parser_was_aborted: Cell<bool>,
497 fired_unload: Cell<bool>,
499 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
501 redirect_count: Cell<u16>,
503 script_and_layout_blockers: Cell<u32>,
505 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
507 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
508 completely_loaded: Cell<bool>,
510 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
512 shadow_roots_styles_changed: Cell<bool>,
514 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
520 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
523 has_pending_animated_image_update: Cell<bool>,
525 selection: MutNullableDom<Selection>,
527 animation_timeline: DomRefCell<AnimationTimeline>,
530 animations: Animations,
532 image_animation_manager: DomRefCell<ImageAnimationManager>,
534 dirty_root: MutNullableDom<Element>,
536 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
538 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
547 fonts: MutNullableDom<FontFaceSet>,
550 visibility_state: Cell<DocumentVisibilityState>,
552 status_code: Option<u16>,
554 is_initial_about_blank: Cell<bool>,
556 allow_declarative_shadow_roots: Cell<bool>,
558 #[no_trace]
560 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
561 has_trustworthy_ancestor_origin: Cell<bool>,
563 intersection_observer_task_queued: Cell<bool>,
565 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
577 highlighted_dom_node: MutNullableDom<Node>,
579 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
582 #[ignore_malloc_size_of = "mozjs"]
584 adopted_stylesheets_frozen_types: CachedFrozenArray,
585 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
587 rendering_update_reasons: Cell<RenderingUpdateReason>,
589 waiting_on_canvas_image_updates: Cell<bool>,
593 #[no_trace]
601 current_rendering_epoch: Cell<Epoch>,
602 #[conditional_malloc_size_of]
604 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
605 #[no_trace]
606 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
608 #[no_trace]
609 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
616 #[no_trace]
618 favicon: RefCell<Option<Image>>,
619
620 websockets: DOMTracker<WebSocket>,
622
623 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
625
626 #[no_trace]
628 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
629
630 layout_animations_test_enabled: bool,
632
633 state_override: Cell<bool>,
635
636 value_override: DomRefCell<Option<DOMString>>,
638
639 #[no_trace]
641 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
642
643 css_styling_flag: Cell<bool>,
645}
646
647impl Document {
648 fn unloading_cleanup_steps(&self) {
650 if self.close_outstanding_websockets() {
653 self.salvageable.set(false);
655 }
656
657 if !self.salvageable.get() {
662 let global_scope = self.window.as_global_scope();
663
664 global_scope.close_event_sources();
666
667 let msg = ScriptToConstellationMessage::DiscardDocument;
672 let _ = global_scope.script_to_constellation_chan().send(msg);
673 }
674 }
675
676 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
677 self.websockets.track(websocket);
678 }
679
680 fn close_outstanding_websockets(&self) -> bool {
681 let mut closed_any_websocket = false;
682 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
683 if websocket.make_disappear() {
684 closed_any_websocket = true;
685 }
686 });
687 closed_any_websocket
688 }
689
690 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
691 debug_assert!(*node.owner_doc() == *self);
692 if !node.is_connected() {
693 return;
694 }
695
696 let parent = match node.parent_in_flat_tree() {
697 Some(parent) => parent,
698 None => {
699 let document_element = match self.GetDocumentElement() {
702 Some(element) => element,
703 None => return,
704 };
705 if let Some(dirty_root) = self.dirty_root.get() {
706 for ancestor in dirty_root
709 .upcast::<Node>()
710 .inclusive_ancestors_in_flat_tree()
711 {
712 if ancestor.is::<Element>() {
713 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
714 }
715 }
716 }
717 self.dirty_root.set(Some(&document_element));
718 return;
719 },
720 };
721
722 if parent.is::<Element>() {
723 if !parent.is_styled() {
724 return;
725 }
726
727 if parent.is_display_none() {
728 return;
729 }
730 }
731
732 let element_parent: DomRoot<Element>;
733 let element = match node.downcast::<Element>() {
734 Some(element) => element,
735 None => {
736 match DomRoot::downcast::<Element>(parent) {
739 Some(parent) => {
740 element_parent = parent;
741 &element_parent
742 },
743 None => {
744 return;
748 },
749 }
750 },
751 };
752
753 let dirty_root = match self.dirty_root.get() {
754 Some(root) if root.is_connected() => root,
755 _ => {
756 element
757 .upcast::<Node>()
758 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
759 self.dirty_root.set(Some(element));
760 return;
761 },
762 };
763
764 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
765 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
766 return;
767 }
768
769 if ancestor.is::<Element>() {
770 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
771 }
772 }
773
774 let new_dirty_root = element
775 .upcast::<Node>()
776 .common_ancestor_in_flat_tree(dirty_root.upcast())
777 .expect("Couldn't find common ancestor");
778
779 let mut has_dirty_descendants = true;
780 for ancestor in dirty_root
781 .upcast::<Node>()
782 .inclusive_ancestors_in_flat_tree()
783 {
784 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
785 has_dirty_descendants &= *ancestor != *new_dirty_root;
786 }
787
788 self.dirty_root
789 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
790 }
791
792 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
793 self.dirty_root.take()
794 }
795
796 #[inline]
797 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
798 self.loader.borrow()
799 }
800
801 #[inline]
802 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
803 self.loader.borrow_mut()
804 }
805
806 #[inline]
807 pub(crate) fn has_browsing_context(&self) -> bool {
808 self.has_browsing_context
809 }
810
811 #[inline]
813 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
814 if self.has_browsing_context {
815 self.window.undiscarded_window_proxy()
816 } else {
817 None
818 }
819 }
820
821 pub(crate) fn webview_id(&self) -> WebViewId {
822 self.window.webview_id()
823 }
824
825 #[inline]
826 pub(crate) fn window(&self) -> &Window {
827 &self.window
828 }
829
830 #[inline]
831 pub(crate) fn is_html_document(&self) -> bool {
832 self.is_html_document
833 }
834
835 pub(crate) fn is_xhtml_document(&self) -> bool {
836 self.content_type.matches(APPLICATION, "xhtml+xml")
837 }
838
839 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
840 self.https_state.set(https_state);
841 }
842
843 pub(crate) fn is_fully_active(&self) -> bool {
844 self.activity.get() == DocumentActivity::FullyActive
845 }
846
847 pub(crate) fn is_active(&self) -> bool {
848 self.activity.get() != DocumentActivity::Inactive
849 }
850
851 #[inline]
852 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
853 self.current_rendering_epoch.get()
854 }
855
856 pub(crate) fn set_activity(&self, cx: &mut js::context::JSContext, activity: DocumentActivity) {
857 assert!(self.has_browsing_context);
859 if activity == self.activity.get() {
860 return;
861 }
862
863 self.activity.set(activity);
865 let media = ServoMedia::get();
866 let pipeline_id = self.window().pipeline_id();
867 let client_context_id =
868 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
869
870 if activity != DocumentActivity::FullyActive {
871 self.window().suspend(cx);
872 media.suspend(&client_context_id);
873 return;
874 }
875
876 self.title_changed();
877 self.notify_embedder_favicon();
878 self.dirty_all_nodes();
879 self.window().resume(CanGc::from_cx(cx));
880 media.resume(&client_context_id);
881
882 if self.ready_state.get() != DocumentReadyState::Complete {
883 return;
884 }
885
886 let document = Trusted::new(self);
890 self.owner_global()
891 .task_manager()
892 .dom_manipulation_task_source()
893 .queue(task!(fire_pageshow_event: move || {
894 let document = document.root();
895 let window = document.window();
896 if document.page_showing.get() {
898 return;
899 }
900 document.page_showing.set(true);
902 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
904 let event = PageTransitionEvent::new(
907 window,
908 atom!("pageshow"),
909 false, false, true, CanGc::note(),
913 );
914 let event = event.upcast::<Event>();
915 event.set_trusted(true);
916 window.dispatch_event_with_target_override(event, CanGc::note());
917 }))
918 }
919
920 pub(crate) fn origin(&self) -> &MutableOrigin {
921 &self.origin
922 }
923
924 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
925 *self.protocol_handler_automation_mode.borrow_mut() = mode;
926 }
927
928 pub(crate) fn url(&self) -> ServoUrl {
930 self.url.borrow().clone()
931 }
932
933 pub(crate) fn set_url(&self, url: ServoUrl) {
934 *self.url.borrow_mut() = url;
935 }
936
937 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
938 self.about_base_url.borrow().clone()
939 }
940
941 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
942 *self.about_base_url.borrow_mut() = about_base_url;
943 }
944
945 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
947 let document_url = self.url();
948 if document_url.as_str() == "about:srcdoc" {
950 return self
953 .about_base_url()
954 .expect("about:srcdoc page should always have an about base URL");
955 }
956
957 if document_url.matches_about_blank() {
960 if let Some(about_base_url) = self.about_base_url() {
961 return about_base_url;
962 }
963 }
964
965 document_url
967 }
968
969 pub(crate) fn base_url(&self) -> ServoUrl {
971 match self.base_element() {
972 None => self.fallback_base_url(),
974 Some(base) => base.frozen_base_url(),
976 }
977 }
978
979 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
980 self.needs_restyle.set(self.needs_restyle.get() | reason)
981 }
982
983 pub(crate) fn clear_restyle_reasons(&self) {
984 self.needs_restyle.set(RestyleReason::empty());
985 }
986
987 pub(crate) fn restyle_reason(&self) -> RestyleReason {
988 let mut condition = self.needs_restyle.get();
989 if self.stylesheets.borrow().has_changed() {
990 condition.insert(RestyleReason::StylesheetsChanged);
991 }
992
993 if let Some(root) = self.GetDocumentElement() {
997 if root.upcast::<Node>().has_dirty_descendants() {
998 condition.insert(RestyleReason::DOMChanged);
999 }
1000 }
1001
1002 if !self.pending_restyles.borrow().is_empty() {
1003 condition.insert(RestyleReason::PendingRestyles);
1004 }
1005
1006 condition
1007 }
1008
1009 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1011 self.base_element.get()
1012 }
1013
1014 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1016 self.target_base_element.get()
1017 }
1018
1019 pub(crate) fn refresh_base_element(&self) {
1021 if let Some(base_element) = self.base_element.get() {
1022 base_element.clear_frozen_base_url();
1023 }
1024 let new_base_element = self
1025 .upcast::<Node>()
1026 .traverse_preorder(ShadowIncluding::No)
1027 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1028 .find(|element| {
1029 element
1030 .upcast::<Element>()
1031 .has_attribute(&local_name!("href"))
1032 });
1033 if let Some(ref new_base_element) = new_base_element {
1034 new_base_element.set_frozen_base_url();
1035 }
1036 self.base_element.set(new_base_element.as_deref());
1037
1038 let new_target_base_element = self
1039 .upcast::<Node>()
1040 .traverse_preorder(ShadowIncluding::No)
1041 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1042 .next();
1043 self.target_base_element
1044 .set(new_target_base_element.as_deref());
1045 }
1046
1047 pub(crate) fn dom_count(&self) -> u32 {
1048 self.dom_count.get()
1049 }
1050
1051 pub(crate) fn increment_dom_count(&self) {
1055 self.dom_count.set(self.dom_count.get() + 1);
1056 }
1057
1058 pub(crate) fn decrement_dom_count(&self) {
1060 self.dom_count.set(self.dom_count.get() - 1);
1061 }
1062
1063 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1064 self.quirks_mode.get()
1065 }
1066
1067 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1068 let old_mode = self.quirks_mode.replace(new_mode);
1069
1070 if old_mode != new_mode {
1071 self.window.layout_mut().set_quirks_mode(new_mode);
1072 }
1073 }
1074
1075 pub(crate) fn encoding(&self) -> &'static Encoding {
1076 self.encoding.get()
1077 }
1078
1079 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1080 self.encoding.set(encoding);
1081 }
1082
1083 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1084 if node.is_connected() {
1085 node.note_dirty_descendants();
1086 }
1087
1088 node.dirty(NodeDamage::ContentOrHeritage);
1091 }
1092
1093 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1095 self.document_or_shadow_root
1096 .unregister_named_element(&self.id_map, to_unregister, &id);
1097 self.reset_form_owner_for_listeners(&id, can_gc);
1098 }
1099
1100 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1102 let root = self.GetDocumentElement().expect(
1103 "The element is in the document, so there must be a document \
1104 element.",
1105 );
1106 self.document_or_shadow_root.register_named_element(
1107 &self.id_map,
1108 element,
1109 &id,
1110 DomRoot::from_ref(root.upcast::<Node>()),
1111 );
1112 self.reset_form_owner_for_listeners(&id, can_gc);
1113 }
1114
1115 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1117 self.document_or_shadow_root
1118 .unregister_named_element(&self.name_map, to_unregister, &name);
1119 }
1120
1121 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1123 let root = self.GetDocumentElement().expect(
1124 "The element is in the document, so there must be a document \
1125 element.",
1126 );
1127 self.document_or_shadow_root.register_named_element(
1128 &self.name_map,
1129 element,
1130 &name,
1131 DomRoot::from_ref(root.upcast::<Node>()),
1132 );
1133 }
1134
1135 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1136 &self,
1137 id: DOMString,
1138 listener: &T,
1139 ) {
1140 let mut map = self.form_id_listener_map.borrow_mut();
1141 let listener = listener.to_element();
1142 let set = map.entry(Atom::from(id)).or_default();
1143 set.insert(Dom::from_ref(listener));
1144 }
1145
1146 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1147 &self,
1148 id: DOMString,
1149 listener: &T,
1150 ) {
1151 let mut map = self.form_id_listener_map.borrow_mut();
1152 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1153 entry
1154 .get_mut()
1155 .remove(&Dom::from_ref(listener.to_element()));
1156 if entry.get().is_empty() {
1157 entry.remove();
1158 }
1159 }
1160 }
1161
1162 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1164 self.get_element_by_id(&Atom::from(fragment))
1168 .or_else(|| self.get_anchor_by_name(fragment))
1172 }
1173
1174 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1177 if fragment.is_empty() {
1187 return Some(DomRoot::from_ref(self.upcast()));
1188 }
1189 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1191 {
1192 return Some(DomRoot::upcast(potential_indicated_element));
1194 }
1195 let fragment_bytes = percent_decode(fragment.as_bytes());
1197 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1199 return None;
1200 };
1201 if let Some(potential_indicated_element) =
1203 self.find_a_potential_indicated_element(&decoded_fragment)
1204 {
1205 return Some(DomRoot::upcast(potential_indicated_element));
1207 }
1208 if decoded_fragment.eq_ignore_ascii_case("top") {
1210 return Some(DomRoot::from_ref(self.upcast()));
1211 }
1212 None
1214 }
1215
1216 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str) {
1218 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1223 self.set_target_element(None);
1224 return;
1225 };
1226 if *indicated_part == *self.upcast() {
1228 self.set_target_element(None);
1230 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1235 return;
1237 }
1238 let Some(target) = indicated_part.downcast::<Element>() else {
1241 unreachable!("Indicated part should always be an element");
1243 };
1244 self.set_target_element(Some(target));
1246 target.scroll_into_view_with_options(
1250 ScrollBehavior::Auto,
1251 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1252 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1253 None,
1254 None,
1255 );
1256 }
1261
1262 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1263 let name = Atom::from(name);
1264 self.name_map.borrow().get(&name).and_then(|elements| {
1265 elements
1266 .iter()
1267 .find(|e| e.is::<HTMLAnchorElement>())
1268 .map(|e| DomRoot::from_ref(&**e))
1269 })
1270 }
1271
1272 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1274 match state {
1275 DocumentReadyState::Loading => {
1276 if self.window().is_top_level() {
1277 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1278 self.webview_id(),
1279 LoadStatus::Started,
1280 ));
1281 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1282 }
1283 },
1284 DocumentReadyState::Complete => {
1285 if self.window().is_top_level() {
1286 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1287 self.webview_id(),
1288 LoadStatus::Complete,
1289 ));
1290 }
1291 update_with_current_instant(&self.dom_complete);
1292 },
1293 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1294 };
1295
1296 self.ready_state.set(state);
1297
1298 self.upcast::<EventTarget>()
1299 .fire_event(atom!("readystatechange"), can_gc);
1300 }
1301
1302 pub(crate) fn scripting_enabled(&self) -> bool {
1305 self.has_browsing_context() &&
1308 !self.has_active_sandboxing_flag(
1312 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1313 )
1314 }
1315
1316 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1319 self.focused.get()
1320 }
1321
1322 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1327 self.focus_sequence.get()
1328 }
1329
1330 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1332 self.focus_sequence.set(FocusSequenceNumber(
1333 self.focus_sequence
1334 .get()
1335 .0
1336 .checked_add(1)
1337 .expect("too many focus messages have been sent"),
1338 ));
1339 self.focus_sequence.get()
1340 }
1341
1342 pub(crate) fn has_focus_transaction(&self) -> bool {
1343 self.focus_transaction.borrow().is_some()
1344 }
1345
1346 pub(crate) fn begin_focus_transaction(&self) {
1349 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1351 element: self.focused.get().as_deref().map(Dom::from_ref),
1352 has_focus: self.has_focus.get(),
1353 focus_options: FocusOptions {
1354 preventScroll: true,
1355 },
1356 });
1357 }
1358
1359 pub(crate) fn perform_focus_fixup_rule(&self, can_gc: CanGc) {
1366 if self
1367 .focused
1368 .get()
1369 .as_deref()
1370 .is_none_or(|focused| focused.is_focusable_area())
1371 {
1372 return;
1373 }
1374 self.request_focus(None, FocusInitiator::Script, can_gc);
1375 }
1376
1377 pub(crate) fn request_focus(
1380 &self,
1381 elem: Option<&Element>,
1382 focus_initiator: FocusInitiator,
1383 can_gc: CanGc,
1384 ) {
1385 self.request_focus_with_options(
1386 elem,
1387 focus_initiator,
1388 FocusOptions {
1389 preventScroll: true,
1390 },
1391 can_gc,
1392 );
1393 }
1394
1395 pub(crate) fn request_focus_with_options(
1401 &self,
1402 target: Option<&Element>,
1403 focus_initiator: FocusInitiator,
1404 focus_options: FocusOptions,
1405 can_gc: CanGc,
1406 ) {
1407 if target.is_some_and(|target| match focus_initiator {
1409 FocusInitiator::Keyboard => !target.is_sequentially_focusable(),
1410 FocusInitiator::Click => !target.is_click_focusable(),
1411 FocusInitiator::Script | FocusInitiator::Remote => !target.is_focusable_area(),
1412 }) {
1413 return;
1414 }
1415
1416 let implicit_transaction = self.focus_transaction.borrow().is_none();
1417
1418 if implicit_transaction {
1419 self.begin_focus_transaction();
1420 }
1421
1422 {
1423 let mut focus_transaction = self.focus_transaction.borrow_mut();
1424 let focus_transaction = focus_transaction.as_mut().unwrap();
1425 focus_transaction.element = target.map(Dom::from_ref);
1426 focus_transaction.has_focus = true;
1427 focus_transaction.focus_options = focus_options;
1428 }
1429
1430 if implicit_transaction {
1431 self.commit_focus_transaction(focus_initiator, can_gc);
1432 }
1433 }
1434
1435 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1439 if self.window().parent_info().is_none() {
1440 warn!("Top-level document cannot be unfocused");
1441 return;
1442 }
1443
1444 assert!(
1447 self.focus_transaction.borrow().is_none(),
1448 "there mustn't be an in-progress focus transaction at this point"
1449 );
1450
1451 self.begin_focus_transaction();
1453
1454 {
1456 let mut focus_transaction = self.focus_transaction.borrow_mut();
1457 focus_transaction.as_mut().unwrap().has_focus = false;
1458 }
1459
1460 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1462 }
1463
1464 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1467 let (mut new_focused, new_focus_state, prevent_scroll) = {
1468 let focus_transaction = self.focus_transaction.borrow();
1469 let focus_transaction = focus_transaction
1470 .as_ref()
1471 .expect("no focus transaction in progress");
1472 (
1473 focus_transaction
1474 .element
1475 .as_ref()
1476 .map(|e| DomRoot::from_ref(&**e)),
1477 focus_transaction.has_focus,
1478 focus_transaction.focus_options.preventScroll,
1479 )
1480 };
1481 *self.focus_transaction.borrow_mut() = None;
1482
1483 if !new_focus_state {
1484 if new_focused.take().is_some() {
1487 trace!(
1488 "Forgetting the document's focused area because the \
1489 document's container was removed from the top-level BC's \
1490 focus chain"
1491 );
1492 }
1493 }
1494
1495 let old_focused = self.focused.get();
1496 let old_focus_state = self.has_focus.get();
1497
1498 debug!(
1499 "Committing focus transaction: {:?} → {:?}",
1500 (&old_focused, old_focus_state),
1501 (&new_focused, new_focus_state),
1502 );
1503
1504 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1507 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1508
1509 let trace_focus_chain = |name, element, doc| {
1510 trace!(
1511 "{} local focus chain: {}",
1512 name,
1513 match (element, doc) {
1514 (Some(e), _) => format!("[{:?}, document]", e),
1515 (None, true) => "[document]".to_owned(),
1516 (None, false) => "[]".to_owned(),
1517 }
1518 );
1519 };
1520
1521 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1522 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1523
1524 if old_focused_filtered != new_focused_filtered {
1525 if let Some(elem) = &old_focused_filtered {
1526 let node = elem.upcast::<Node>();
1527 elem.set_focus_state(false);
1528 if node.is_connected() {
1530 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1531 }
1532 }
1533 }
1534
1535 if old_focus_state != new_focus_state && !new_focus_state {
1536 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1537 }
1538
1539 self.focused.set(new_focused.as_deref());
1540 self.has_focus.set(new_focus_state);
1541
1542 if old_focus_state != new_focus_state && new_focus_state {
1543 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1544 }
1545
1546 if old_focused_filtered != new_focused_filtered {
1547 if let Some(elem) = &new_focused_filtered {
1548 elem.set_focus_state(true);
1549 let node = elem.upcast::<Node>();
1550 if let Some(html_element) = elem.downcast::<HTMLElement>() {
1551 html_element.handle_focus_state_for_contenteditable(can_gc);
1552 }
1553 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1555
1556 if !prevent_scroll {
1559 let scroll_axis = ScrollAxisState {
1562 position: ScrollLogicalPosition::Center,
1563 requirement: ScrollRequirement::IfNotVisible,
1564 };
1565
1566 elem.scroll_into_view_with_options(
1570 ScrollBehavior::Smooth,
1571 scroll_axis,
1572 scroll_axis,
1573 None,
1574 None,
1575 );
1576 }
1577 }
1578 }
1579
1580 if focus_initiator == FocusInitiator::Remote {
1581 return;
1582 }
1583
1584 match (old_focus_state, new_focus_state) {
1587 (_, true) => {
1588 let child_browsing_context_id = new_focused
1609 .as_ref()
1610 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1611 .and_then(|iframe| iframe.browsing_context_id());
1612
1613 let sequence = self.increment_fetch_focus_sequence();
1614
1615 debug!(
1616 "Advertising the focus request to the constellation \
1617 with sequence number {} and child BC ID {}",
1618 sequence,
1619 child_browsing_context_id
1620 .as_ref()
1621 .map(|id| id as &dyn std::fmt::Display)
1622 .unwrap_or(&"(none)"),
1623 );
1624
1625 self.window()
1626 .send_to_constellation(ScriptToConstellationMessage::Focus(
1627 child_browsing_context_id,
1628 sequence,
1629 ));
1630 },
1631 (false, false) => {
1632 },
1635 (true, false) => {
1636 unreachable!(
1637 "Can't lose the document's focus without specifying \
1638 another one to focus"
1639 );
1640 },
1641 }
1642 }
1643
1644 pub(crate) fn title_changed(&self) {
1646 if self.browsing_context().is_some() {
1647 self.send_title_to_embedder();
1648 let title = String::from(self.Title());
1649 self.window
1650 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1651 self.window.pipeline_id(),
1652 title.clone(),
1653 ));
1654 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1655 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1656 self.window.pipeline_id(),
1657 title,
1658 ));
1659 }
1660 }
1661 }
1662
1663 fn title(&self) -> Option<DOMString> {
1667 let title = self.GetDocumentElement().and_then(|root| {
1668 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1669 root.upcast::<Node>()
1671 .child_elements()
1672 .find(|node| {
1673 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1674 })
1675 .map(DomRoot::upcast::<Node>)
1676 } else {
1677 root.upcast::<Node>()
1679 .traverse_preorder(ShadowIncluding::No)
1680 .find(|node| node.is::<HTMLTitleElement>())
1681 }
1682 });
1683
1684 title.map(|title| {
1685 let value = title.child_text_content();
1687 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1688 })
1689 }
1690
1691 pub(crate) fn send_title_to_embedder(&self) {
1693 let window = self.window();
1694 if window.is_top_level() {
1695 let title = self.title().map(String::from);
1696 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1697 }
1698 }
1699
1700 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1701 let window = self.window();
1702 window.send_to_embedder(msg);
1703 }
1704
1705 pub(crate) fn dirty_all_nodes(&self) {
1706 let root = match self.GetDocumentElement() {
1707 Some(root) => root,
1708 None => return,
1709 };
1710 for node in root
1711 .upcast::<Node>()
1712 .traverse_preorder(ShadowIncluding::Yes)
1713 {
1714 node.dirty(NodeDamage::Other)
1715 }
1716 }
1717
1718 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1720 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1732 for target in notify_list.iter() {
1733 if target.downcast::<Document>().is_some() {
1734 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1737 } else if target.downcast::<Element>().is_some() {
1738 target.fire_event(Atom::from("scroll"), can_gc);
1741 }
1742 }
1743
1744 }
1748
1749 pub(crate) fn handle_viewport_scroll_event(&self) {
1753 let target = self.upcast::<EventTarget>();
1762 if self
1763 .pending_scroll_event_targets
1764 .borrow()
1765 .iter()
1766 .any(|other_target| *other_target == target)
1767 {
1768 return;
1769 }
1770
1771 self.pending_scroll_event_targets
1774 .borrow_mut()
1775 .push(Dom::from_ref(target));
1776 }
1777
1778 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1782 let target = element.upcast::<EventTarget>();
1792 if self
1793 .pending_scroll_event_targets
1794 .borrow()
1795 .iter()
1796 .any(|other_target| *other_target == target)
1797 {
1798 return;
1799 }
1800
1801 self.pending_scroll_event_targets
1804 .borrow_mut()
1805 .push(Dom::from_ref(target));
1806 }
1807
1808 pub(crate) fn node_from_nodes_and_strings(
1810 &self,
1811 mut nodes: Vec<NodeOrString>,
1812 can_gc: CanGc,
1813 ) -> Fallible<DomRoot<Node>> {
1814 if nodes.len() == 1 {
1815 Ok(match nodes.pop().unwrap() {
1816 NodeOrString::Node(node) => node,
1817 NodeOrString::String(string) => {
1818 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1819 },
1820 })
1821 } else {
1822 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1823 for node in nodes {
1824 match node {
1825 NodeOrString::Node(node) => {
1826 fragment.AppendChild(&node, can_gc)?;
1827 },
1828 NodeOrString::String(string) => {
1829 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1830 fragment.AppendChild(&node, can_gc).unwrap();
1833 },
1834 }
1835 }
1836 Ok(fragment)
1837 }
1838 }
1839
1840 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1841 match self.GetBody() {
1842 Some(ref body) if body.is_body_element() => {
1843 body.upcast::<Element>().get_string_attribute(local_name)
1844 },
1845 _ => DOMString::new(),
1846 }
1847 }
1848
1849 pub(crate) fn set_body_attribute(
1850 &self,
1851 local_name: &LocalName,
1852 value: DOMString,
1853 can_gc: CanGc,
1854 ) {
1855 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1856 let body = body.upcast::<Element>();
1857 let value = body.parse_attribute(&ns!(), local_name, value);
1858 body.set_attribute(local_name, value, can_gc);
1859 }
1860 }
1861
1862 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1863 self.current_script.set(script);
1864 }
1865
1866 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1867 self.script_blocking_stylesheets_count.get()
1868 }
1869
1870 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1871 let count_cell = &self.script_blocking_stylesheets_count;
1872 count_cell.set(count_cell.get() + 1);
1873 }
1874
1875 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1876 let count_cell = &self.script_blocking_stylesheets_count;
1877 assert!(count_cell.get() > 0);
1878 count_cell.set(count_cell.get() - 1);
1879 }
1880
1881 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1882 self.render_blocking_element_count.get()
1883 }
1884
1885 pub(crate) fn increment_render_blocking_element_count(&self) {
1887 assert!(self.allows_adding_render_blocking_elements());
1894 let count_cell = &self.render_blocking_element_count;
1895 count_cell.set(count_cell.get() + 1);
1896 }
1897
1898 pub(crate) fn decrement_render_blocking_element_count(&self) {
1900 let count_cell = &self.render_blocking_element_count;
1906 assert!(count_cell.get() > 0);
1907 count_cell.set(count_cell.get() - 1);
1908 }
1909
1910 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1912 self.is_html_document && self.GetBody().is_none()
1915 }
1916
1917 pub(crate) fn is_render_blocked(&self) -> bool {
1919 self.render_blocking_element_count() > 0
1923 }
1928
1929 pub(crate) fn invalidate_stylesheets(&self) {
1930 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1931
1932 if let Some(element) = self.GetDocumentElement() {
1936 element.upcast::<Node>().dirty(NodeDamage::Style);
1937 }
1938 }
1939
1940 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1943 !self.animation_frame_list.borrow().is_empty()
1944 }
1945
1946 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1948 let ident = self.animation_frame_ident.get() + 1;
1949 self.animation_frame_ident.set(ident);
1950
1951 let had_animation_frame_callbacks;
1952 {
1953 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1954 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1955 animation_frame_list.push_back((ident, Some(callback)));
1956 }
1957
1958 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1964 self.window().send_to_constellation(
1965 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1966 AnimationState::AnimationCallbacksPresent,
1967 ),
1968 );
1969 }
1970
1971 ident
1972 }
1973
1974 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1976 let mut list = self.animation_frame_list.borrow_mut();
1977 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1978 pair.1 = None;
1979 }
1980 }
1981
1982 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1984 let _realm = enter_realm(self);
1985
1986 self.running_animation_callbacks.set(true);
1987 let timing = self.global().performance().Now();
1988
1989 let num_callbacks = self.animation_frame_list.borrow().len();
1990 for _ in 0..num_callbacks {
1991 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1992 if let Some(callback) = maybe_callback {
1993 callback.call(self, *timing, can_gc);
1994 }
1995 }
1996 self.running_animation_callbacks.set(false);
1997
1998 if self.animation_frame_list.borrow().is_empty() {
1999 self.window().send_to_constellation(
2000 ScriptToConstellationMessage::ChangeRunningAnimationsState(
2001 AnimationState::NoAnimationCallbacksPresent,
2002 ),
2003 );
2004 }
2005 }
2006
2007 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
2008 self.policy_container.borrow()
2009 }
2010
2011 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
2012 *self.policy_container.borrow_mut() = policy_container;
2013 }
2014
2015 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
2016 self.policy_container.borrow_mut().set_csp_list(csp_list);
2017 }
2018
2019 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
2021 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
2023 csp_list.push(policy);
2024 self.policy_container
2025 .borrow_mut()
2026 .set_csp_list(Some(csp_list));
2027 }
2028
2029 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
2030 Ref::map(self.policy_container.borrow(), |policy_container| {
2031 &policy_container.csp_list
2032 })
2033 }
2034
2035 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
2036 self.preloaded_resources.borrow()
2037 }
2038
2039 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
2040 self.preloaded_resources
2041 .borrow_mut()
2042 .insert(key, preload_id);
2043 }
2044
2045 pub(crate) fn fetch<Listener: FetchResponseListener>(
2046 &self,
2047 load: LoadType,
2048 mut request: RequestBuilder,
2049 listener: Listener,
2050 ) {
2051 request = request
2052 .insecure_requests_policy(self.insecure_requests_policy())
2053 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2054 let callback = NetworkListener {
2055 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2056 task_source: self
2057 .owner_global()
2058 .task_manager()
2059 .networking_task_source()
2060 .into(),
2061 }
2062 .into_callback();
2063 self.loader_mut()
2064 .fetch_async_with_callback(load, request, callback);
2065 }
2066
2067 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
2068 &self,
2069 mut request: RequestBuilder,
2070 listener: Listener,
2071 ) {
2072 request = request
2073 .insecure_requests_policy(self.insecure_requests_policy())
2074 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2075 let callback = NetworkListener {
2076 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2077 task_source: self
2078 .owner_global()
2079 .task_manager()
2080 .networking_task_source()
2081 .into(),
2082 }
2083 .into_callback();
2084 self.loader_mut().fetch_async_background(request, callback);
2085 }
2086
2087 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
2089 match self.window().window_proxy().frame_element() {
2090 None => DomRoot::from_ref(self),
2093 Some(container) => container.owner_document().deferred_fetch_control_document(),
2095 }
2096 }
2097
2098 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
2100 let control_document = self.deferred_fetch_control_document();
2102 let navigable = control_document.window();
2104 let is_top_level = navigable.is_top_level();
2107 let deferred_fetch_allowed = true;
2111 let deferred_fetch_minimal_allowed = true;
2115 let mut quota = match is_top_level {
2117 true if !deferred_fetch_allowed => 0,
2119 true if !deferred_fetch_minimal_allowed => 640 * 1024,
2121 true => 512 * 1024,
2123 _ if deferred_fetch_allowed => 0,
2127 _ if deferred_fetch_minimal_allowed => 8 * 1024,
2131 _ => 0,
2133 } as isize;
2134 let mut quota_for_request_origin = 64 * 1024_isize;
2136 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
2145 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
2147 continue;
2148 }
2149 let request_length = deferred_fetch.request.total_request_length();
2151 quota -= request_length as isize;
2153 if deferred_fetch.request.url().origin() == origin {
2156 quota_for_request_origin -= request_length as isize;
2157 }
2158 }
2159 if quota <= 0 {
2161 return 0;
2162 }
2163 if quota < quota_for_request_origin {
2165 return quota;
2166 }
2167 quota_for_request_origin
2169 }
2170
2171 pub(crate) fn update_document_for_history_step_application(
2173 &self,
2174 old_url: &ServoUrl,
2175 new_url: &ServoUrl,
2176 ) {
2177 if old_url.as_url()[Position::BeforeFragment..] !=
2207 new_url.as_url()[Position::BeforeFragment..]
2208 {
2209 let window = Trusted::new(self.owner_window().deref());
2210 let old_url = old_url.to_string();
2211 let new_url = new_url.to_string();
2212 self.owner_global()
2213 .task_manager()
2214 .dom_manipulation_task_source()
2215 .queue(task!(hashchange_event: move || {
2216 let window = window.root();
2217 HashChangeEvent::new(
2218 &window,
2219 atom!("hashchange"),
2220 false,
2221 false,
2222 old_url,
2223 new_url,
2224 CanGc::note(),
2225 )
2226 .upcast::<Event>()
2227 .fire(window.upcast(), CanGc::note());
2228 }));
2229 }
2230 }
2231
2232 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut js::context::JSContext) {
2235 debug!("Document got finish_load: {:?}", load);
2237 self.loader.borrow_mut().finish_load(&load);
2238
2239 match load {
2240 LoadType::Stylesheet(_) => {
2241 self.process_pending_parsing_blocking_script(cx);
2244
2245 self.process_deferred_scripts(CanGc::from_cx(cx));
2247 },
2248 LoadType::PageSource(_) => {
2249 if self.has_browsing_context && self.is_fully_active() {
2252 self.window().allow_layout_if_necessary();
2253 }
2254
2255 self.process_deferred_scripts(CanGc::from_cx(cx));
2260 },
2261 _ => {},
2262 }
2263
2264 let loader = self.loader.borrow();
2271
2272 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
2274 update_with_current_instant(&self.top_level_dom_complete);
2275 }
2276
2277 if loader.is_blocked() || loader.events_inhibited() {
2278 return;
2280 }
2281
2282 ScriptThread::mark_document_with_no_blocked_loads(self);
2283 }
2284
2285 pub(crate) fn check_if_unloading_is_cancelled(
2287 &self,
2288 recursive_flag: bool,
2289 can_gc: CanGc,
2290 ) -> bool {
2291 self.incr_ignore_opens_during_unload_counter();
2294 let beforeunload_event = BeforeUnloadEvent::new(
2296 &self.window,
2297 atom!("beforeunload"),
2298 EventBubbles::Bubbles,
2299 EventCancelable::Cancelable,
2300 can_gc,
2301 );
2302 let event = beforeunload_event.upcast::<Event>();
2303 event.set_trusted(true);
2304 let event_target = self.window.upcast::<EventTarget>();
2305 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2306 self.window
2307 .dispatch_event_with_target_override(event, can_gc);
2308 if has_listeners {
2311 self.salvageable.set(false);
2312 }
2313 let mut can_unload = true;
2314 let default_prevented = event.DefaultPrevented();
2316 let return_value_not_empty = !event
2317 .downcast::<BeforeUnloadEvent>()
2318 .unwrap()
2319 .ReturnValue()
2320 .is_empty();
2321 if default_prevented || return_value_not_empty {
2322 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2323 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2324 self.send_to_embedder(msg);
2325 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2326 }
2327 if !recursive_flag {
2329 let iframes: Vec<_> = self.iframes().iter().collect();
2332 for iframe in &iframes {
2333 let document = iframe.owner_document();
2335 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2336 if !document.salvageable() {
2337 self.salvageable.set(false);
2338 }
2339 if !can_unload {
2340 break;
2341 }
2342 }
2343 }
2344 self.decr_ignore_opens_during_unload_counter();
2346 can_unload
2347 }
2348
2349 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2351 self.incr_ignore_opens_during_unload_counter();
2354 if self.page_showing.get() {
2356 self.page_showing.set(false);
2358 let event = PageTransitionEvent::new(
2361 &self.window,
2362 atom!("pagehide"),
2363 false, false, self.salvageable.get(), can_gc,
2367 );
2368 let event = event.upcast::<Event>();
2369 event.set_trusted(true);
2370 self.window
2371 .dispatch_event_with_target_override(event, can_gc);
2372 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2374 }
2375 if !self.fired_unload.get() {
2377 let event = Event::new(
2378 self.window.upcast(),
2379 atom!("unload"),
2380 EventBubbles::Bubbles,
2381 EventCancelable::Cancelable,
2382 can_gc,
2383 );
2384 event.set_trusted(true);
2385 let event_target = self.window.upcast::<EventTarget>();
2386 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2387 self.window
2388 .dispatch_event_with_target_override(&event, can_gc);
2389 self.fired_unload.set(true);
2390 if has_listeners {
2392 self.salvageable.set(false);
2393 }
2394 }
2395 if !recursive_flag {
2399 let iframes: Vec<_> = self.iframes().iter().collect();
2402 for iframe in &iframes {
2403 let document = iframe.owner_document();
2405 document.unload(true, can_gc);
2406 if !document.salvageable() {
2407 self.salvageable.set(false);
2408 }
2409 }
2410 }
2411
2412 self.unloading_cleanup_steps();
2414
2415 self.window.as_global_scope().clean_up_all_file_resources();
2417
2418 self.decr_ignore_opens_during_unload_counter();
2420
2421 }
2424
2425 fn completely_finish_loading(&self) {
2427 self.completely_loaded.set(true);
2432 self.notify_constellation_load();
2441
2442 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2451 &*self.declarative_refresh.borrow()
2452 {
2453 self.window.as_global_scope().schedule_callback(
2454 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2455 window: DomRoot::from_ref(self.window()),
2456 url: url.clone(),
2457 }),
2458 Duration::from_secs(*time),
2459 );
2460 }
2461 }
2462
2463 pub(crate) fn maybe_queue_document_completion(&self) {
2465 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2467 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2468 None => false,
2469 };
2470
2471 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2476 !self.is_fully_active() ||
2477 is_in_delaying_load_events_mode ||
2478 self.loader.borrow().events_inhibited();
2481
2482 if not_ready_for_load {
2483 return;
2485 }
2486
2487 self.loader.borrow_mut().inhibit_events();
2488
2489 debug!("Document loads are complete.");
2494 let document = Trusted::new(self);
2495 self.owner_global()
2496 .task_manager()
2497 .dom_manipulation_task_source()
2498 .queue(task!(fire_load_event: move || {
2499 let document = document.root();
2500 let window = document.window();
2502 if !window.is_alive() {
2503 return;
2504 }
2505
2506 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2508
2509 if document.browsing_context().is_none() {
2511 return;
2512 }
2513
2514 update_with_current_instant(&document.load_event_start);
2516
2517 let load_event = Event::new(
2519 window.upcast(),
2520 atom!("load"),
2521 EventBubbles::DoesNotBubble,
2522 EventCancelable::NotCancelable,
2523 CanGc::note(),
2524 );
2525 load_event.set_trusted(true);
2526 debug!("About to dispatch load for {:?}", document.url());
2527 window.dispatch_event_with_target_override(&load_event, CanGc::note());
2528
2529 update_with_current_instant(&document.load_event_end);
2539
2540 document.page_showing.set(true);
2545
2546 let page_show_event = PageTransitionEvent::new(
2548 window,
2549 atom!("pageshow"),
2550 false, false, false, CanGc::note(),
2554 );
2555 let page_show_event = page_show_event.upcast::<Event>();
2556 page_show_event.set_trusted(true);
2557 page_show_event.fire(window.upcast(), CanGc::note());
2558
2559 document.completely_finish_loading();
2561
2562 if let Some(fragment) = document.url().fragment() {
2566 document.scroll_to_the_fragment(fragment);
2567 }
2568 }));
2569
2570 #[cfg(feature = "webxr")]
2585 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2586 self.window.Navigator().Xr().dispatch_sessionavailable();
2587 }
2588 }
2589
2590 pub(crate) fn completely_loaded(&self) -> bool {
2591 self.completely_loaded.get()
2592 }
2593
2594 pub(crate) fn set_pending_parsing_blocking_script(
2596 &self,
2597 script: &HTMLScriptElement,
2598 load: Option<ScriptResult>,
2599 ) {
2600 assert!(!self.has_pending_parsing_blocking_script());
2601 *self.pending_parsing_blocking_script.borrow_mut() =
2602 Some(PendingScript::new_with_load(script, load));
2603 }
2604
2605 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2607 self.pending_parsing_blocking_script.borrow().is_some()
2608 }
2609
2610 pub(crate) fn pending_parsing_blocking_script_loaded(
2612 &self,
2613 element: &HTMLScriptElement,
2614 result: ScriptResult,
2615 cx: &mut js::context::JSContext,
2616 ) {
2617 {
2618 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2619 let entry = blocking_script.as_mut().unwrap();
2620 assert!(&*entry.element == element);
2621 entry.loaded(result);
2622 }
2623 self.process_pending_parsing_blocking_script(cx);
2624 }
2625
2626 fn process_pending_parsing_blocking_script(&self, cx: &mut js::context::JSContext) {
2627 if self.script_blocking_stylesheets_count.get() > 0 {
2628 return;
2629 }
2630 let pair = self
2631 .pending_parsing_blocking_script
2632 .borrow_mut()
2633 .as_mut()
2634 .and_then(PendingScript::take_result);
2635 if let Some((element, result)) = pair {
2636 *self.pending_parsing_blocking_script.borrow_mut() = None;
2637 self.get_current_parser()
2638 .unwrap()
2639 .resume_with_pending_parsing_blocking_script(&element, result, cx);
2640 }
2641 }
2642
2643 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2645 self.asap_scripts_set
2646 .borrow_mut()
2647 .push(Dom::from_ref(script));
2648 }
2649
2650 pub(crate) fn asap_script_loaded(
2653 &self,
2654 element: &HTMLScriptElement,
2655 result: ScriptResult,
2656 can_gc: CanGc,
2657 ) {
2658 {
2659 let mut scripts = self.asap_scripts_set.borrow_mut();
2660 let idx = scripts
2661 .iter()
2662 .position(|entry| &**entry == element)
2663 .unwrap();
2664 scripts.swap_remove(idx);
2665 }
2666 element.execute(result, can_gc);
2667 }
2668
2669 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2671 self.asap_in_order_scripts_list.push(script);
2672 }
2673
2674 pub(crate) fn asap_in_order_script_loaded(
2677 &self,
2678 element: &HTMLScriptElement,
2679 result: ScriptResult,
2680 can_gc: CanGc,
2681 ) {
2682 self.asap_in_order_scripts_list.loaded(element, result);
2683 while let Some((element, result)) = self
2684 .asap_in_order_scripts_list
2685 .take_next_ready_to_be_executed()
2686 {
2687 element.execute(result, can_gc);
2688 }
2689 }
2690
2691 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2693 self.deferred_scripts.push(script);
2694 }
2695
2696 pub(crate) fn deferred_script_loaded(
2699 &self,
2700 element: &HTMLScriptElement,
2701 result: ScriptResult,
2702 can_gc: CanGc,
2703 ) {
2704 self.deferred_scripts.loaded(element, result);
2705 self.process_deferred_scripts(can_gc);
2706 }
2707
2708 fn process_deferred_scripts(&self, can_gc: CanGc) {
2710 if self.ready_state.get() != DocumentReadyState::Interactive {
2711 return;
2712 }
2713 loop {
2715 if self.script_blocking_stylesheets_count.get() > 0 {
2716 return;
2717 }
2718 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2719 {
2720 element.execute(result, can_gc);
2721 } else {
2722 break;
2723 }
2724 }
2725 if self.deferred_scripts.is_empty() {
2726 self.maybe_dispatch_dom_content_loaded();
2728 }
2729 }
2730
2731 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2733 if self.domcontentloaded_dispatched.get() {
2734 return;
2735 }
2736 self.domcontentloaded_dispatched.set(true);
2737 assert_ne!(
2738 self.ReadyState(),
2739 DocumentReadyState::Complete,
2740 "Complete before DOMContentLoaded?"
2741 );
2742
2743 let document = Trusted::new(self);
2746 self.owner_global()
2747 .task_manager()
2748 .dom_manipulation_task_source()
2749 .queue(
2750 task!(fire_dom_content_loaded_event: move || {
2751 let document = document.root();
2752
2753 update_with_current_instant(&document.dom_content_loaded_event_start);
2756
2757 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2760
2761 update_with_current_instant(&document.dom_content_loaded_event_end);
2764
2765 })
2772 );
2773
2774 self.interactive_time
2776 .borrow()
2777 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2778
2779 }
2782
2783 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut js::context::JSContext) {
2785 if !self.is_fully_active() {
2787 self.salvageable.set(false);
2792 }
2796 for exited_iframe in self.iframes().iter() {
2809 debug!("Destroying nested iframe document");
2810 exited_iframe.destroy_document_and_its_descendants(cx);
2811 }
2812 self.destroy(cx);
2817 }
2820
2821 pub(crate) fn destroy(&self, cx: &mut js::context::JSContext) {
2823 let exited_window = self.window();
2824 self.abort(cx);
2826 self.salvageable.set(false);
2828 self.unloading_cleanup_steps();
2838
2839 exited_window
2842 .as_global_scope()
2843 .task_manager()
2844 .cancel_all_tasks_and_ignore_future_tasks();
2845
2846 exited_window.discard_browsing_context();
2848
2849 }
2861
2862 fn terminate_fetch_group(&self) -> bool {
2864 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2865
2866 for canceller in &mut load_cancellers {
2870 if !canceller.keep_alive() {
2871 canceller.terminate();
2872 }
2873 }
2874 self.owner_global().process_deferred_fetches();
2876
2877 !load_cancellers.is_empty()
2878 }
2879
2880 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
2882 self.loader.borrow_mut().inhibit_events();
2884
2885 for iframe in self.iframes().iter() {
2887 if let Some(document) = iframe.GetContentDocument() {
2888 document.abort(cx);
2889 }
2890 }
2891
2892 self.script_blocking_stylesheets_count.set(0);
2898 *self.pending_parsing_blocking_script.borrow_mut() = None;
2899 *self.asap_scripts_set.borrow_mut() = vec![];
2900 self.asap_in_order_scripts_list.clear();
2901 self.deferred_scripts.clear();
2902 let loads_cancelled = self.terminate_fetch_group();
2903 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2904 if loads_cancelled || event_sources_canceled {
2905 self.salvageable.set(false);
2907 };
2908
2909 self.owner_global()
2914 .task_manager()
2915 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2916
2917 if let Some(parser) = self.get_current_parser() {
2922 self.active_parser_was_aborted.set(true);
2924 parser.abort(cx);
2926 self.salvageable.set(false);
2928 }
2929 }
2930
2931 pub(crate) fn notify_constellation_load(&self) {
2932 self.window()
2933 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2934 }
2935
2936 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2937 self.current_parser.set(script);
2938 }
2939
2940 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2941 self.current_parser.get()
2942 }
2943
2944 pub(crate) fn get_current_parser_line(&self) -> u32 {
2945 self.get_current_parser()
2946 .map(|parser| parser.get_current_line())
2947 .unwrap_or(0)
2948 }
2949
2950 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2953 self.iframes.borrow_mut().validate(self);
2954 self.iframes.borrow()
2955 }
2956
2957 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2960 self.iframes.borrow_mut().validate(self);
2961 self.iframes.borrow_mut()
2962 }
2963
2964 pub(crate) fn invalidate_iframes_collection(&self) {
2965 self.iframes.borrow_mut().invalidate();
2966 }
2967
2968 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2969 self.dom_interactive.get()
2970 }
2971
2972 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2973 self.interactive_time
2974 .borrow_mut()
2975 .set_navigation_start(navigation_start);
2976 }
2977
2978 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2979 self.interactive_time.borrow()
2980 }
2981
2982 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2983 self.get_interactive_metrics().get_tti().is_some()
2984 }
2985
2986 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2987 self.dom_content_loaded_event_start.get()
2988 }
2989
2990 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2991 self.dom_content_loaded_event_end.get()
2992 }
2993
2994 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2995 self.dom_complete.get()
2996 }
2997
2998 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2999 self.top_level_dom_complete.get()
3000 }
3001
3002 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
3003 self.load_event_start.get()
3004 }
3005
3006 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
3007 self.load_event_end.get()
3008 }
3009
3010 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
3011 self.unload_event_start.get()
3012 }
3013
3014 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
3015 self.unload_event_end.get()
3016 }
3017
3018 pub(crate) fn start_tti(&self) {
3019 if self.get_interactive_metrics().needs_tti() {
3020 self.tti_window.borrow_mut().start_window();
3021 }
3022 }
3023
3024 pub(crate) fn record_tti_if_necessary(&self) {
3028 if self.has_recorded_tti_metric() {
3029 return;
3030 }
3031 if self.tti_window.borrow().needs_check() {
3032 self.get_interactive_metrics()
3033 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
3034 self.tti_window.borrow().get_start(),
3035 ));
3036 }
3037 }
3038
3039 fn fire_focus_event(
3041 &self,
3042 focus_event_type: FocusEventType,
3043 event_target: &EventTarget,
3044 related_target: Option<&EventTarget>,
3045 can_gc: CanGc,
3046 ) {
3047 let (event_name, does_bubble) = match focus_event_type {
3048 FocusEventType::Focus => ("focus".into(), EventBubbles::DoesNotBubble),
3049 FocusEventType::Blur => ("blur".into(), EventBubbles::DoesNotBubble),
3050 };
3051 let event = FocusEvent::new(
3052 &self.window,
3053 event_name,
3054 does_bubble,
3055 EventCancelable::NotCancelable,
3056 Some(&self.window),
3057 0i32,
3058 related_target,
3059 can_gc,
3060 );
3061 let event = event.upcast::<Event>();
3062 event.set_trusted(true);
3063 event.fire(event_target, can_gc);
3064 }
3065
3066 pub(crate) fn is_cookie_averse(&self) -> bool {
3068 !self.has_browsing_context || !url_has_network_scheme(&self.url())
3069 }
3070
3071 pub(crate) fn lookup_custom_element_definition(
3073 &self,
3074 namespace: &Namespace,
3075 local_name: &LocalName,
3076 is: Option<&LocalName>,
3077 ) -> Option<Rc<CustomElementDefinition>> {
3078 if *namespace != ns!(html) {
3080 return None;
3081 }
3082
3083 if !self.has_browsing_context {
3085 return None;
3086 }
3087
3088 let registry = self.window.CustomElements();
3090
3091 registry.lookup_definition(local_name, is)
3092 }
3093
3094 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
3096 self.window.CustomElements()
3097 }
3098
3099 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
3100 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3101 self.throw_on_dynamic_markup_insertion_counter
3102 .set(counter + 1);
3103 }
3104
3105 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
3106 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3107 self.throw_on_dynamic_markup_insertion_counter
3108 .set(counter - 1);
3109 }
3110
3111 pub(crate) fn react_to_environment_changes(&self) {
3112 for image in self.responsive_images.borrow().iter() {
3113 image.react_to_environment_changes();
3114 }
3115 }
3116
3117 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3118 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3119 }
3120
3121 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3122 let index = self
3123 .responsive_images
3124 .borrow()
3125 .iter()
3126 .position(|x| **x == *img);
3127 if let Some(i) = index {
3128 self.responsive_images.borrow_mut().remove(i);
3129 }
3130 }
3131
3132 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3133 let did_have_these_media_controls = self
3134 .media_controls
3135 .borrow_mut()
3136 .insert(id.to_string(), Dom::from_ref(controls))
3137 .is_some();
3138 debug_assert!(
3139 !did_have_these_media_controls,
3140 "Trying to register known media controls"
3141 );
3142 }
3143
3144 pub(crate) fn unregister_media_controls(&self, id: &str) {
3145 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3146 debug_assert!(
3147 did_have_these_media_controls,
3148 "Trying to unregister unknown media controls"
3149 );
3150 }
3151
3152 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3153 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3154 if dirty_canvases
3155 .iter()
3156 .any(|dirty_canvas| dirty_canvas == canvas)
3157 {
3158 return;
3159 }
3160 dirty_canvases.push(canvas.clone());
3161 }
3162
3163 pub(crate) fn needs_rendering_update(&self) -> bool {
3167 if !self.is_fully_active() {
3168 return false;
3169 }
3170 if !self.window().layout_blocked() &&
3171 (!self.restyle_reason().is_empty() ||
3172 self.window().layout().needs_new_display_list())
3173 {
3174 return true;
3175 }
3176 if !self.rendering_update_reasons.get().is_empty() {
3177 return true;
3178 }
3179 if self.event_handler.has_pending_input_events() {
3180 return true;
3181 }
3182 if self.has_pending_scroll_events() {
3183 return true;
3184 }
3185 if self.window().has_unhandled_resize_event() {
3186 return true;
3187 }
3188 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3189 {
3190 return true;
3191 }
3192
3193 false
3194 }
3195
3196 pub(crate) fn update_the_rendering(&self) -> (ReflowPhasesRun, ReflowStatistics) {
3204 assert!(!self.is_render_blocked());
3205
3206 let mut phases = ReflowPhasesRun::empty();
3207 if self.has_pending_animated_image_update.get() {
3208 self.image_animation_manager
3209 .borrow()
3210 .update_active_frames(&self.window, self.current_animation_timeline_value());
3211 self.has_pending_animated_image_update.set(false);
3212 phases.insert(ReflowPhasesRun::UpdatedImageData);
3213 }
3214
3215 self.current_rendering_epoch
3216 .set(self.current_rendering_epoch.get().next());
3217 let current_rendering_epoch = self.current_rendering_epoch.get();
3218
3219 let image_keys: Vec<_> = self
3221 .dirty_canvases
3222 .borrow_mut()
3223 .drain(..)
3224 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3225 .collect();
3226
3227 let pipeline_id = self.window().pipeline_id();
3230 if !image_keys.is_empty() {
3231 phases.insert(ReflowPhasesRun::UpdatedImageData);
3232 self.waiting_on_canvas_image_updates.set(true);
3233 self.window().paint_api().delay_new_frame_for_canvas(
3234 self.webview_id(),
3235 self.window().pipeline_id(),
3236 current_rendering_epoch,
3237 image_keys,
3238 );
3239 }
3240
3241 let (reflow_phases, statistics) = self.window().reflow(ReflowGoal::UpdateTheRendering);
3242 let phases = phases.union(reflow_phases);
3243
3244 self.window().paint_api().update_epoch(
3245 self.webview_id(),
3246 pipeline_id,
3247 current_rendering_epoch,
3248 );
3249
3250 (phases, statistics)
3251 }
3252
3253 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3254 self.waiting_on_canvas_image_updates.set(false);
3255 }
3256
3257 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3258 self.waiting_on_canvas_image_updates.get()
3259 }
3260
3261 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
3271 if !self.is_fully_active() {
3272 return false;
3273 }
3274
3275 let fonts = self.Fonts(can_gc);
3276 if !fonts.waiting_to_fullfill_promise() {
3277 return false;
3278 }
3279 if self.window().font_context().web_fonts_still_loading() != 0 {
3280 return false;
3281 }
3282 if self.ReadyState() != DocumentReadyState::Complete {
3283 return false;
3284 }
3285 if !self.restyle_reason().is_empty() {
3286 return false;
3287 }
3288 if !self.rendering_update_reasons.get().is_empty() {
3289 return false;
3290 }
3291
3292 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
3293
3294 if result {
3298 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3299 }
3300
3301 result
3302 }
3303
3304 pub(crate) fn id_map(
3305 &self,
3306 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3307 self.id_map.borrow()
3308 }
3309
3310 pub(crate) fn name_map(
3311 &self,
3312 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3313 self.name_map.borrow()
3314 }
3315
3316 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3318 self.resize_observers
3319 .borrow_mut()
3320 .push(Dom::from_ref(resize_observer));
3321 }
3322
3323 pub(crate) fn has_resize_observers(&self) -> bool {
3325 !self.resize_observers.borrow().is_empty()
3326 }
3327
3328 pub(crate) fn gather_active_resize_observations_at_depth(
3331 &self,
3332 depth: &ResizeObservationDepth,
3333 ) -> bool {
3334 let mut has_active_resize_observations = false;
3335 for observer in self.resize_observers.borrow_mut().iter_mut() {
3336 observer.gather_active_resize_observations_at_depth(
3337 depth,
3338 &mut has_active_resize_observations,
3339 );
3340 }
3341 has_active_resize_observations
3342 }
3343
3344 #[expect(clippy::redundant_iter_cloned)]
3346 pub(crate) fn broadcast_active_resize_observations(
3347 &self,
3348 can_gc: CanGc,
3349 ) -> ResizeObservationDepth {
3350 let mut shallowest = ResizeObservationDepth::max();
3351 let iterator: Vec<DomRoot<ResizeObserver>> = self
3355 .resize_observers
3356 .borrow()
3357 .iter()
3358 .cloned()
3359 .map(|obs| DomRoot::from_ref(&*obs))
3360 .collect();
3361 for observer in iterator {
3362 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3363 }
3364 shallowest
3365 }
3366
3367 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3369 self.resize_observers
3370 .borrow()
3371 .iter()
3372 .any(|observer| observer.has_skipped_resize_observations())
3373 }
3374
3375 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3377 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3378 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3379 ..Default::default()
3380 };
3381 self.window
3382 .as_global_scope()
3383 .report_an_error(error_info, HandleValue::null(), can_gc);
3384 }
3385
3386 pub(crate) fn status_code(&self) -> Option<u16> {
3387 self.status_code
3388 }
3389
3390 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3392 let encoding = self.encoding.get();
3398
3399 let base_url = self.base_url();
3405
3406 url::Url::options()
3408 .base_url(Some(base_url.as_url()))
3409 .encoding_override(Some(&|input| {
3410 servo_url::encoding::encode_as_url_query_string(input, encoding)
3411 }))
3412 .parse(url)
3413 .map(ServoUrl::from)
3414 }
3415
3416 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3418 if !self.has_browsing_context {
3420 return false;
3421 }
3422
3423 if !self.is_fully_active() {
3425 return false;
3426 }
3427
3428 true
3434 }
3435
3436 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3439 self.intersection_observers
3440 .borrow_mut()
3441 .push(Dom::from_ref(intersection_observer));
3442 }
3443
3444 pub(crate) fn remove_intersection_observer(
3448 &self,
3449 intersection_observer: &IntersectionObserver,
3450 ) {
3451 self.intersection_observers
3452 .borrow_mut()
3453 .retain(|observer| *observer != intersection_observer)
3454 }
3455
3456 pub(crate) fn update_intersection_observer_steps(
3458 &self,
3459 time: CrossProcessInstant,
3460 can_gc: CanGc,
3461 ) {
3462 for intersection_observer in &*self.intersection_observers.borrow() {
3464 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3465 }
3466 }
3467
3468 fn update_single_intersection_observer_steps(
3470 &self,
3471 intersection_observer: &IntersectionObserver,
3472 time: CrossProcessInstant,
3473 can_gc: CanGc,
3474 ) {
3475 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3478
3479 intersection_observer.update_intersection_observations_steps(
3483 self,
3484 time,
3485 root_bounds,
3486 can_gc,
3487 );
3488 }
3489
3490 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3492 self.intersection_observer_task_queued.set(false);
3495
3496 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3501
3502 for intersection_observer in notify_list.iter() {
3505 intersection_observer.invoke_callback_if_necessary(can_gc);
3507 }
3508 }
3509
3510 pub(crate) fn queue_an_intersection_observer_task(&self) {
3512 if self.intersection_observer_task_queued.get() {
3515 return;
3516 }
3517
3518 self.intersection_observer_task_queued.set(true);
3521
3522 let document = Trusted::new(self);
3526 self.owner_global()
3527 .task_manager()
3528 .intersection_observer_task_source()
3529 .queue(task!(notify_intersection_observers: move || {
3530 document.root().notify_intersection_observers(CanGc::note());
3531 }));
3532 }
3533
3534 pub(crate) fn handle_paint_metric(
3535 &self,
3536 metric_type: ProgressiveWebMetricType,
3537 metric_value: CrossProcessInstant,
3538 first_reflow: bool,
3539 can_gc: CanGc,
3540 ) {
3541 let metrics = self.interactive_time.borrow();
3542 match metric_type {
3543 ProgressiveWebMetricType::FirstPaint |
3544 ProgressiveWebMetricType::FirstContentfulPaint => {
3545 let binding = PerformancePaintTiming::new(
3546 self.window.as_global_scope(),
3547 metric_type.clone(),
3548 metric_value,
3549 can_gc,
3550 );
3551 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3552 let entry = binding.upcast::<PerformanceEntry>();
3553 self.window.Performance().queue_entry(entry);
3554 },
3555 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3556 let binding = LargestContentfulPaint::new(
3557 self.window.as_global_scope(),
3558 metric_value,
3559 area,
3560 url,
3561 can_gc,
3562 );
3563 metrics.set_largest_contentful_paint(metric_value, area);
3564 let entry = binding.upcast::<PerformanceEntry>();
3565 self.window.Performance().queue_entry(entry);
3566 },
3567 ProgressiveWebMetricType::TimeToInteractive => {
3568 unreachable!("Unexpected non-paint metric.")
3569 },
3570 }
3571 }
3572
3573 fn write(
3575 &self,
3576 cx: &mut js::context::JSContext,
3577 text: Vec<TrustedHTMLOrString>,
3578 line_feed: bool,
3579 containing_class: &str,
3580 field: &str,
3581 ) -> ErrorResult {
3582 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3584 let mut is_trusted = true;
3586 for value in text {
3588 match value {
3589 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3591 strings.push(trusted_html.to_string());
3592 },
3593 TrustedHTMLOrString::String(str_) => {
3594 is_trusted = false;
3596 strings.push(str_.into());
3598 },
3599 };
3600 }
3601 let mut string = itertools::join(strings, "");
3602 if !is_trusted {
3606 string = TrustedHTML::get_trusted_script_compliant_string(
3607 &self.global(),
3608 TrustedHTMLOrString::String(string.into()),
3609 &format!("{} {}", containing_class, field),
3610 CanGc::from_cx(cx),
3611 )?
3612 .str()
3613 .to_owned();
3614 }
3615 if line_feed {
3617 string.push('\n');
3618 }
3619 if !self.is_html_document() {
3621 return Err(Error::InvalidState(None));
3622 }
3623
3624 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3627 return Err(Error::InvalidState(None));
3628 }
3629
3630 if !self.is_active() || self.active_parser_was_aborted.get() {
3632 return Ok(());
3633 }
3634
3635 let parser = match self.get_current_parser() {
3636 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3637 _ => {
3639 if self.is_prompting_or_unloading() ||
3642 self.ignore_destructive_writes_counter.get() > 0
3643 {
3644 return Ok(());
3645 }
3646 self.Open(cx, None, None)?;
3648 self.get_current_parser().unwrap()
3649 },
3650 };
3651
3652 parser.write(string.into(), cx);
3654
3655 Ok(())
3656 }
3657
3658 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3659 RefMut::map(
3660 self.details_name_groups.borrow_mut(),
3661 |details_name_groups| details_name_groups.get_or_insert_default(),
3662 )
3663 }
3664}
3665
3666#[derive(MallocSizeOf, PartialEq)]
3667pub(crate) enum DocumentSource {
3668 FromParser,
3669 NotFromParser,
3670}
3671
3672pub(crate) trait LayoutDocumentHelpers<'dom> {
3673 fn is_html_document_for_layout(&self) -> bool;
3674 fn quirks_mode(self) -> QuirksMode;
3675 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3676 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3677 fn shadow_roots_styles_changed(self) -> bool;
3678 fn flush_shadow_roots_stylesheets(self);
3679 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>];
3680}
3681
3682#[expect(unsafe_code)]
3683impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3684 #[inline]
3685 fn is_html_document_for_layout(&self) -> bool {
3686 self.unsafe_get().is_html_document
3687 }
3688
3689 #[inline]
3690 fn quirks_mode(self) -> QuirksMode {
3691 self.unsafe_get().quirks_mode.get()
3692 }
3693
3694 #[inline]
3695 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3696 self.unsafe_get().style_shared_lock()
3697 }
3698
3699 #[inline]
3700 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3701 unsafe {
3706 self.unsafe_get()
3707 .shadow_roots
3708 .borrow_for_layout()
3709 .iter()
3710 .map(|sr| sr.to_layout())
3711 .collect()
3712 }
3713 }
3714
3715 #[inline]
3716 fn shadow_roots_styles_changed(self) -> bool {
3717 self.unsafe_get().shadow_roots_styles_changed.get()
3718 }
3719
3720 #[inline]
3721 fn flush_shadow_roots_stylesheets(self) {
3722 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3723 }
3724
3725 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3726 let id_map = unsafe { self.unsafe_get().id_map.borrow_for_layout() };
3727 let matching_elements = id_map.get(id).map(Vec::as_slice).unwrap_or_default();
3728 unsafe { LayoutDom::to_layout_slice(matching_elements) }
3729 }
3730}
3731
3732pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3736 host_suffix_string: &str,
3737 original_host: Host,
3738) -> Option<Host> {
3739 if host_suffix_string.is_empty() {
3741 return None;
3742 }
3743
3744 let host = match Host::parse(host_suffix_string) {
3746 Ok(host) => host,
3747 Err(_) => return None,
3748 };
3749
3750 if host != original_host {
3752 let host = match host {
3754 Host::Domain(ref host) => host,
3755 _ => return None,
3756 };
3757 let original_host = match original_host {
3758 Host::Domain(ref original_host) => original_host,
3759 _ => return None,
3760 };
3761
3762 let index = original_host.len().checked_sub(host.len())?;
3764 let (prefix, suffix) = original_host.split_at(index);
3765
3766 if !prefix.ends_with('.') {
3767 return None;
3768 }
3769 if suffix != host {
3770 return None;
3771 }
3772
3773 if is_pub_domain(host) {
3775 return None;
3776 }
3777 }
3778
3779 Some(host)
3781}
3782
3783fn url_has_network_scheme(url: &ServoUrl) -> bool {
3785 matches!(url.scheme(), "ftp" | "http" | "https")
3786}
3787
3788#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3789pub(crate) enum HasBrowsingContext {
3790 No,
3791 Yes,
3792}
3793
3794impl Document {
3795 #[allow(clippy::too_many_arguments)]
3796 pub(crate) fn new_inherited(
3797 window: &Window,
3798 has_browsing_context: HasBrowsingContext,
3799 url: Option<ServoUrl>,
3800 about_base_url: Option<ServoUrl>,
3801 origin: MutableOrigin,
3802 is_html_document: IsHTMLDocument,
3803 content_type: Option<Mime>,
3804 last_modified: Option<String>,
3805 activity: DocumentActivity,
3806 source: DocumentSource,
3807 doc_loader: DocumentLoader,
3808 referrer: Option<String>,
3809 status_code: Option<u16>,
3810 canceller: FetchCanceller,
3811 is_initial_about_blank: bool,
3812 allow_declarative_shadow_roots: bool,
3813 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3814 has_trustworthy_ancestor_origin: bool,
3815 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3816 creation_sandboxing_flag_set: SandboxingFlagSet,
3817 ) -> Document {
3818 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3819
3820 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3821 (DocumentReadyState::Loading, false)
3822 } else {
3823 (DocumentReadyState::Complete, true)
3824 };
3825
3826 let frame_type = match window.is_top_level() {
3827 true => TimerMetadataFrameType::RootWindow,
3828 false => TimerMetadataFrameType::IFrame,
3829 };
3830 let interactive_time = ProgressiveWebMetrics::new(
3831 window.time_profiler_chan().clone(),
3832 url.clone(),
3833 frame_type,
3834 );
3835
3836 let content_type = content_type.unwrap_or_else(|| {
3837 match is_html_document {
3838 IsHTMLDocument::HTMLDocument => "text/html",
3840 IsHTMLDocument::NonHTMLDocument => "application/xml",
3842 }
3843 .parse()
3844 .unwrap()
3845 });
3846
3847 let encoding = content_type
3848 .get_parameter(CHARSET)
3849 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3850 .unwrap_or(UTF_8);
3851
3852 let has_focus = window.parent_info().is_none();
3853
3854 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3855
3856 Document {
3857 node: Node::new_document_node(),
3858 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3859 window: Dom::from_ref(window),
3860 has_browsing_context,
3861 implementation: Default::default(),
3862 content_type,
3863 last_modified,
3864 url: DomRefCell::new(url),
3865 about_base_url: DomRefCell::new(about_base_url),
3866 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3868 event_handler: DocumentEventHandler::new(window),
3869 embedder_controls: DocumentEmbedderControls::new(window),
3870 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3871 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3872 encoding: Cell::new(encoding),
3874 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3875 activity: Cell::new(activity),
3876 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3877 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3878 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3879 images: Default::default(),
3880 embeds: Default::default(),
3881 links: Default::default(),
3882 forms: Default::default(),
3883 scripts: Default::default(),
3884 anchors: Default::default(),
3885 applets: Default::default(),
3886 iframes: RefCell::new(IFrameCollection::new()),
3887 style_shared_lock: {
3888 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3895 LazyLock::new(StyleSharedRwLock::new);
3896
3897 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3898 },
3900 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3901 stylesheet_list: MutNullableDom::new(None),
3902 ready_state: Cell::new(ready_state),
3903 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3904 focus_transaction: DomRefCell::new(None),
3905 focused: Default::default(),
3906 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3907 has_focus: Cell::new(has_focus),
3908 current_script: Default::default(),
3909 pending_parsing_blocking_script: Default::default(),
3910 script_blocking_stylesheets_count: Default::default(),
3911 render_blocking_element_count: Default::default(),
3912 deferred_scripts: Default::default(),
3913 asap_in_order_scripts_list: Default::default(),
3914 asap_scripts_set: Default::default(),
3915 animation_frame_ident: Cell::new(0),
3916 animation_frame_list: DomRefCell::new(VecDeque::new()),
3917 running_animation_callbacks: Cell::new(false),
3918 loader: DomRefCell::new(doc_loader),
3919 current_parser: Default::default(),
3920 base_element: Default::default(),
3921 target_base_element: Default::default(),
3922 appropriate_template_contents_owner_document: Default::default(),
3923 pending_restyles: DomRefCell::new(FxHashMap::default()),
3924 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3925 dom_interactive: Cell::new(Default::default()),
3926 dom_content_loaded_event_start: Cell::new(Default::default()),
3927 dom_content_loaded_event_end: Cell::new(Default::default()),
3928 dom_complete: Cell::new(Default::default()),
3929 top_level_dom_complete: Cell::new(Default::default()),
3930 load_event_start: Cell::new(Default::default()),
3931 load_event_end: Cell::new(Default::default()),
3932 unload_event_start: Cell::new(Default::default()),
3933 unload_event_end: Cell::new(Default::default()),
3934 https_state: Cell::new(HttpsState::None),
3935 origin,
3936 referrer,
3937 target_element: MutNullableDom::new(None),
3938 policy_container: DomRefCell::new(PolicyContainer::default()),
3939 preloaded_resources: Default::default(),
3940 ignore_destructive_writes_counter: Default::default(),
3941 ignore_opens_during_unload_counter: Default::default(),
3942 spurious_animation_frames: Cell::new(0),
3943 dom_count: Cell::new(1),
3944 fullscreen_element: MutNullableDom::new(None),
3945 form_id_listener_map: Default::default(),
3946 interactive_time: DomRefCell::new(interactive_time),
3947 tti_window: DomRefCell::new(InteractiveWindow::default()),
3948 canceller,
3949 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3950 page_showing: Cell::new(false),
3951 salvageable: Cell::new(true),
3952 active_parser_was_aborted: Cell::new(false),
3953 fired_unload: Cell::new(false),
3954 responsive_images: Default::default(),
3955 redirect_count: Cell::new(0),
3956 completely_loaded: Cell::new(false),
3957 script_and_layout_blockers: Cell::new(0),
3958 delayed_tasks: Default::default(),
3959 shadow_roots: DomRefCell::new(HashSet::new()),
3960 shadow_roots_styles_changed: Cell::new(false),
3961 media_controls: DomRefCell::new(HashMap::new()),
3962 dirty_canvases: DomRefCell::new(Default::default()),
3963 has_pending_animated_image_update: Cell::new(false),
3964 selection: MutNullableDom::new(None),
3965 animation_timeline: if pref!(layout_animations_test_enabled) {
3966 DomRefCell::new(AnimationTimeline::new_for_testing())
3967 } else {
3968 DomRefCell::new(AnimationTimeline::new())
3969 },
3970 animations: Animations::new(),
3971 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3972 dirty_root: Default::default(),
3973 declarative_refresh: Default::default(),
3974 resize_observers: Default::default(),
3975 fonts: Default::default(),
3976 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3977 status_code,
3978 is_initial_about_blank: Cell::new(is_initial_about_blank),
3979 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3980 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3981 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3982 intersection_observer_task_queued: Cell::new(false),
3983 intersection_observers: Default::default(),
3984 highlighted_dom_node: Default::default(),
3985 adopted_stylesheets: Default::default(),
3986 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3987 pending_scroll_event_targets: Default::default(),
3988 rendering_update_reasons: Default::default(),
3989 waiting_on_canvas_image_updates: Cell::new(false),
3990 current_rendering_epoch: Default::default(),
3991 custom_element_reaction_stack,
3992 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3993 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3994 favicon: RefCell::new(None),
3995 websockets: DOMTracker::new(),
3996 details_name_groups: Default::default(),
3997 protocol_handler_automation_mode: Default::default(),
3998 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3999 state_override: Default::default(),
4000 value_override: Default::default(),
4001 default_single_line_container_name: Default::default(),
4002 css_styling_flag: Default::default(),
4003 }
4004 }
4005
4006 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
4008 if let Some(csp_list) = self.get_csp_list().as_ref() {
4009 for policy in &csp_list.0 {
4010 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
4011 policy.disposition == PolicyDisposition::Enforce
4012 {
4013 return InsecureRequestsPolicy::Upgrade;
4014 }
4015 }
4016 }
4017
4018 self.inherited_insecure_requests_policy
4019 .get()
4020 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
4021 }
4022
4023 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
4025 &self.event_handler
4026 }
4027
4028 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
4030 &self.embedder_controls
4031 }
4032
4033 fn has_pending_scroll_events(&self) -> bool {
4036 !self.pending_scroll_event_targets.borrow().is_empty()
4037 }
4038
4039 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
4042 self.rendering_update_reasons
4043 .set(self.rendering_update_reasons.get().union(reason));
4044 }
4045
4046 pub(crate) fn clear_rendering_update_reasons(&self) {
4048 self.rendering_update_reasons
4049 .set(RenderingUpdateReason::empty())
4050 }
4051
4052 pub(crate) fn add_script_and_layout_blocker(&self) {
4059 self.script_and_layout_blockers
4060 .set(self.script_and_layout_blockers.get() + 1);
4061 }
4062
4063 #[expect(unsafe_code)]
4064 pub(crate) fn remove_script_and_layout_blocker(&self) {
4068 assert!(self.script_and_layout_blockers.get() > 0);
4069 self.script_and_layout_blockers
4070 .set(self.script_and_layout_blockers.get() - 1);
4071 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
4072 {
4073 let task = self.delayed_tasks.borrow_mut().remove(0);
4074 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
4075 task.run_box(&mut cx);
4076 }
4077 }
4078
4079 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
4081 self.delayed_tasks.borrow_mut().push(Box::new(task));
4082 }
4083
4084 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
4087 assert_eq!(
4088 self.script_and_layout_blockers.get(),
4089 0,
4090 "Attempt to use script or layout while DOM not in a stable state"
4091 );
4092 }
4093
4094 #[allow(clippy::too_many_arguments)]
4095 pub(crate) fn new(
4096 window: &Window,
4097 has_browsing_context: HasBrowsingContext,
4098 url: Option<ServoUrl>,
4099 about_base_url: Option<ServoUrl>,
4100 origin: MutableOrigin,
4101 doctype: IsHTMLDocument,
4102 content_type: Option<Mime>,
4103 last_modified: Option<String>,
4104 activity: DocumentActivity,
4105 source: DocumentSource,
4106 doc_loader: DocumentLoader,
4107 referrer: Option<String>,
4108 status_code: Option<u16>,
4109 canceller: FetchCanceller,
4110 is_initial_about_blank: bool,
4111 allow_declarative_shadow_roots: bool,
4112 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4113 has_trustworthy_ancestor_origin: bool,
4114 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4115 creation_sandboxing_flag_set: SandboxingFlagSet,
4116 can_gc: CanGc,
4117 ) -> DomRoot<Document> {
4118 Self::new_with_proto(
4119 window,
4120 None,
4121 has_browsing_context,
4122 url,
4123 about_base_url,
4124 origin,
4125 doctype,
4126 content_type,
4127 last_modified,
4128 activity,
4129 source,
4130 doc_loader,
4131 referrer,
4132 status_code,
4133 canceller,
4134 is_initial_about_blank,
4135 allow_declarative_shadow_roots,
4136 inherited_insecure_requests_policy,
4137 has_trustworthy_ancestor_origin,
4138 custom_element_reaction_stack,
4139 creation_sandboxing_flag_set,
4140 can_gc,
4141 )
4142 }
4143
4144 #[allow(clippy::too_many_arguments)]
4145 fn new_with_proto(
4146 window: &Window,
4147 proto: Option<HandleObject>,
4148 has_browsing_context: HasBrowsingContext,
4149 url: Option<ServoUrl>,
4150 about_base_url: Option<ServoUrl>,
4151 origin: MutableOrigin,
4152 doctype: IsHTMLDocument,
4153 content_type: Option<Mime>,
4154 last_modified: Option<String>,
4155 activity: DocumentActivity,
4156 source: DocumentSource,
4157 doc_loader: DocumentLoader,
4158 referrer: Option<String>,
4159 status_code: Option<u16>,
4160 canceller: FetchCanceller,
4161 is_initial_about_blank: bool,
4162 allow_declarative_shadow_roots: bool,
4163 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4164 has_trustworthy_ancestor_origin: bool,
4165 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4166 creation_sandboxing_flag_set: SandboxingFlagSet,
4167 can_gc: CanGc,
4168 ) -> DomRoot<Document> {
4169 let document = reflect_dom_object_with_proto(
4170 Box::new(Document::new_inherited(
4171 window,
4172 has_browsing_context,
4173 url,
4174 about_base_url,
4175 origin,
4176 doctype,
4177 content_type,
4178 last_modified,
4179 activity,
4180 source,
4181 doc_loader,
4182 referrer,
4183 status_code,
4184 canceller,
4185 is_initial_about_blank,
4186 allow_declarative_shadow_roots,
4187 inherited_insecure_requests_policy,
4188 has_trustworthy_ancestor_origin,
4189 custom_element_reaction_stack,
4190 creation_sandboxing_flag_set,
4191 )),
4192 window,
4193 proto,
4194 can_gc,
4195 );
4196 {
4197 let node = document.upcast::<Node>();
4198 node.set_owner_doc(&document);
4199 }
4200 document
4201 }
4202
4203 pub(crate) fn get_redirect_count(&self) -> u16 {
4204 self.redirect_count.get()
4205 }
4206
4207 pub(crate) fn set_redirect_count(&self, count: u16) {
4208 self.redirect_count.set(count)
4209 }
4210
4211 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4212 if name.is_empty() {
4213 return 0;
4214 }
4215 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4216 }
4217
4218 pub(crate) fn nth_element_by_name(
4219 &self,
4220 index: u32,
4221 name: &DOMString,
4222 ) -> Option<DomRoot<Node>> {
4223 if name.is_empty() {
4224 return None;
4225 }
4226 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4227 }
4228
4229 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4232 let element = match node.downcast::<Element>() {
4233 Some(element) => element,
4234 None => return false,
4235 };
4236 if element.namespace() != &ns!(html) {
4237 return false;
4238 }
4239 element.get_name().is_some_and(|n| &*n == name)
4240 }
4241
4242 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4243 let doc = self.GetDocumentElement();
4244 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4245 maybe_node
4246 .iter()
4247 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4248 .filter(|node| callback(node))
4249 .count() as u32
4250 }
4251
4252 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4253 &self,
4254 index: u32,
4255 callback: F,
4256 ) -> Option<DomRoot<Node>> {
4257 let doc = self.GetDocumentElement();
4258 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4259 maybe_node
4260 .iter()
4261 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4262 .filter(|node| callback(node))
4263 .nth(index as usize)
4264 .map(|n| DomRoot::from_ref(&*n))
4265 }
4266
4267 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4268 self.GetDocumentElement().and_then(DomRoot::downcast)
4269 }
4270
4271 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
4273 &self.style_shared_lock
4274 }
4275
4276 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4278 let mut stylesheets = self.stylesheets.borrow_mut();
4285 let have_changed = stylesheets.has_changed();
4286 stylesheets.flush_without_invalidation();
4287 have_changed
4288 }
4289
4290 pub(crate) fn salvageable(&self) -> bool {
4291 self.salvageable.get()
4292 }
4293
4294 pub(crate) fn appropriate_template_contents_owner_document(
4296 &self,
4297 can_gc: CanGc,
4298 ) -> DomRoot<Document> {
4299 self.appropriate_template_contents_owner_document
4300 .or_init(|| {
4301 let doctype = if self.is_html_document {
4302 IsHTMLDocument::HTMLDocument
4303 } else {
4304 IsHTMLDocument::NonHTMLDocument
4305 };
4306 let new_doc = Document::new(
4307 self.window(),
4308 HasBrowsingContext::No,
4309 None,
4310 None,
4311 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4313 doctype,
4314 None,
4315 None,
4316 DocumentActivity::Inactive,
4317 DocumentSource::NotFromParser,
4318 DocumentLoader::new(&self.loader()),
4319 None,
4320 None,
4321 Default::default(),
4322 false,
4323 self.allow_declarative_shadow_roots(),
4324 Some(self.insecure_requests_policy()),
4325 self.has_trustworthy_ancestor_or_current_origin(),
4326 self.custom_element_reaction_stack.clone(),
4327 self.creation_sandboxing_flag_set(),
4328 can_gc,
4329 );
4330 new_doc
4331 .appropriate_template_contents_owner_document
4332 .set(Some(&new_doc));
4333 new_doc
4334 })
4335 }
4336
4337 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4338 self.id_map
4339 .borrow()
4340 .get(id)
4341 .map(|elements| DomRoot::from_ref(&*elements[0]))
4342 }
4343
4344 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4345 let map = self.pending_restyles.borrow_mut();
4346 RefMut::map(map, |m| {
4347 &mut m
4348 .entry(Dom::from_ref(el))
4349 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4350 .0
4351 })
4352 }
4353
4354 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4355 let mut entry = self.ensure_pending_restyle(el);
4361 if entry.snapshot.is_none() {
4362 entry.snapshot = Some(Snapshot::new());
4363 }
4364 if attr.local_name() == &local_name!("style") {
4365 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4366 }
4367
4368 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4369 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4370 }
4371
4372 let snapshot = entry.snapshot.as_mut().unwrap();
4373 if attr.local_name() == &local_name!("id") {
4374 if snapshot.id_changed {
4375 return;
4376 }
4377 snapshot.id_changed = true;
4378 } else if attr.local_name() == &local_name!("class") {
4379 if snapshot.class_changed {
4380 return;
4381 }
4382 snapshot.class_changed = true;
4383 } else {
4384 snapshot.other_attributes_changed = true;
4385 }
4386 let local_name = style::LocalName::cast(attr.local_name());
4387 if !snapshot.changed_attrs.contains(local_name) {
4388 snapshot.changed_attrs.push(local_name.clone());
4389 }
4390 if snapshot.attrs.is_none() {
4391 let attrs = el
4392 .attrs()
4393 .iter()
4394 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4395 .collect();
4396 snapshot.attrs = Some(attrs);
4397 }
4398 }
4399
4400 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4401 self.policy_container
4402 .borrow_mut()
4403 .set_referrer_policy(policy);
4404 }
4405
4406 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4407 self.policy_container.borrow().get_referrer_policy()
4408 }
4409
4410 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4411 if let Some(ref element) = self.target_element.get() {
4412 element.set_target_state(false);
4413 }
4414
4415 self.target_element.set(node);
4416
4417 if let Some(ref element) = self.target_element.get() {
4418 element.set_target_state(true);
4419 }
4420 }
4421
4422 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4423 self.ignore_destructive_writes_counter
4424 .set(self.ignore_destructive_writes_counter.get() + 1);
4425 }
4426
4427 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4428 self.ignore_destructive_writes_counter
4429 .set(self.ignore_destructive_writes_counter.get() - 1);
4430 }
4431
4432 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4433 self.ignore_opens_during_unload_counter.get() > 0
4434 }
4435
4436 fn incr_ignore_opens_during_unload_counter(&self) {
4437 self.ignore_opens_during_unload_counter
4438 .set(self.ignore_opens_during_unload_counter.get() + 1);
4439 }
4440
4441 fn decr_ignore_opens_during_unload_counter(&self) {
4442 self.ignore_opens_during_unload_counter
4443 .set(self.ignore_opens_during_unload_counter.get() - 1);
4444 }
4445
4446 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4448 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4455 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4456
4457 if !self.is_fully_active() {
4460 promise.reject_error(
4461 Error::Type(c"Document is not fully active".to_owned()),
4462 can_gc,
4463 );
4464 return promise;
4465 }
4466
4467 let mut error = false;
4470
4471 {
4474 match *pending.namespace() {
4476 ns!(mathml) => {
4477 if pending.local_name().as_ref() != "math" {
4478 error = true;
4479 }
4480 },
4481 ns!(svg) => {
4482 if pending.local_name().as_ref() != "svg" {
4483 error = true;
4484 }
4485 },
4486 ns!(html) => (),
4487 _ => error = true,
4488 }
4489
4490 if pending.is::<HTMLDialogElement>() {
4492 error = true;
4493 }
4494
4495 if !pending.fullscreen_element_ready_check() {
4497 error = true;
4498 }
4499
4500 if !pending.owner_window().has_transient_activation() {
4508 error = true;
4509 }
4510 }
4511
4512 if pref!(dom_fullscreen_test) {
4513 info!("Tests don't really enter fullscreen.");
4516 } else {
4517 warn!("Fullscreen not supported yet");
4520 }
4521
4522 if !error {
4525 pending.owner_window().consume_user_activation();
4526 }
4527
4528 if !error {
4534 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4535 self.send_to_embedder(event);
4536 }
4537
4538 let pipeline_id = self.window().pipeline_id();
4541
4542 let trusted_pending = Trusted::new(pending);
4543 let trusted_pending_doc = Trusted::new(self);
4544 let trusted_promise = TrustedPromise::new(promise.clone());
4545 let handler = ElementPerformFullscreenEnter::new(
4546 trusted_pending,
4547 trusted_pending_doc,
4548 trusted_promise,
4549 error,
4550 );
4551 let script_msg = CommonScriptMsg::Task(
4552 ScriptThreadEventCategory::EnterFullscreen,
4553 handler,
4554 Some(pipeline_id),
4555 TaskSourceName::DOMManipulation,
4556 );
4557 let msg = MainThreadScriptMsg::Common(script_msg);
4558 self.window().main_thread_script_chan().send(msg).unwrap();
4559
4560 promise
4561 }
4562
4563 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4565 let global = self.global();
4566
4567 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4570 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4571
4572 if !self.is_fully_active() || self.fullscreen_element.get().is_none() {
4575 promise.reject_error(
4576 Error::Type(
4577 c"No fullscreen element to exit or document is not fully active".to_owned(),
4578 ),
4579 can_gc,
4580 );
4581 return promise;
4582 }
4583
4584 let element = self.fullscreen_element.get().unwrap();
4587 let window = self.window();
4588
4589 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4593 self.send_to_embedder(event);
4594
4595 let trusted_element = Trusted::new(&*element);
4598 let trusted_promise = TrustedPromise::new(promise.clone());
4599 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4600 let pipeline_id = Some(global.pipeline_id());
4601 let script_msg = CommonScriptMsg::Task(
4602 ScriptThreadEventCategory::ExitFullscreen,
4603 handler,
4604 pipeline_id,
4605 TaskSourceName::DOMManipulation,
4606 );
4607 let msg = MainThreadScriptMsg::Common(script_msg);
4608 window.main_thread_script_chan().send(msg).unwrap();
4609
4610 promise
4611 }
4612
4613 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4614 self.fullscreen_element.set(element);
4615 }
4616
4617 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4618 match self.browsing_context() {
4620 None => false,
4622 Some(_) => {
4623 let window = self.window();
4625 if window.is_top_level() {
4626 true
4627 } else {
4628 window
4630 .GetFrameElement()
4631 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4632 }
4633 },
4634 }
4635 }
4636
4637 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4638 let map = self.form_id_listener_map.borrow();
4639 if let Some(listeners) = map.get(id) {
4640 for listener in listeners {
4641 listener
4642 .as_maybe_form_control()
4643 .expect("Element must be a form control")
4644 .reset_form_owner(can_gc);
4645 }
4646 }
4647 }
4648
4649 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4650 self.shadow_roots
4651 .borrow_mut()
4652 .insert(Dom::from_ref(shadow_root));
4653 self.invalidate_shadow_roots_stylesheets();
4654 }
4655
4656 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4657 let mut shadow_roots = self.shadow_roots.borrow_mut();
4658 shadow_roots.remove(&Dom::from_ref(shadow_root));
4659 }
4660
4661 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4662 self.shadow_roots_styles_changed.set(true);
4663 }
4664
4665 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4666 self.shadow_roots_styles_changed.get()
4667 }
4668
4669 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4670 if !self.shadow_roots_styles_changed.get() {
4671 return;
4672 }
4673 self.shadow_roots_styles_changed.set(false);
4674 }
4675
4676 pub(crate) fn stylesheet_count(&self) -> usize {
4677 self.stylesheets.borrow().len()
4678 }
4679
4680 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4681 let stylesheets = self.stylesheets.borrow();
4682
4683 stylesheets
4684 .get(Origin::Author, index)
4685 .and_then(|s| s.owner.get_cssom_object())
4686 }
4687
4688 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4695 let stylesheets = &mut *self.stylesheets.borrow_mut();
4696
4697 let insertion_point = stylesheets
4699 .iter()
4700 .map(|(sheet, _origin)| sheet)
4701 .find(|sheet_in_doc| {
4702 match &sheet_in_doc.owner {
4703 StylesheetSource::Element(other_node) => {
4704 owner_node.upcast::<Node>().is_before(other_node.upcast())
4705 },
4706 StylesheetSource::Constructed(_) => true,
4709 }
4710 })
4711 .cloned();
4712
4713 if self.has_browsing_context() {
4714 let document_context = self.window.web_font_context();
4715
4716 self.window.layout_mut().add_stylesheet(
4717 sheet.clone(),
4718 insertion_point.as_ref().map(|s| s.sheet.clone()),
4719 &document_context,
4720 );
4721 }
4722
4723 DocumentOrShadowRoot::add_stylesheet(
4724 StylesheetSource::Element(Dom::from_ref(owner_node)),
4725 StylesheetSetRef::Document(stylesheets),
4726 sheet,
4727 insertion_point,
4728 self.style_shared_lock(),
4729 );
4730 }
4731
4732 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4737 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4738 debug_assert!(cssom_stylesheet.is_constructed());
4739
4740 let stylesheets = &mut *self.stylesheets.borrow_mut();
4741 let sheet = cssom_stylesheet.style_stylesheet().clone();
4742
4743 let insertion_point = stylesheets
4744 .iter()
4745 .last()
4746 .map(|(sheet, _origin)| sheet)
4747 .cloned();
4748
4749 if self.has_browsing_context() {
4750 self.window.layout_mut().add_stylesheet(
4751 sheet.clone(),
4752 insertion_point.as_ref().map(|s| s.sheet.clone()),
4753 &self.window.web_font_context(),
4754 );
4755 }
4756
4757 DocumentOrShadowRoot::add_stylesheet(
4758 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4759 StylesheetSetRef::Document(stylesheets),
4760 sheet,
4761 insertion_point,
4762 self.style_shared_lock(),
4763 );
4764 }
4765
4766 pub(crate) fn load_web_fonts_from_stylesheet(
4768 &self,
4769 stylesheet: &Arc<Stylesheet>,
4770 document_context: &WebFontDocumentContext,
4771 ) {
4772 self.window
4773 .layout()
4774 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4775 }
4776
4777 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4780 if self.has_browsing_context() {
4781 self.window
4782 .layout_mut()
4783 .remove_stylesheet(stylesheet.clone());
4784 }
4785
4786 DocumentOrShadowRoot::remove_stylesheet(
4787 owner,
4788 stylesheet,
4789 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4790 )
4791 }
4792
4793 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4794 Ref::map(self.id_map.borrow(), |map| {
4795 map.get(id).map(|vec| &**vec).unwrap_or_default()
4796 })
4797 }
4798
4799 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4800 Ref::map(self.name_map.borrow(), |map| {
4801 map.get(name).map(|vec| &**vec).unwrap_or_default()
4802 })
4803 }
4804
4805 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4806 self.pending_restyles
4807 .borrow_mut()
4808 .drain()
4809 .filter_map(|(elem, restyle)| {
4810 let node = elem.upcast::<Node>();
4811 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4812 return None;
4813 }
4814 node.note_dirty_descendants();
4815 Some((node.to_trusted_node_address(), restyle.0))
4816 })
4817 .collect()
4818 }
4819
4820 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4821 self.animation_timeline.borrow_mut().advance_specific(delta);
4822 let current_timeline_value = self.current_animation_timeline_value();
4823 self.animations
4824 .update_for_new_timeline_value(&self.window, current_timeline_value);
4825 }
4826
4827 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4828 let current_timeline_value = self.current_animation_timeline_value();
4829 self.animations
4830 .mark_animating_nodes_as_dirty(current_timeline_value);
4831 }
4832
4833 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4834 self.animation_timeline.borrow().current_value()
4835 }
4836
4837 pub(crate) fn animations(&self) -> &Animations {
4838 &self.animations
4839 }
4840
4841 pub(crate) fn update_animations_post_reflow(&self) {
4842 self.animations
4843 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4844 self.image_animation_manager
4845 .borrow()
4846 .maybe_schedule_update_after_layout(
4847 &self.window,
4848 self.current_animation_timeline_value(),
4849 );
4850 }
4851
4852 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4853 self.animations.cancel_animations_for_node(node);
4854 self.image_animation_manager
4855 .borrow()
4856 .cancel_animations_for_node(node);
4857 }
4858
4859 pub(crate) fn update_animations_and_send_events(&self, cx: &mut js::context::JSContext) {
4861 if !self.layout_animations_test_enabled {
4863 self.animation_timeline.borrow_mut().update();
4864 }
4865
4866 let current_timeline_value = self.current_animation_timeline_value();
4873 self.animations
4874 .update_for_new_timeline_value(&self.window, current_timeline_value);
4875 self.maybe_mark_animating_nodes_as_dirty();
4876
4877 self.window().perform_a_microtask_checkpoint(cx);
4879
4880 let _realm = enter_realm(self);
4882 self.animations()
4883 .send_pending_events(self.window(), CanGc::from_cx(cx));
4884 }
4885
4886 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4887 self.image_animation_manager.borrow()
4888 }
4889
4890 pub(crate) fn set_has_pending_animated_image_update(&self) {
4891 self.has_pending_animated_image_update.set(true);
4892 }
4893
4894 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4896 if self.will_declaratively_refresh() {
4898 return;
4899 }
4900
4901 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4903 Regex::new(
4907 r#"(?xs)
4908 ^
4909 \s* # 3
4910 ((?<time>[0-9]+)|\.) # 5-6
4911 [0-9.]* # 8
4912 (
4913 (
4914 (\s*;|\s*,|\s) # 10.3
4915 \s* # 10.4
4916 )
4917 (
4918 (
4919 (U|u)(R|r)(L|l) # 11.2-11.4
4920 \s*=\s* # 11.5-11.7
4921 )?
4922 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4923 |
4924 (?<url4>(?s-u:.)*)
4925 )
4926 )?
4927 $
4928 "#,
4929 )
4930 .unwrap()
4931 });
4932
4933 let mut url_record = self.url();
4935 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4936 captures
4937 } else {
4938 return;
4939 };
4940 let time = if let Some(time_string) = captures.name("time") {
4941 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4942 } else {
4943 0
4944 };
4945 let captured_url = captures.name("url1").or(captures
4946 .name("url2")
4947 .or(captures.name("url3").or(captures.name("url4"))));
4948
4949 if let Some(url_match) = captured_url {
4951 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4952 Some(&url_record),
4953 &String::from_utf8_lossy(url_match.as_bytes()),
4954 ) {
4955 info!("Refresh to {}", url.debug_compact());
4956 url
4957 } else {
4958 return;
4960 }
4961 }
4962 if self.completely_loaded() {
4964 self.window.as_global_scope().schedule_callback(
4966 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4967 window: DomRoot::from_ref(self.window()),
4968 url: url_record,
4969 }),
4970 Duration::from_secs(time),
4971 );
4972 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4973 } else {
4974 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4975 url: url_record,
4976 time,
4977 });
4978 }
4979 }
4980
4981 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4982 self.declarative_refresh.borrow().is_some()
4983 }
4984 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4985 *self.declarative_refresh.borrow_mut() = Some(refresh);
4986 }
4987
4988 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4990 if self.visibility_state.get() == visibility_state {
4992 return;
4993 }
4994 self.visibility_state.set(visibility_state);
4996 let entry = VisibilityStateEntry::new(
4999 &self.global(),
5000 visibility_state,
5001 CrossProcessInstant::now(),
5002 can_gc,
5003 );
5004 self.window
5005 .Performance()
5006 .queue_entry(entry.upcast::<PerformanceEntry>());
5007
5008 #[cfg(feature = "gamepad")]
5019 if visibility_state == DocumentVisibilityState::Hidden {
5020 self.window
5021 .Navigator()
5022 .GetGamepads()
5023 .iter_mut()
5024 .for_each(|gamepad| {
5025 if let Some(g) = gamepad {
5026 g.vibration_actuator().handle_visibility_change();
5027 }
5028 });
5029 }
5030
5031 self.upcast::<EventTarget>()
5033 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
5034 }
5035
5036 pub(crate) fn is_initial_about_blank(&self) -> bool {
5038 self.is_initial_about_blank.get()
5039 }
5040
5041 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
5043 self.allow_declarative_shadow_roots.get()
5044 }
5045
5046 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
5047 self.has_trustworthy_ancestor_origin.get()
5048 }
5049
5050 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
5051 self.has_trustworthy_ancestor_origin.get() ||
5052 self.origin().immutable().is_potentially_trustworthy()
5053 }
5054
5055 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
5056 self.highlighted_dom_node.set(node);
5057 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
5058 }
5059
5060 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
5061 self.highlighted_dom_node.get()
5062 }
5063
5064 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
5065 self.custom_element_reaction_stack.clone()
5066 }
5067
5068 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
5069 self.active_sandboxing_flag_set.get().contains(flag)
5070 }
5071
5072 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
5073 self.active_sandboxing_flag_set.set(flags)
5074 }
5075
5076 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
5077 self.creation_sandboxing_flag_set.get()
5078 }
5079
5080 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
5081 &self,
5082 ) -> SandboxingFlagSet {
5083 self.window()
5084 .window_proxy()
5085 .frame_element()
5086 .and_then(|element| element.downcast::<HTMLIFrameElement>())
5087 .map(HTMLIFrameElement::sandboxing_flag_set)
5088 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
5089 }
5090
5091 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
5092 self.window()
5093 .scrolling_box_query(None, flags)
5094 .expect("We should always have a ScrollingBox for the Viewport")
5095 }
5096
5097 pub(crate) fn notify_embedder_favicon(&self) {
5098 if let Some(ref image) = *self.favicon.borrow() {
5099 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
5100 }
5101 }
5102
5103 pub(crate) fn set_favicon(&self, favicon: Image) {
5104 *self.favicon.borrow_mut() = Some(favicon);
5105 self.notify_embedder_favicon();
5106 }
5107
5108 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
5109 self.fullscreen_element.get()
5110 }
5111
5112 pub(crate) fn state_override(&self) -> bool {
5114 self.state_override.get()
5115 }
5116
5117 pub(crate) fn value_override(&self) -> Option<DOMString> {
5119 self.value_override.borrow().clone()
5120 }
5121
5122 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
5124 self.default_single_line_container_name.get()
5125 }
5126
5127 pub(crate) fn set_default_single_line_container_name(
5129 &self,
5130 value: DefaultSingleLineContainerName,
5131 ) {
5132 self.default_single_line_container_name.set(value)
5133 }
5134
5135 pub(crate) fn css_styling_flag(&self) -> bool {
5137 self.css_styling_flag.get()
5138 }
5139
5140 pub(crate) fn set_css_styling_flag(&self, value: bool) {
5142 self.css_styling_flag.set(value)
5143 }
5144}
5145
5146impl DocumentMethods<crate::DomTypeHolder> for Document {
5147 fn Constructor(
5149 window: &Window,
5150 proto: Option<HandleObject>,
5151 can_gc: CanGc,
5152 ) -> Fallible<DomRoot<Document>> {
5153 let doc = window.Document();
5155 let docloader = DocumentLoader::new(&doc.loader());
5156 Ok(Document::new_with_proto(
5157 window,
5158 proto,
5159 HasBrowsingContext::No,
5160 None,
5161 None,
5162 doc.origin().clone(),
5163 IsHTMLDocument::NonHTMLDocument,
5164 None,
5165 None,
5166 DocumentActivity::Inactive,
5167 DocumentSource::NotFromParser,
5168 docloader,
5169 None,
5170 None,
5171 Default::default(),
5172 false,
5173 doc.allow_declarative_shadow_roots(),
5174 Some(doc.insecure_requests_policy()),
5175 doc.has_trustworthy_ancestor_or_current_origin(),
5176 doc.custom_element_reaction_stack(),
5177 doc.active_sandboxing_flag_set.get(),
5178 can_gc,
5179 ))
5180 }
5181
5182 fn ParseHTMLUnsafe(
5184 cx: &mut js::context::JSContext,
5185 window: &Window,
5186 s: TrustedHTMLOrString,
5187 ) -> Fallible<DomRoot<Self>> {
5188 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
5192 window.as_global_scope(),
5193 s,
5194 "Document parseHTMLUnsafe",
5195 CanGc::from_cx(cx),
5196 )?;
5197
5198 let url = window.get_url();
5199 let doc = window.Document();
5200 let loader = DocumentLoader::new(&doc.loader());
5201
5202 let content_type = "text/html"
5203 .parse()
5204 .expect("Supported type is not a MIME type");
5205 let document = Document::new(
5208 window,
5209 HasBrowsingContext::No,
5210 Some(ServoUrl::parse("about:blank").unwrap()),
5211 None,
5212 doc.origin().clone(),
5213 IsHTMLDocument::HTMLDocument,
5214 Some(content_type),
5215 None,
5216 DocumentActivity::Inactive,
5217 DocumentSource::FromParser,
5218 loader,
5219 None,
5220 None,
5221 Default::default(),
5222 false,
5223 true,
5224 Some(doc.insecure_requests_policy()),
5225 doc.has_trustworthy_ancestor_or_current_origin(),
5226 doc.custom_element_reaction_stack(),
5227 doc.creation_sandboxing_flag_set(),
5228 CanGc::from_cx(cx),
5229 );
5230 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, cx);
5232 document.set_ready_state(DocumentReadyState::Complete, CanGc::from_cx(cx));
5234 Ok(document)
5235 }
5236
5237 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
5239 self.stylesheet_list.or_init(|| {
5240 StyleSheetList::new(
5241 &self.window,
5242 StyleSheetListOwner::Document(Dom::from_ref(self)),
5243 can_gc,
5244 )
5245 })
5246 }
5247
5248 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
5250 self.implementation
5251 .or_init(|| DOMImplementation::new(self, can_gc))
5252 }
5253
5254 fn URL(&self) -> USVString {
5256 USVString(String::from(self.url().as_str()))
5257 }
5258
5259 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5261 self.document_or_shadow_root.get_active_element(
5262 self.get_focused_element(),
5263 self.GetBody(),
5264 self.GetDocumentElement(),
5265 )
5266 }
5267
5268 fn HasFocus(&self) -> bool {
5270 if self.window().parent_info().is_none() {
5292 self.is_fully_active()
5294 } else {
5295 self.is_fully_active() && self.has_focus.get()
5297 }
5298 }
5299
5300 fn Domain(&self) -> DOMString {
5302 match self.origin.effective_domain() {
5304 None => DOMString::new(),
5306 Some(Host::Domain(domain)) => DOMString::from(domain),
5308 Some(host) => DOMString::from(host.to_string()),
5309 }
5310 }
5311
5312 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5314 if !self.has_browsing_context {
5316 return Err(Error::Security(None));
5317 }
5318
5319 if self.has_active_sandboxing_flag(
5322 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5323 ) {
5324 return Err(Error::Security(None));
5325 }
5326
5327 let effective_domain = match self.origin.effective_domain() {
5329 Some(effective_domain) => effective_domain,
5330 None => return Err(Error::Security(None)),
5332 };
5333
5334 let host =
5336 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5337 None => return Err(Error::Security(None)),
5338 Some(host) => host,
5339 };
5340
5341 self.origin.set_domain(host);
5346
5347 Ok(())
5348 }
5349
5350 fn Referrer(&self) -> DOMString {
5352 match self.referrer {
5353 Some(ref referrer) => DOMString::from(referrer.to_string()),
5354 None => DOMString::new(),
5355 }
5356 }
5357
5358 fn DocumentURI(&self) -> USVString {
5360 self.URL()
5361 }
5362
5363 fn CompatMode(&self) -> DOMString {
5365 DOMString::from(match self.quirks_mode.get() {
5366 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5367 QuirksMode::Quirks => "BackCompat",
5368 })
5369 }
5370
5371 fn CharacterSet(&self) -> DOMString {
5373 DOMString::from(self.encoding.get().name())
5374 }
5375
5376 fn Charset(&self) -> DOMString {
5378 self.CharacterSet()
5379 }
5380
5381 fn InputEncoding(&self) -> DOMString {
5383 self.CharacterSet()
5384 }
5385
5386 fn ContentType(&self) -> DOMString {
5388 DOMString::from(self.content_type.to_string())
5389 }
5390
5391 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5393 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5394 }
5395
5396 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5398 self.upcast::<Node>().child_elements().next()
5399 }
5400
5401 fn GetElementsByTagName(
5403 &self,
5404 qualified_name: DOMString,
5405 can_gc: CanGc,
5406 ) -> DomRoot<HTMLCollection> {
5407 let qualified_name = LocalName::from(qualified_name);
5408 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5409 return DomRoot::from_ref(entry);
5410 }
5411 let result = HTMLCollection::by_qualified_name(
5412 &self.window,
5413 self.upcast(),
5414 qualified_name.clone(),
5415 can_gc,
5416 );
5417 self.tag_map
5418 .borrow_mut()
5419 .insert(qualified_name, Dom::from_ref(&*result));
5420 result
5421 }
5422
5423 fn GetElementsByTagNameNS(
5425 &self,
5426 maybe_ns: Option<DOMString>,
5427 tag_name: DOMString,
5428 can_gc: CanGc,
5429 ) -> DomRoot<HTMLCollection> {
5430 let ns = namespace_from_domstring(maybe_ns);
5431 let local = LocalName::from(tag_name);
5432 let qname = QualName::new(None, ns, local);
5433 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5434 return DomRoot::from_ref(collection);
5435 }
5436 let result =
5437 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
5438 self.tagns_map
5439 .borrow_mut()
5440 .insert(qname, Dom::from_ref(&*result));
5441 result
5442 }
5443
5444 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5446 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5447 .map(Atom::from)
5448 .collect();
5449 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5450 return DomRoot::from_ref(collection);
5451 }
5452 let result = HTMLCollection::by_atomic_class_name(
5453 &self.window,
5454 self.upcast(),
5455 class_atoms.clone(),
5456 can_gc,
5457 );
5458 self.classes_map
5459 .borrow_mut()
5460 .insert(class_atoms, Dom::from_ref(&*result));
5461 result
5462 }
5463
5464 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5466 self.get_element_by_id(&Atom::from(id))
5467 }
5468
5469 fn CreateElement(
5471 &self,
5472 cx: &mut js::context::JSContext,
5473 mut local_name: DOMString,
5474 options: StringOrElementCreationOptions,
5475 ) -> Fallible<DomRoot<Element>> {
5476 if !is_valid_element_local_name(&local_name.str()) {
5479 debug!("Not a valid element name");
5480 return Err(Error::InvalidCharacter(None));
5481 }
5482
5483 if self.is_html_document {
5484 local_name.make_ascii_lowercase();
5485 }
5486
5487 let ns = if self.is_html_document || self.is_xhtml_document() {
5488 ns!(html)
5489 } else {
5490 ns!()
5491 };
5492
5493 let name = QualName::new(None, ns, LocalName::from(local_name));
5494 let is = match options {
5495 StringOrElementCreationOptions::String(_) => None,
5496 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5497 options.is.as_ref().map(LocalName::from)
5498 },
5499 };
5500 Ok(Element::create(
5501 name,
5502 is,
5503 self,
5504 ElementCreator::ScriptCreated,
5505 CustomElementCreationMode::Synchronous,
5506 None,
5507 CanGc::from_cx(cx),
5508 ))
5509 }
5510
5511 fn CreateElementNS(
5513 &self,
5514 cx: &mut js::context::JSContext,
5515 namespace: Option<DOMString>,
5516 qualified_name: DOMString,
5517 options: StringOrElementCreationOptions,
5518 ) -> Fallible<DomRoot<Element>> {
5519 let context = domname::Context::Element;
5522 let (namespace, prefix, local_name) =
5523 domname::validate_and_extract(namespace, &qualified_name, context)?;
5524
5525 let name = QualName::new(prefix, namespace, local_name);
5528 let is = match options {
5529 StringOrElementCreationOptions::String(_) => None,
5530 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5531 options.is.as_ref().map(LocalName::from)
5532 },
5533 };
5534
5535 Ok(Element::create(
5537 name,
5538 is,
5539 self,
5540 ElementCreator::ScriptCreated,
5541 CustomElementCreationMode::Synchronous,
5542 None,
5543 CanGc::from_cx(cx),
5544 ))
5545 }
5546
5547 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5549 if !is_valid_attribute_local_name(&local_name.str()) {
5552 debug!("Not a valid attribute name");
5553 return Err(Error::InvalidCharacter(None));
5554 }
5555 if self.is_html_document {
5556 local_name.make_ascii_lowercase();
5557 }
5558 let name = LocalName::from(local_name);
5559 let value = AttrValue::String("".to_owned());
5560
5561 Ok(Attr::new(
5562 self,
5563 name.clone(),
5564 value,
5565 name,
5566 ns!(),
5567 None,
5568 None,
5569 can_gc,
5570 ))
5571 }
5572
5573 fn CreateAttributeNS(
5575 &self,
5576 namespace: Option<DOMString>,
5577 qualified_name: DOMString,
5578 can_gc: CanGc,
5579 ) -> Fallible<DomRoot<Attr>> {
5580 let context = domname::Context::Attribute;
5583 let (namespace, prefix, local_name) =
5584 domname::validate_and_extract(namespace, &qualified_name, context)?;
5585 let value = AttrValue::String("".to_owned());
5586 let qualified_name = LocalName::from(qualified_name);
5587 Ok(Attr::new(
5588 self,
5589 local_name,
5590 value,
5591 qualified_name,
5592 namespace,
5593 prefix,
5594 None,
5595 can_gc,
5596 ))
5597 }
5598
5599 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5601 DocumentFragment::new(self, can_gc)
5602 }
5603
5604 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5606 Text::new(data, self, can_gc)
5607 }
5608
5609 fn CreateCDATASection(
5611 &self,
5612 data: DOMString,
5613 can_gc: CanGc,
5614 ) -> Fallible<DomRoot<CDATASection>> {
5615 if self.is_html_document {
5617 return Err(Error::NotSupported(None));
5618 }
5619
5620 if data.contains("]]>") {
5622 return Err(Error::InvalidCharacter(None));
5623 }
5624
5625 Ok(CDATASection::new(data, self, can_gc))
5627 }
5628
5629 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5631 Comment::new(data, self, None, can_gc)
5632 }
5633
5634 fn CreateProcessingInstruction(
5636 &self,
5637 target: DOMString,
5638 data: DOMString,
5639 can_gc: CanGc,
5640 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5641 if !matches_name_production(&target.str()) {
5643 return Err(Error::InvalidCharacter(None));
5644 }
5645
5646 if data.contains("?>") {
5648 return Err(Error::InvalidCharacter(None));
5649 }
5650
5651 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5653 }
5654
5655 fn ImportNode(
5657 &self,
5658 cx: &mut js::context::JSContext,
5659 node: &Node,
5660 options: BooleanOrImportNodeOptions,
5661 ) -> Fallible<DomRoot<Node>> {
5662 if node.is::<Document>() || node.is::<ShadowRoot>() {
5664 return Err(Error::NotSupported(None));
5665 }
5666 let (subtree, registry) = match options {
5668 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5671 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5673 let subtree = (!options.selfOnly).into();
5675 let registry = options.customElementRegistry;
5677 (subtree, registry)
5681 },
5682 };
5683 let registry = registry
5686 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5687
5688 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5691 }
5692
5693 fn AdoptNode(&self, cx: &mut js::context::JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5695 if node.is::<Document>() {
5697 return Err(Error::NotSupported(None));
5698 }
5699
5700 if node.is::<ShadowRoot>() {
5702 return Err(Error::HierarchyRequest(None));
5703 }
5704
5705 Node::adopt(cx, node, self);
5707
5708 Ok(DomRoot::from_ref(node))
5710 }
5711
5712 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5714 interface.make_ascii_lowercase();
5715 match &*interface.str() {
5716 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5717 &self.window,
5718 can_gc,
5719 ))),
5720 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5721 CompositionEvent::new_uninitialized(&self.window, can_gc),
5722 )),
5723 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5724 self.window.upcast(),
5725 can_gc,
5726 ))),
5727 "events" | "event" | "htmlevents" | "svgevents" => {
5730 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5731 },
5732 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5733 &self.window,
5734 can_gc,
5735 ))),
5736 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5737 &self.window,
5738 can_gc,
5739 ))),
5740 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5741 &self.window,
5742 can_gc,
5743 ))),
5744 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5745 self.window.upcast(),
5746 can_gc,
5747 ))),
5748 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5749 &self.window,
5750 can_gc,
5751 ))),
5752 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5753 &self.window,
5754 "".into(),
5755 can_gc,
5756 ))),
5757 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5758 &self.window,
5759 &TouchList::new(&self.window, &[], can_gc),
5760 &TouchList::new(&self.window, &[], can_gc),
5761 &TouchList::new(&self.window, &[], can_gc),
5762 can_gc,
5763 ))),
5764 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5765 &self.window,
5766 can_gc,
5767 ))),
5768 _ => Err(Error::NotSupported(None)),
5769 }
5770 }
5771
5772 fn LastModified(&self) -> DOMString {
5774 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5775 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5781 }))
5782 }
5783
5784 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5786 Range::new_with_doc(self, None, can_gc)
5787 }
5788
5789 fn CreateNodeIterator(
5791 &self,
5792 root: &Node,
5793 what_to_show: u32,
5794 filter: Option<Rc<NodeFilter>>,
5795 can_gc: CanGc,
5796 ) -> DomRoot<NodeIterator> {
5797 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5798 }
5799
5800 fn CreateTreeWalker(
5802 &self,
5803 root: &Node,
5804 what_to_show: u32,
5805 filter: Option<Rc<NodeFilter>>,
5806 ) -> DomRoot<TreeWalker> {
5807 TreeWalker::new(self, root, what_to_show, filter)
5808 }
5809
5810 fn Title(&self) -> DOMString {
5812 self.title().unwrap_or_else(|| DOMString::from(""))
5813 }
5814
5815 fn SetTitle(&self, cx: &mut js::context::JSContext, title: DOMString) {
5817 let root = match self.GetDocumentElement() {
5818 Some(root) => root,
5819 None => return,
5820 };
5821
5822 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5823 let elem = root.upcast::<Node>().child_elements().find(|node| {
5824 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5825 });
5826 match elem {
5827 Some(elem) => DomRoot::upcast::<Node>(elem),
5828 None => {
5829 let name = QualName::new(None, ns!(svg), local_name!("title"));
5830 let elem = Element::create(
5831 name,
5832 None,
5833 self,
5834 ElementCreator::ScriptCreated,
5835 CustomElementCreationMode::Synchronous,
5836 None,
5837 CanGc::from_cx(cx),
5838 );
5839 let parent = root.upcast::<Node>();
5840 let child = elem.upcast::<Node>();
5841 parent
5842 .InsertBefore(child, parent.GetFirstChild().as_deref(), CanGc::from_cx(cx))
5843 .unwrap()
5844 },
5845 }
5846 } else if root.namespace() == &ns!(html) {
5847 let elem = root
5848 .upcast::<Node>()
5849 .traverse_preorder(ShadowIncluding::No)
5850 .find(|node| node.is::<HTMLTitleElement>());
5851 match elem {
5852 Some(elem) => elem,
5853 None => match self.GetHead() {
5854 Some(head) => {
5855 let name = QualName::new(None, ns!(html), local_name!("title"));
5856 let elem = Element::create(
5857 name,
5858 None,
5859 self,
5860 ElementCreator::ScriptCreated,
5861 CustomElementCreationMode::Synchronous,
5862 None,
5863 CanGc::from_cx(cx),
5864 );
5865 head.upcast::<Node>()
5866 .AppendChild(elem.upcast(), CanGc::from_cx(cx))
5867 .unwrap()
5868 },
5869 None => return,
5870 },
5871 }
5872 } else {
5873 return;
5874 };
5875
5876 node.set_text_content_for_element(Some(title), CanGc::from_cx(cx));
5877 }
5878
5879 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5881 self.get_html_element()
5882 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5883 }
5884
5885 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5887 self.current_script.get()
5888 }
5889
5890 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5892 self.get_html_element().and_then(|root| {
5895 let node = root.upcast::<Node>();
5896 node.children()
5897 .find(|child| {
5898 matches!(
5899 child.type_id(),
5900 NodeTypeId::Element(ElementTypeId::HTMLElement(
5901 HTMLElementTypeId::HTMLBodyElement,
5902 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5903 HTMLElementTypeId::HTMLFrameSetElement,
5904 ))
5905 )
5906 })
5907 .map(|node| DomRoot::downcast(node).unwrap())
5908 })
5909 }
5910
5911 fn SetBody(
5913 &self,
5914 cx: &mut js::context::JSContext,
5915 new_body: Option<&HTMLElement>,
5916 ) -> ErrorResult {
5917 let new_body = match new_body {
5919 Some(new_body) => new_body,
5920 None => return Err(Error::HierarchyRequest(None)),
5921 };
5922
5923 let node = new_body.upcast::<Node>();
5924 match node.type_id() {
5925 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5926 NodeTypeId::Element(ElementTypeId::HTMLElement(
5927 HTMLElementTypeId::HTMLFrameSetElement,
5928 )) => {},
5929 _ => return Err(Error::HierarchyRequest(None)),
5930 }
5931
5932 let old_body = self.GetBody();
5934 if old_body.as_deref() == Some(new_body) {
5935 return Ok(());
5936 }
5937
5938 match (self.GetDocumentElement(), &old_body) {
5939 (Some(ref root), Some(child)) => {
5942 let root = root.upcast::<Node>();
5943 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
5944 .map(|_| ())
5945 },
5946
5947 (None, _) => Err(Error::HierarchyRequest(None)),
5949
5950 (Some(ref root), &None) => {
5953 let root = root.upcast::<Node>();
5954 root.AppendChild(new_body.upcast(), CanGc::from_cx(cx))
5955 .map(|_| ())
5956 },
5957 }
5958 }
5959
5960 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5962 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5963 }
5964
5965 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5967 self.images.or_init(|| {
5968 HTMLCollection::new_with_filter_fn(
5969 &self.window,
5970 self.upcast(),
5971 |element, _| element.is::<HTMLImageElement>(),
5972 can_gc,
5973 )
5974 })
5975 }
5976
5977 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5979 self.embeds.or_init(|| {
5980 HTMLCollection::new_with_filter_fn(
5981 &self.window,
5982 self.upcast(),
5983 |element, _| element.is::<HTMLEmbedElement>(),
5984 can_gc,
5985 )
5986 })
5987 }
5988
5989 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5991 self.Embeds(can_gc)
5992 }
5993
5994 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5996 self.links.or_init(|| {
5997 HTMLCollection::new_with_filter_fn(
5998 &self.window,
5999 self.upcast(),
6000 |element, _| {
6001 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
6002 element.has_attribute(&local_name!("href"))
6003 },
6004 can_gc,
6005 )
6006 })
6007 }
6008
6009 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6011 self.forms.or_init(|| {
6012 HTMLCollection::new_with_filter_fn(
6013 &self.window,
6014 self.upcast(),
6015 |element, _| element.is::<HTMLFormElement>(),
6016 can_gc,
6017 )
6018 })
6019 }
6020
6021 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6023 self.scripts.or_init(|| {
6024 HTMLCollection::new_with_filter_fn(
6025 &self.window,
6026 self.upcast(),
6027 |element, _| element.is::<HTMLScriptElement>(),
6028 can_gc,
6029 )
6030 })
6031 }
6032
6033 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6035 self.anchors.or_init(|| {
6036 HTMLCollection::new_with_filter_fn(
6037 &self.window,
6038 self.upcast(),
6039 |element, _| {
6040 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
6041 },
6042 can_gc,
6043 )
6044 })
6045 }
6046
6047 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6049 self.applets
6050 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
6051 }
6052
6053 fn GetLocation(&self) -> Option<DomRoot<Location>> {
6055 if self.is_fully_active() {
6056 Some(self.window.Location())
6057 } else {
6058 None
6059 }
6060 }
6061
6062 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6064 HTMLCollection::children(&self.window, self.upcast(), can_gc)
6065 }
6066
6067 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
6069 self.upcast::<Node>().child_elements().next()
6070 }
6071
6072 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
6074 self.upcast::<Node>()
6075 .rev_children()
6076 .find_map(DomRoot::downcast)
6077 }
6078
6079 fn ChildElementCount(&self) -> u32 {
6081 self.upcast::<Node>().child_elements().count() as u32
6082 }
6083
6084 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
6086 self.upcast::<Node>().prepend(nodes, can_gc)
6087 }
6088
6089 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
6091 self.upcast::<Node>().append(nodes, can_gc)
6092 }
6093
6094 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
6096 self.upcast::<Node>().replace_children(nodes, can_gc)
6097 }
6098
6099 fn MoveBefore(&self, node: &Node, child: Option<&Node>, can_gc: CanGc) -> ErrorResult {
6101 self.upcast::<Node>().move_before(node, child, can_gc)
6102 }
6103
6104 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
6106 self.upcast::<Node>().query_selector(selectors)
6107 }
6108
6109 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
6111 self.upcast::<Node>().query_selector_all(selectors)
6112 }
6113
6114 fn ReadyState(&self) -> DocumentReadyState {
6116 self.ready_state.get()
6117 }
6118
6119 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
6121 if self.has_browsing_context {
6122 Some(DomRoot::from_ref(&*self.window))
6123 } else {
6124 None
6125 }
6126 }
6127
6128 fn GetCookie(&self) -> Fallible<DOMString> {
6130 if self.is_cookie_averse() {
6131 return Ok(DOMString::new());
6132 }
6133
6134 if !self.origin.is_tuple() {
6135 return Err(Error::Security(None));
6136 }
6137
6138 let url = self.url();
6139 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
6140 let _ = self
6141 .window
6142 .as_global_scope()
6143 .resource_threads()
6144 .send(GetCookiesForUrl(url, tx, NonHTTP));
6145 let cookies = rx.recv().unwrap();
6146 Ok(cookies.map_or(DOMString::new(), DOMString::from))
6147 }
6148
6149 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
6151 if self.is_cookie_averse() {
6152 return Ok(());
6153 }
6154
6155 if !self.origin.is_tuple() {
6156 return Err(Error::Security(None));
6157 }
6158
6159 if !cookie.is_valid_for_cookie() {
6160 return Ok(());
6161 }
6162
6163 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6164 vec![cookie]
6165 } else {
6166 vec![]
6167 };
6168
6169 let _ = self
6170 .window
6171 .as_global_scope()
6172 .resource_threads()
6173 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6174 Ok(())
6175 }
6176
6177 fn BgColor(&self) -> DOMString {
6179 self.get_body_attribute(&local_name!("bgcolor"))
6180 }
6181
6182 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
6184 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
6185 }
6186
6187 fn FgColor(&self) -> DOMString {
6189 self.get_body_attribute(&local_name!("text"))
6190 }
6191
6192 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
6194 self.set_body_attribute(&local_name!("text"), value, can_gc)
6195 }
6196
6197 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
6199 if name.is_empty() {
6200 return None;
6201 }
6202 let name = Atom::from(name);
6203
6204 let elements_with_name = self.get_elements_with_name(&name);
6207 let name_iter = elements_with_name
6208 .iter()
6209 .filter(|elem| is_named_element_with_name_attribute(elem));
6210 let elements_with_id = self.get_elements_with_id(&name);
6211 let id_iter = elements_with_id
6212 .iter()
6213 .filter(|elem| is_named_element_with_id_attribute(elem));
6214 let mut elements = name_iter.chain(id_iter);
6215
6216 let first = elements.next()?;
6223 if elements.all(|other| first == other) {
6224 if let Some(nested_window_proxy) = first
6225 .downcast::<HTMLIFrameElement>()
6226 .and_then(|iframe| iframe.GetContentWindow())
6227 {
6228 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6229 }
6230
6231 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6233 }
6234
6235 #[derive(JSTraceable, MallocSizeOf)]
6238 struct DocumentNamedGetter {
6239 #[no_trace]
6240 name: Atom,
6241 }
6242 impl CollectionFilter for DocumentNamedGetter {
6243 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6244 let type_ = match elem.upcast::<Node>().type_id() {
6245 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6246 _ => return false,
6247 };
6248 match type_ {
6249 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6250 elem.get_name().as_ref() == Some(&self.name)
6251 },
6252 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6253 name == *self.name ||
6254 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6255 }),
6256 _ => false,
6260 }
6261 }
6262 }
6263 let collection = HTMLCollection::create(
6264 self.window(),
6265 self.upcast(),
6266 Box::new(DocumentNamedGetter { name }),
6267 can_gc,
6268 );
6269 Some(NamedPropertyValue::HTMLCollection(collection))
6270 }
6271
6272 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
6274 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
6275
6276 let name_map = self.name_map.borrow();
6277 for (name, elements) in &(name_map).0 {
6278 if name.is_empty() {
6279 continue;
6280 }
6281 let mut name_iter = elements
6282 .iter()
6283 .filter(|elem| is_named_element_with_name_attribute(elem));
6284 if let Some(first) = name_iter.next() {
6285 names_with_first_named_element_map.insert(name, first);
6286 }
6287 }
6288 let id_map = self.id_map.borrow();
6289 for (id, elements) in &(id_map).0 {
6290 if id.is_empty() {
6291 continue;
6292 }
6293 let mut id_iter = elements
6294 .iter()
6295 .filter(|elem| is_named_element_with_id_attribute(elem));
6296 if let Some(first) = id_iter.next() {
6297 match names_with_first_named_element_map.entry(id) {
6298 Vacant(entry) => drop(entry.insert(first)),
6299 Occupied(mut entry) => {
6300 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6301 *entry.get_mut() = first;
6302 }
6303 },
6304 }
6305 }
6306 }
6307
6308 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
6309 names_with_first_named_element_map
6310 .iter()
6311 .map(|(k, v)| (*k, *v))
6312 .collect();
6313 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6314 if a.1 == b.1 {
6315 a.0.cmp(b.0)
6318 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6319 Ordering::Less
6320 } else {
6321 Ordering::Greater
6322 }
6323 });
6324
6325 names_with_first_named_element_vec
6326 .iter()
6327 .map(|(k, _v)| DOMString::from(&***k))
6328 .collect()
6329 }
6330
6331 fn Clear(&self) {
6333 }
6335
6336 fn CaptureEvents(&self) {
6338 }
6340
6341 fn ReleaseEvents(&self) {
6343 }
6345
6346 global_event_handlers!();
6348
6349 event_handler!(
6351 readystatechange,
6352 GetOnreadystatechange,
6353 SetOnreadystatechange
6354 );
6355
6356 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6358 self.document_or_shadow_root.element_from_point(
6359 x,
6360 y,
6361 self.GetDocumentElement(),
6362 self.has_browsing_context,
6363 )
6364 }
6365
6366 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6368 self.document_or_shadow_root.elements_from_point(
6369 x,
6370 y,
6371 self.GetDocumentElement(),
6372 self.has_browsing_context,
6373 )
6374 }
6375
6376 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6378 if self.quirks_mode() == QuirksMode::Quirks {
6380 if let Some(ref body) = self.GetBody() {
6382 let e = body.upcast::<Element>();
6383 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6387 return Some(DomRoot::from_ref(e));
6388 }
6389 }
6390
6391 return None;
6393 }
6394
6395 self.GetDocumentElement()
6398 }
6399
6400 fn Open(
6402 &self,
6403 cx: &mut js::context::JSContext,
6404 _unused1: Option<DOMString>,
6405 _unused2: Option<DOMString>,
6406 ) -> Fallible<DomRoot<Document>> {
6407 if !self.is_html_document() {
6409 return Err(Error::InvalidState(None));
6410 }
6411
6412 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6414 return Err(Error::InvalidState(None));
6415 }
6416
6417 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6419
6420 if !self.origin.same_origin(&entry_responsible_document.origin) {
6422 return Err(Error::Security(None));
6423 }
6424
6425 if self
6427 .get_current_parser()
6428 .is_some_and(|parser| parser.is_active())
6429 {
6430 return Ok(DomRoot::from_ref(self));
6431 }
6432
6433 if self.is_prompting_or_unloading() {
6435 return Ok(DomRoot::from_ref(self));
6436 }
6437
6438 if self.active_parser_was_aborted.get() {
6440 return Ok(DomRoot::from_ref(self));
6441 }
6442
6443 self.window().set_navigation_start();
6447
6448 if self.has_browsing_context() {
6451 self.abort(cx);
6454 }
6455
6456 for node in self
6458 .upcast::<Node>()
6459 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6460 {
6461 node.upcast::<EventTarget>().remove_all_listeners();
6462 }
6463
6464 if self.window.Document() == DomRoot::from_ref(self) {
6466 self.window.upcast::<EventTarget>().remove_all_listeners();
6467 }
6468
6469 Node::replace_all(None, self.upcast::<Node>(), CanGc::from_cx(cx));
6471
6472 if self.is_fully_active() {
6479 let mut new_url = entry_responsible_document.url();
6481
6482 if entry_responsible_document != DomRoot::from_ref(self) {
6484 new_url.set_fragment(None);
6485 }
6486
6487 self.set_url(new_url);
6490 }
6491
6492 self.is_initial_about_blank.set(false);
6494
6495 self.set_quirks_mode(QuirksMode::NoQuirks);
6501
6502 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6508 *self.loader.borrow_mut() =
6509 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6510 ServoParser::parse_html_script_input(self, self.url());
6511
6512 self.ready_state.set(DocumentReadyState::Loading);
6518
6519 Ok(DomRoot::from_ref(self))
6521 }
6522
6523 fn Open_(
6525 &self,
6526 cx: &mut js::context::JSContext,
6527 url: USVString,
6528 target: DOMString,
6529 features: DOMString,
6530 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6531 self.browsing_context()
6532 .ok_or(Error::InvalidAccess(None))?
6533 .open(url, target, features, CanGc::from_cx(cx))
6534 }
6535
6536 fn Write(
6538 &self,
6539 cx: &mut js::context::JSContext,
6540 text: Vec<TrustedHTMLOrString>,
6541 ) -> ErrorResult {
6542 self.write(cx, text, false, "Document", "write")
6545 }
6546
6547 fn Writeln(
6549 &self,
6550 cx: &mut js::context::JSContext,
6551 text: Vec<TrustedHTMLOrString>,
6552 ) -> ErrorResult {
6553 self.write(cx, text, true, "Document", "writeln")
6556 }
6557
6558 fn Close(&self, cx: &mut js::context::JSContext) -> ErrorResult {
6560 if !self.is_html_document() {
6561 return Err(Error::InvalidState(None));
6563 }
6564
6565 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6568 return Err(Error::InvalidState(None));
6569 }
6570
6571 let parser = match self.get_current_parser() {
6573 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6574 _ => {
6575 return Ok(());
6576 },
6577 };
6578
6579 parser.close(cx);
6581
6582 Ok(())
6583 }
6584
6585 fn ExecCommand(
6587 &self,
6588 cx: &mut js::context::JSContext,
6589 command_id: DOMString,
6590 _show_ui: bool,
6591 value: TrustedHTMLOrString,
6592 ) -> Fallible<bool> {
6593 let value = if command_id == "insertHTML" {
6594 TrustedHTML::get_trusted_script_compliant_string(
6595 self.window.as_global_scope(),
6596 value,
6597 "Document execCommand",
6598 CanGc::from_cx(cx),
6599 )?
6600 } else {
6601 match value {
6602 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6603 TrustedHTMLOrString::String(value) => value,
6604 }
6605 };
6606
6607 Ok(self.exec_command_for_command_id(cx, command_id, value))
6608 }
6609
6610 fn QueryCommandEnabled(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6612 self.check_support_and_enabled(cx, &command_id).is_some()
6614 }
6615
6616 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6618 self.is_command_supported(command_id)
6622 }
6623
6624 fn QueryCommandIndeterm(&self, command_id: DOMString) -> bool {
6626 self.is_command_indeterminate(command_id)
6627 }
6628
6629 fn QueryCommandState(&self, command_id: DOMString) -> bool {
6631 self.command_state_for_command(command_id)
6632 }
6633
6634 fn QueryCommandValue(&self, command_id: DOMString) -> DOMString {
6636 self.command_value_for_command(command_id)
6637 }
6638
6639 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6641
6642 event_handler!(
6644 fullscreenchange,
6645 GetOnfullscreenchange,
6646 SetOnfullscreenchange
6647 );
6648
6649 fn FullscreenEnabled(&self) -> bool {
6651 self.get_allow_fullscreen()
6652 }
6653
6654 fn Fullscreen(&self) -> bool {
6656 self.fullscreen_element.get().is_some()
6657 }
6658
6659 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6661 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6662 }
6663
6664 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6666 self.exit_fullscreen(can_gc)
6667 }
6668
6669 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6673 match self.media_controls.borrow().get(&*id.str()) {
6674 Some(m) => Ok(DomRoot::from_ref(m)),
6675 None => Err(Error::InvalidAccess(None)),
6676 }
6677 }
6678
6679 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6681 if self.has_browsing_context {
6682 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6683 } else {
6684 None
6685 }
6686 }
6687
6688 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6690 self.fonts
6691 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6692 }
6693
6694 fn Hidden(&self) -> bool {
6696 self.visibility_state.get() == DocumentVisibilityState::Hidden
6697 }
6698
6699 fn VisibilityState(&self) -> DocumentVisibilityState {
6701 self.visibility_state.get()
6702 }
6703
6704 fn CreateExpression(
6705 &self,
6706 expression: DOMString,
6707 resolver: Option<Rc<XPathNSResolver>>,
6708 can_gc: CanGc,
6709 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6710 let parsed_expression =
6711 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6712 Ok(XPathExpression::new(
6713 &self.window,
6714 None,
6715 can_gc,
6716 parsed_expression,
6717 ))
6718 }
6719
6720 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6721 let global = self.global();
6722 let window = global.as_window();
6723 let evaluator = XPathEvaluator::new(window, None, can_gc);
6724 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6725 }
6726
6727 fn Evaluate(
6728 &self,
6729 expression: DOMString,
6730 context_node: &Node,
6731 resolver: Option<Rc<XPathNSResolver>>,
6732 result_type: u16,
6733 result: Option<&super::types::XPathResult>,
6734 can_gc: CanGc,
6735 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6736 let parsed_expression =
6737 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6738 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6739 context_node,
6740 result_type,
6741 result,
6742 can_gc,
6743 )
6744 }
6745
6746 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6748 self.adopted_stylesheets_frozen_types.get_or_init(
6749 || {
6750 self.adopted_stylesheets
6751 .borrow()
6752 .clone()
6753 .iter()
6754 .map(|sheet| sheet.as_rooted())
6755 .collect()
6756 },
6757 context,
6758 retval,
6759 can_gc,
6760 );
6761 }
6762
6763 fn SetAdoptedStyleSheets(
6765 &self,
6766 context: JSContext,
6767 val: HandleValue,
6768 can_gc: CanGc,
6769 ) -> ErrorResult {
6770 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6771 context,
6772 self.adopted_stylesheets.borrow_mut().as_mut(),
6773 val,
6774 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6775 can_gc,
6776 );
6777
6778 if result.is_ok() {
6780 self.adopted_stylesheets_frozen_types.clear()
6781 }
6782
6783 result
6784 }
6785}
6786
6787fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6788 if marker.get().is_none() {
6789 marker.set(Some(CrossProcessInstant::now()))
6790 }
6791}
6792
6793#[derive(Clone, Copy, PartialEq)]
6795pub(crate) enum FocusType {
6796 Element, Parent, }
6799
6800#[derive(Clone, Copy, PartialEq)]
6802pub enum FocusInitiator {
6803 Keyboard,
6806 Click,
6809 Script,
6812 Remote,
6815}
6816
6817pub(crate) enum FocusEventType {
6819 Focus, Blur, }
6822
6823#[derive(JSTraceable, MallocSizeOf)]
6824pub(crate) enum AnimationFrameCallback {
6825 DevtoolsFramerateTick {
6826 actor_name: String,
6827 },
6828 FrameRequestCallback {
6829 #[conditional_malloc_size_of]
6830 callback: Rc<FrameRequestCallback>,
6831 },
6832}
6833
6834impl AnimationFrameCallback {
6835 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6836 match *self {
6837 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6838 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6839 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6840 devtools_sender.send(msg).unwrap();
6841 },
6842 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6843 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6846 },
6847 }
6848 }
6849}
6850
6851#[derive(Default, JSTraceable, MallocSizeOf)]
6852#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6853struct PendingInOrderScriptVec {
6854 scripts: DomRefCell<VecDeque<PendingScript>>,
6855}
6856
6857impl PendingInOrderScriptVec {
6858 fn is_empty(&self) -> bool {
6859 self.scripts.borrow().is_empty()
6860 }
6861
6862 fn push(&self, element: &HTMLScriptElement) {
6863 self.scripts
6864 .borrow_mut()
6865 .push_back(PendingScript::new(element));
6866 }
6867
6868 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6869 let mut scripts = self.scripts.borrow_mut();
6870 let entry = scripts
6871 .iter_mut()
6872 .find(|entry| &*entry.element == element)
6873 .unwrap();
6874 entry.loaded(result);
6875 }
6876
6877 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6878 let mut scripts = self.scripts.borrow_mut();
6879 let pair = scripts.front_mut()?.take_result()?;
6880 scripts.pop_front();
6881 Some(pair)
6882 }
6883
6884 fn clear(&self) {
6885 *self.scripts.borrow_mut() = Default::default();
6886 }
6887}
6888
6889#[derive(JSTraceable, MallocSizeOf)]
6890#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6891struct PendingScript {
6892 element: Dom<HTMLScriptElement>,
6893 load: Option<ScriptResult>,
6895}
6896
6897impl PendingScript {
6898 fn new(element: &HTMLScriptElement) -> Self {
6899 Self {
6900 element: Dom::from_ref(element),
6901 load: None,
6902 }
6903 }
6904
6905 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6906 Self {
6907 element: Dom::from_ref(element),
6908 load,
6909 }
6910 }
6911
6912 fn loaded(&mut self, result: ScriptResult) {
6913 assert!(self.load.is_none());
6914 self.load = Some(result);
6915 }
6916
6917 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6918 self.load
6919 .take()
6920 .map(|result| (DomRoot::from_ref(&*self.element), result))
6921 }
6922}
6923
6924fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6925 let type_ = match elem.upcast::<Node>().type_id() {
6926 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6927 _ => return false,
6928 };
6929 match type_ {
6930 HTMLElementTypeId::HTMLFormElement |
6931 HTMLElementTypeId::HTMLIFrameElement |
6932 HTMLElementTypeId::HTMLImageElement => true,
6933 _ => false,
6937 }
6938}
6939
6940fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6941 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6945}
6946
6947impl DocumentHelpers for Document {
6948 fn ensure_safe_to_run_script_or_layout(&self) {
6949 Document::ensure_safe_to_run_script_or_layout(self)
6950 }
6951}
6952
6953pub(crate) struct SameoriginAncestorNavigablesIterator {
6957 document: DomRoot<Document>,
6958}
6959
6960impl SameoriginAncestorNavigablesIterator {
6961 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6962 Self { document }
6963 }
6964}
6965
6966impl Iterator for SameoriginAncestorNavigablesIterator {
6967 type Item = DomRoot<Document>;
6968
6969 fn next(&mut self) -> Option<Self::Item> {
6970 let window_proxy = self.document.browsing_context()?;
6971 self.document = window_proxy.parent()?.document()?;
6972 Some(self.document.clone())
6973 }
6974}
6975
6976pub(crate) struct SameOriginDescendantNavigablesIterator {
6981 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6982}
6983
6984impl SameOriginDescendantNavigablesIterator {
6985 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6986 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6987 Self {
6988 stack: vec![Box::new(iframes.into_iter())],
6989 }
6990 }
6991
6992 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6993 let mut cur_iframe = self.stack.last_mut()?.next();
6994 while cur_iframe.is_none() {
6995 self.stack.pop();
6996 cur_iframe = self.stack.last_mut()?.next();
6997 }
6998 cur_iframe
6999 }
7000}
7001
7002impl Iterator for SameOriginDescendantNavigablesIterator {
7003 type Item = DomRoot<Document>;
7004
7005 fn next(&mut self) -> Option<Self::Item> {
7006 while let Some(iframe) = self.get_next_iframe() {
7007 let Some(pipeline_id) = iframe.pipeline_id() else {
7008 continue;
7009 };
7010
7011 if let Some(document) = ScriptThread::find_document(pipeline_id) {
7012 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
7013 document.iframes().iter().collect();
7014 self.stack.push(Box::new(child_iframes.into_iter()));
7015 return Some(document);
7016 } else {
7017 continue;
7018 };
7019 }
7020 None
7021 }
7022}