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::rc::Rc;
11use std::str::FromStr;
12use std::sync::{LazyLock, Mutex};
13use std::time::Duration;
14
15use base::cross_process_instant::CrossProcessInstant;
16use base::id::WebViewId;
17use base::{Epoch, IpcSend, generic_channel};
18use bitflags::bitflags;
19use canvas_traits::canvas::CanvasId;
20use canvas_traits::webgl::{WebGLContextId, WebGLMsg};
21use chrono::Local;
22use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
23use content_security_policy::sandboxing_directive::SandboxingFlagSet;
24use content_security_policy::{CspList, PolicyDisposition};
25use cookie::Cookie;
26use data_url::mime::Mime;
27use devtools_traits::ScriptToDevtoolsControlMsg;
28use dom_struct::dom_struct;
29use embedder_traits::{
30 AllowOrDeny, AnimationState, EmbedderMsg, FocusSequenceNumber, Image, LoadStatus,
31};
32use encoding_rs::{Encoding, UTF_8};
33use html5ever::{LocalName, Namespace, QualName, local_name, ns};
34use hyper_serde::Serde;
35use js::rust::{HandleObject, HandleValue, MutableHandleValue};
36use layout_api::{
37 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
38 TrustedNodeAddress,
39};
40use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
41use net_traits::CookieSource::NonHTTP;
42use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
43use net_traits::policy_container::PolicyContainer;
44use net_traits::pub_domains::is_pub_domain;
45use net_traits::request::{InsecureRequestsPolicy, PreloadedResources, RequestBuilder};
46use net_traits::response::HttpsState;
47use net_traits::{FetchResponseListener, ReferrerPolicy};
48use percent_encoding::percent_decode;
49use profile_traits::ipc as profile_ipc;
50use profile_traits::time::TimerMetadataFrameType;
51use regex::bytes::Regex;
52use rustc_hash::{FxBuildHasher, FxHashMap};
53use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
54use script_bindings::interfaces::DocumentHelpers;
55use script_bindings::script_runtime::JSContext;
56use script_traits::{DocumentActivity, ProgressiveWebMetricType};
57use servo_arc::Arc;
58use servo_config::pref;
59use servo_media::{ClientContextId, ServoMedia};
60use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
61use style::attr::AttrValue;
62use style::context::QuirksMode;
63use style::invalidation::element::restyle_hints::RestyleHint;
64use style::selector_parser::Snapshot;
65use style::shared_lock::SharedRwLock as StyleSharedRwLock;
66use style::str::{split_html_space_chars, str_join};
67use style::stylesheet_set::DocumentStylesheetSet;
68use style::stylesheets::{Origin, OriginSet, Stylesheet};
69use stylo_atoms::Atom;
70use url::Host;
71use uuid::Uuid;
72#[cfg(feature = "webgpu")]
73use webgpu_traits::WebGPUContextId;
74
75use crate::animation_timeline::AnimationTimeline;
76use crate::animations::Animations;
77use crate::canvas_context::CanvasContext as _;
78use crate::document_loader::{DocumentLoader, LoadType};
79use crate::dom::attr::Attr;
80use crate::dom::beforeunloadevent::BeforeUnloadEvent;
81use crate::dom::bindings::callback::ExceptionHandling;
82use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
83use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
84use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
85 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
86};
87use crate::dom::bindings::codegen::Bindings::ElementBinding::{
88 ScrollIntoViewContainer, ScrollIntoViewOptions, ScrollLogicalPosition,
89};
90use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
91use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
92use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
93use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
94use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
95use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
96use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
97use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
98use crate::dom::bindings::codegen::Bindings::WindowBinding::{
99 FrameRequestCallback, ScrollBehavior, ScrollOptions, WindowMethods,
100};
101use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
102use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
103use crate::dom::bindings::codegen::UnionTypes::{
104 BooleanOrScrollIntoViewOptions, NodeOrString, StringOrElementCreationOptions,
105 TrustedHTMLOrString,
106};
107use crate::dom::bindings::domname::{
108 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
109};
110use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
111use crate::dom::bindings::frozenarray::CachedFrozenArray;
112use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
113use crate::dom::bindings::num::Finite;
114use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
115use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
116use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
117use crate::dom::bindings::str::{DOMString, USVString};
118use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
119use crate::dom::bindings::weakref::DOMTracker;
120use crate::dom::bindings::xmlname::matches_name_production;
121use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
122use crate::dom::cdatasection::CDATASection;
123use crate::dom::comment::Comment;
124use crate::dom::compositionevent::CompositionEvent;
125use crate::dom::css::cssstylesheet::CSSStyleSheet;
126use crate::dom::css::fontfaceset::FontFaceSet;
127use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
128use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack};
129use crate::dom::customevent::CustomEvent;
130use crate::dom::document_embedder_controls::DocumentEmbedderControls;
131use crate::dom::document_event_handler::DocumentEventHandler;
132use crate::dom::documentfragment::DocumentFragment;
133use crate::dom::documentorshadowroot::{
134 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
135};
136use crate::dom::documenttype::DocumentType;
137use crate::dom::domimplementation::DOMImplementation;
138use crate::dom::element::{
139 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
140 ElementPerformFullscreenExit,
141};
142use crate::dom::event::{Event, EventBubbles, EventCancelable};
143use crate::dom::eventtarget::EventTarget;
144use crate::dom::focusevent::FocusEvent;
145use crate::dom::globalscope::GlobalScope;
146use crate::dom::hashchangeevent::HashChangeEvent;
147use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
148use crate::dom::html::htmlareaelement::HTMLAreaElement;
149use crate::dom::html::htmlbaseelement::HTMLBaseElement;
150use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
151use crate::dom::html::htmlelement::HTMLElement;
152use crate::dom::html::htmlembedelement::HTMLEmbedElement;
153use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
154use crate::dom::html::htmlheadelement::HTMLHeadElement;
155use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
156use crate::dom::html::htmliframeelement::HTMLIFrameElement;
157use crate::dom::html::htmlimageelement::HTMLImageElement;
158use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
159use crate::dom::html::htmltitleelement::HTMLTitleElement;
160use crate::dom::intersectionobserver::IntersectionObserver;
161use crate::dom::keyboardevent::KeyboardEvent;
162use crate::dom::location::{Location, NavigationType};
163use crate::dom::messageevent::MessageEvent;
164use crate::dom::mouseevent::MouseEvent;
165use crate::dom::node::{
166 CloneChildrenFlag, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding,
167};
168use crate::dom::nodeiterator::NodeIterator;
169use crate::dom::nodelist::NodeList;
170use crate::dom::pagetransitionevent::PageTransitionEvent;
171use crate::dom::performance::performanceentry::PerformanceEntry;
172use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
173use crate::dom::processinginstruction::ProcessingInstruction;
174use crate::dom::promise::Promise;
175use crate::dom::range::Range;
176use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
177use crate::dom::scrolling_box::ScrollingBox;
178use crate::dom::selection::Selection;
179use crate::dom::servoparser::ServoParser;
180use crate::dom::shadowroot::ShadowRoot;
181use crate::dom::storageevent::StorageEvent;
182use crate::dom::text::Text;
183use crate::dom::touchevent::TouchEvent as DomTouchEvent;
184use crate::dom::touchlist::TouchList;
185use crate::dom::treewalker::TreeWalker;
186use crate::dom::trustedhtml::TrustedHTML;
187use crate::dom::types::VisibilityStateEntry;
188use crate::dom::uievent::UIEvent;
189use crate::dom::virtualmethods::vtable_for;
190use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
191#[cfg(feature = "webgpu")]
192use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext;
193use crate::dom::websocket::WebSocket;
194use crate::dom::window::Window;
195use crate::dom::windowproxy::WindowProxy;
196use crate::dom::xpathevaluator::XPathEvaluator;
197use crate::fetch::FetchCanceller;
198use crate::iframe_collection::IFrameCollection;
199use crate::image_animation::ImageAnimationManager;
200use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
201use crate::mime::{APPLICATION, CHARSET};
202use crate::network_listener::{NetworkListener, PreInvoke};
203use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
204use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
205use crate::script_thread::ScriptThread;
206use crate::stylesheet_set::StylesheetSetRef;
207use crate::task::NonSendTaskBox;
208use crate::task_source::TaskSourceName;
209use crate::timers::OneshotTimerCallback;
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) {
241 self.window.Location().navigate(
242 self.url.clone(),
243 NavigationHistoryBehavior::Replace,
244 NavigationType::DeclarativeRefresh,
245 can_gc,
246 );
247 }
248}
249
250#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
251pub(crate) enum IsHTMLDocument {
252 HTMLDocument,
253 NonHTMLDocument,
254}
255
256#[derive(JSTraceable, MallocSizeOf)]
257#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
258struct FocusTransaction {
259 element: Option<Dom<Element>>,
261 has_focus: bool,
263 focus_options: FocusOptions,
265}
266
267#[derive(JSTraceable, MallocSizeOf)]
269pub(crate) enum DeclarativeRefresh {
270 PendingLoad {
271 #[no_trace]
272 url: ServoUrl,
273 time: u64,
274 },
275 CreatedAfterLoad,
276}
277
278#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
281pub(crate) struct RenderingUpdateReason(u8);
282
283bitflags! {
284 impl RenderingUpdateReason: u8 {
285 const ResizeObserverStartedObservingTarget = 1 << 0;
288 const IntersectionObserverStartedObservingTarget = 1 << 1;
291 const FontReadyPromiseFulfilled = 1 << 2;
295 }
296}
297
298#[dom_struct]
300pub(crate) struct Document {
301 node: Node,
302 document_or_shadow_root: DocumentOrShadowRoot,
303 window: Dom<Window>,
304 implementation: MutNullableDom<DOMImplementation>,
305 #[ignore_malloc_size_of = "type from external crate"]
306 #[no_trace]
307 content_type: Mime,
308 last_modified: Option<String>,
309 #[no_trace]
310 encoding: Cell<&'static Encoding>,
311 has_browsing_context: bool,
312 is_html_document: bool,
313 #[no_trace]
314 activity: Cell<DocumentActivity>,
315 #[no_trace]
316 url: DomRefCell<ServoUrl>,
317 #[ignore_malloc_size_of = "defined in selectors"]
318 #[no_trace]
319 quirks_mode: Cell<QuirksMode>,
320 event_handler: DocumentEventHandler,
322 embedder_controls: DocumentEmbedderControls,
324 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
327 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
328 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
329 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
330 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
331 images: MutNullableDom<HTMLCollection>,
332 embeds: MutNullableDom<HTMLCollection>,
333 links: MutNullableDom<HTMLCollection>,
334 forms: MutNullableDom<HTMLCollection>,
335 scripts: MutNullableDom<HTMLCollection>,
336 anchors: MutNullableDom<HTMLCollection>,
337 applets: MutNullableDom<HTMLCollection>,
338 iframes: RefCell<IFrameCollection>,
340 #[no_trace]
343 style_shared_lock: StyleSharedRwLock,
344 #[custom_trace]
346 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
347 stylesheet_list: MutNullableDom<StyleSheetList>,
348 ready_state: Cell<DocumentReadyState>,
349 domcontentloaded_dispatched: Cell<bool>,
351 focus_transaction: DomRefCell<Option<FocusTransaction>>,
353 focused: MutNullableDom<Element>,
355 #[no_trace]
357 focus_sequence: Cell<FocusSequenceNumber>,
358 has_focus: Cell<bool>,
362 current_script: MutNullableDom<HTMLScriptElement>,
364 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
366 script_blocking_stylesheets_count: Cell<u32>,
368 render_blocking_element_count: Cell<u32>,
371 deferred_scripts: PendingInOrderScriptVec,
373 asap_in_order_scripts_list: PendingInOrderScriptVec,
375 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
377 animation_frame_ident: Cell<u32>,
380 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
383 running_animation_callbacks: Cell<bool>,
388 loader: DomRefCell<DocumentLoader>,
390 current_parser: MutNullableDom<ServoParser>,
392 base_element: MutNullableDom<HTMLBaseElement>,
394 appropriate_template_contents_owner_document: MutNullableDom<Document>,
397 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
400 #[no_trace]
404 needs_restyle: Cell<RestyleReason>,
405 #[no_trace]
408 dom_interactive: Cell<Option<CrossProcessInstant>>,
409 #[no_trace]
410 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
411 #[no_trace]
412 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
413 #[no_trace]
414 dom_complete: Cell<Option<CrossProcessInstant>>,
415 #[no_trace]
416 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
417 #[no_trace]
418 load_event_start: Cell<Option<CrossProcessInstant>>,
419 #[no_trace]
420 load_event_end: Cell<Option<CrossProcessInstant>>,
421 #[no_trace]
422 unload_event_start: Cell<Option<CrossProcessInstant>>,
423 #[no_trace]
424 unload_event_end: Cell<Option<CrossProcessInstant>>,
425 #[no_trace]
427 https_state: Cell<HttpsState>,
428 #[no_trace]
430 origin: MutableOrigin,
431 referrer: Option<String>,
433 target_element: MutNullableDom<Element>,
435 #[no_trace]
437 policy_container: DomRefCell<PolicyContainer>,
438 #[no_trace]
440 #[conditional_malloc_size_of]
441 preloaded_resources: PreloadedResources,
442 ignore_destructive_writes_counter: Cell<u32>,
444 ignore_opens_during_unload_counter: Cell<u32>,
446 spurious_animation_frames: Cell<u8>,
450
451 dom_count: Cell<u32>,
457 fullscreen_element: MutNullableDom<Element>,
459 form_id_listener_map:
466 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
467 #[no_trace]
468 interactive_time: DomRefCell<ProgressiveWebMetrics>,
469 #[no_trace]
470 tti_window: DomRefCell<InteractiveWindow>,
471 canceller: FetchCanceller,
473 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
475 page_showing: Cell<bool>,
477 salvageable: Cell<bool>,
479 active_parser_was_aborted: Cell<bool>,
481 fired_unload: Cell<bool>,
483 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
485 redirect_count: Cell<u16>,
487 script_and_layout_blockers: Cell<u32>,
489 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
491 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
492 completely_loaded: Cell<bool>,
494 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
496 shadow_roots_styles_changed: Cell<bool>,
498 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
504 dirty_2d_contexts:
506 DomRefCell<HashMapTracedValues<CanvasId, Dom<CanvasRenderingContext2D>, FxBuildHasher>>,
507 dirty_webgl_contexts:
509 DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>, FxBuildHasher>>,
510 has_pending_animated_image_update: Cell<bool>,
512 #[cfg(feature = "webgpu")]
514 dirty_webgpu_contexts:
515 DomRefCell<HashMapTracedValues<WebGPUContextId, Dom<GPUCanvasContext>, FxBuildHasher>>,
516 selection: MutNullableDom<Selection>,
518 animation_timeline: DomRefCell<AnimationTimeline>,
521 animations: Animations,
523 image_animation_manager: DomRefCell<ImageAnimationManager>,
525 dirty_root: MutNullableDom<Element>,
527 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
529 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
538 fonts: MutNullableDom<FontFaceSet>,
541 visibility_state: Cell<DocumentVisibilityState>,
543 status_code: Option<u16>,
545 is_initial_about_blank: Cell<bool>,
547 allow_declarative_shadow_roots: Cell<bool>,
549 #[no_trace]
551 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
552 has_trustworthy_ancestor_origin: Cell<bool>,
554 intersection_observer_task_queued: Cell<bool>,
556 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
568 highlighted_dom_node: MutNullableDom<Node>,
570 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
573 #[ignore_malloc_size_of = "mozjs"]
575 adopted_stylesheets_frozen_types: CachedFrozenArray,
576 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
578 rendering_update_reasons: Cell<RenderingUpdateReason>,
580 waiting_on_canvas_image_updates: Cell<bool>,
584 #[no_trace]
592 current_rendering_epoch: Cell<Epoch>,
593 #[conditional_malloc_size_of]
595 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
596 #[no_trace]
597 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
599 #[no_trace]
600 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
607 #[no_trace]
609 #[ignore_malloc_size_of = "TODO: unimplemented on Image"]
610 favicon: RefCell<Option<Image>>,
611
612 websockets: DOMTracker<WebSocket>,
614}
615
616#[allow(non_snake_case)]
617impl Document {
618 fn unloading_cleanup_steps(&self) {
620 if self.close_outstanding_websockets() {
623 self.salvageable.set(false);
625 }
626
627 if !self.salvageable.get() {
632 let global_scope = self.window.as_global_scope();
633
634 global_scope.close_event_sources();
636
637 let msg = ScriptToConstellationMessage::DiscardDocument;
642 let _ = global_scope.script_to_constellation_chan().send(msg);
643 }
644 }
645
646 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
647 self.websockets.track(websocket);
648 }
649
650 fn close_outstanding_websockets(&self) -> bool {
651 let mut closed_any_websocket = false;
652 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
653 if websocket.make_disappear() {
654 closed_any_websocket = true;
655 }
656 });
657 closed_any_websocket
658 }
659
660 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
661 debug_assert!(*node.owner_doc() == *self);
662 if !node.is_connected() {
663 return;
664 }
665
666 let parent = match node.parent_in_flat_tree() {
667 Some(parent) => parent,
668 None => {
669 let document_element = match self.GetDocumentElement() {
672 Some(element) => element,
673 None => return,
674 };
675 if let Some(dirty_root) = self.dirty_root.get() {
676 for ancestor in dirty_root
679 .upcast::<Node>()
680 .inclusive_ancestors_in_flat_tree()
681 {
682 if ancestor.is::<Element>() {
683 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
684 }
685 }
686 }
687 self.dirty_root.set(Some(&document_element));
688 return;
689 },
690 };
691
692 if parent.is::<Element>() {
693 if !parent.is_styled() {
694 return;
695 }
696
697 if parent.is_display_none() {
698 return;
699 }
700 }
701
702 let element_parent: DomRoot<Element>;
703 let element = match node.downcast::<Element>() {
704 Some(element) => element,
705 None => {
706 match DomRoot::downcast::<Element>(parent) {
709 Some(parent) => {
710 element_parent = parent;
711 &element_parent
712 },
713 None => {
714 return;
718 },
719 }
720 },
721 };
722
723 let dirty_root = match self.dirty_root.get() {
724 None => {
725 element
726 .upcast::<Node>()
727 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
728 self.dirty_root.set(Some(element));
729 return;
730 },
731 Some(root) => root,
732 };
733
734 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
735 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
736 return;
737 }
738
739 if ancestor.is::<Element>() {
740 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
741 }
742 }
743
744 let new_dirty_root = element
745 .upcast::<Node>()
746 .common_ancestor_in_flat_tree(dirty_root.upcast())
747 .expect("Couldn't find common ancestor");
748
749 let mut has_dirty_descendants = true;
750 for ancestor in dirty_root
751 .upcast::<Node>()
752 .inclusive_ancestors_in_flat_tree()
753 {
754 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
755 has_dirty_descendants &= *ancestor != *new_dirty_root;
756 }
757
758 self.dirty_root
759 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
760 }
761
762 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
763 self.dirty_root.take()
764 }
765
766 #[inline]
767 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
768 self.loader.borrow()
769 }
770
771 #[inline]
772 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
773 self.loader.borrow_mut()
774 }
775
776 #[inline]
777 pub(crate) fn has_browsing_context(&self) -> bool {
778 self.has_browsing_context
779 }
780
781 #[inline]
783 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
784 if self.has_browsing_context {
785 self.window.undiscarded_window_proxy()
786 } else {
787 None
788 }
789 }
790
791 pub(crate) fn webview_id(&self) -> WebViewId {
792 self.window.webview_id()
793 }
794
795 #[inline]
796 pub(crate) fn window(&self) -> &Window {
797 &self.window
798 }
799
800 #[inline]
801 pub(crate) fn is_html_document(&self) -> bool {
802 self.is_html_document
803 }
804
805 pub(crate) fn is_xhtml_document(&self) -> bool {
806 self.content_type.matches(APPLICATION, "xhtml+xml")
807 }
808
809 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
810 self.https_state.set(https_state);
811 }
812
813 pub(crate) fn is_fully_active(&self) -> bool {
814 self.activity.get() == DocumentActivity::FullyActive
815 }
816
817 pub(crate) fn is_active(&self) -> bool {
818 self.activity.get() != DocumentActivity::Inactive
819 }
820
821 #[inline]
822 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
823 self.current_rendering_epoch.get()
824 }
825
826 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
827 assert!(self.has_browsing_context);
829 if activity == self.activity.get() {
830 return;
831 }
832
833 self.activity.set(activity);
835 let media = ServoMedia::get();
836 let pipeline_id = self.window().pipeline_id();
837 let client_context_id =
838 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
839
840 if activity != DocumentActivity::FullyActive {
841 self.window().suspend(can_gc);
842 media.suspend(&client_context_id);
843 return;
844 }
845
846 self.title_changed();
847 self.notify_embedder_favicon();
848 self.dirty_all_nodes();
849 self.window().resume(can_gc);
850 media.resume(&client_context_id);
851
852 if self.ready_state.get() != DocumentReadyState::Complete {
853 return;
854 }
855
856 let document = Trusted::new(self);
860 self.owner_global()
861 .task_manager()
862 .dom_manipulation_task_source()
863 .queue(task!(fire_pageshow_event: move || {
864 let document = document.root();
865 let window = document.window();
866 if document.page_showing.get() {
868 return;
869 }
870 document.page_showing.set(true);
872 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
874 let event = PageTransitionEvent::new(
877 window,
878 atom!("pageshow"),
879 false, false, true, CanGc::note(),
883 );
884 let event = event.upcast::<Event>();
885 event.set_trusted(true);
886 window.dispatch_event_with_target_override(event, CanGc::note());
887 }))
888 }
889
890 pub(crate) fn origin(&self) -> &MutableOrigin {
891 &self.origin
892 }
893
894 pub(crate) fn url(&self) -> ServoUrl {
896 self.url.borrow().clone()
897 }
898
899 pub(crate) fn set_url(&self, url: ServoUrl) {
900 *self.url.borrow_mut() = url;
901 }
902
903 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
905 let document_url = self.url();
907 if document_url.as_str() == "about:srcdoc" {
908 let base_url = self
909 .browsing_context()
910 .and_then(|browsing_context| browsing_context.creator_base_url());
911
912 if base_url.is_none() {
914 error!("about:srcdoc page should always have a creator base URL");
915 }
916
917 return base_url.unwrap_or(document_url);
919 }
920
921 if document_url.matches_about_blank() {
924 return self
925 .browsing_context()
926 .and_then(|browsing_context| browsing_context.creator_base_url())
927 .unwrap_or(document_url);
928 }
929
930 document_url
932 }
933
934 pub(crate) fn base_url(&self) -> ServoUrl {
936 match self.base_element() {
937 None => self.fallback_base_url(),
939 Some(base) => base.frozen_base_url(),
941 }
942 }
943
944 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
945 self.needs_restyle.set(self.needs_restyle.get() | reason)
946 }
947
948 pub(crate) fn clear_restyle_reasons(&self) {
949 self.needs_restyle.set(RestyleReason::empty());
950 }
951
952 pub(crate) fn restyle_reason(&self) -> RestyleReason {
953 let mut condition = self.needs_restyle.get();
954 if self.stylesheets.borrow().has_changed() {
955 condition.insert(RestyleReason::StylesheetsChanged);
956 }
957
958 if let Some(root) = self.GetDocumentElement() {
962 if root.upcast::<Node>().has_dirty_descendants() {
963 condition.insert(RestyleReason::DOMChanged);
964 }
965 }
966
967 if !self.pending_restyles.borrow().is_empty() {
968 condition.insert(RestyleReason::PendingRestyles);
969 }
970
971 condition
972 }
973
974 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
976 self.base_element.get()
977 }
978
979 pub(crate) fn refresh_base_element(&self) {
982 let base = self
983 .upcast::<Node>()
984 .traverse_preorder(ShadowIncluding::No)
985 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
986 .find(|element| {
987 element
988 .upcast::<Element>()
989 .has_attribute(&local_name!("href"))
990 });
991 self.base_element.set(base.as_deref());
992 }
993
994 pub(crate) fn dom_count(&self) -> u32 {
995 self.dom_count.get()
996 }
997
998 pub(crate) fn increment_dom_count(&self) {
1002 self.dom_count.set(self.dom_count.get() + 1);
1003 }
1004
1005 pub(crate) fn decrement_dom_count(&self) {
1007 self.dom_count.set(self.dom_count.get() - 1);
1008 }
1009
1010 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1011 self.quirks_mode.get()
1012 }
1013
1014 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1015 let old_mode = self.quirks_mode.replace(new_mode);
1016
1017 if old_mode != new_mode {
1018 self.window.layout_mut().set_quirks_mode(new_mode);
1019 }
1020 }
1021
1022 pub(crate) fn encoding(&self) -> &'static Encoding {
1023 self.encoding.get()
1024 }
1025
1026 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1027 self.encoding.set(encoding);
1028 }
1029
1030 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1031 if node.is_connected() {
1032 node.note_dirty_descendants();
1033 }
1034
1035 node.dirty(NodeDamage::ContentOrHeritage);
1038 }
1039
1040 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1042 self.document_or_shadow_root
1043 .unregister_named_element(&self.id_map, to_unregister, &id);
1044 self.reset_form_owner_for_listeners(&id, can_gc);
1045 }
1046
1047 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1049 let root = self.GetDocumentElement().expect(
1050 "The element is in the document, so there must be a document \
1051 element.",
1052 );
1053 self.document_or_shadow_root.register_named_element(
1054 &self.id_map,
1055 element,
1056 &id,
1057 DomRoot::from_ref(root.upcast::<Node>()),
1058 );
1059 self.reset_form_owner_for_listeners(&id, can_gc);
1060 }
1061
1062 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1064 self.document_or_shadow_root
1065 .unregister_named_element(&self.name_map, to_unregister, &name);
1066 }
1067
1068 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1070 let root = self.GetDocumentElement().expect(
1071 "The element is in the document, so there must be a document \
1072 element.",
1073 );
1074 self.document_or_shadow_root.register_named_element(
1075 &self.name_map,
1076 element,
1077 &name,
1078 DomRoot::from_ref(root.upcast::<Node>()),
1079 );
1080 }
1081
1082 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1083 &self,
1084 id: DOMString,
1085 listener: &T,
1086 ) {
1087 let mut map = self.form_id_listener_map.borrow_mut();
1088 let listener = listener.to_element();
1089 let set = map.entry(Atom::from(id)).or_default();
1090 set.insert(Dom::from_ref(listener));
1091 }
1092
1093 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1094 &self,
1095 id: DOMString,
1096 listener: &T,
1097 ) {
1098 let mut map = self.form_id_listener_map.borrow_mut();
1099 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1100 entry
1101 .get_mut()
1102 .remove(&Dom::from_ref(listener.to_element()));
1103 if entry.get().is_empty() {
1104 entry.remove();
1105 }
1106 }
1107 }
1108
1109 pub(crate) fn find_fragment_node(&self, fragid: &str) -> Option<DomRoot<Element>> {
1112 percent_decode(fragid.as_bytes())
1116 .decode_utf8()
1117 .ok()
1118 .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
1120 .or_else(|| self.get_anchor_by_name(fragid))
1122 }
1124
1125 pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) {
1129 let target = self.find_fragment_node(fragment);
1130
1131 self.set_target_element(target.as_deref());
1133
1134 let point = target
1135 .as_ref()
1136 .map(|element| {
1137 let rect = element.upcast::<Node>().border_box().unwrap_or_default();
1142
1143 let device_pixel_ratio = self.window.device_pixel_ratio().get();
1148 (
1149 rect.origin.x.to_nearest_pixel(device_pixel_ratio),
1150 rect.origin.y.to_nearest_pixel(device_pixel_ratio),
1151 )
1152 })
1153 .or_else(|| {
1154 if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
1155 Some((0.0, 0.0))
1158 } else {
1159 None
1160 }
1161 });
1162
1163 if let Some((x, y)) = point {
1164 self.window.scroll(x, y, ScrollBehavior::Instant)
1165 }
1166 }
1167
1168 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1169 let name = Atom::from(name);
1170 self.name_map.borrow().get(&name).and_then(|elements| {
1171 elements
1172 .iter()
1173 .find(|e| e.is::<HTMLAnchorElement>())
1174 .map(|e| DomRoot::from_ref(&**e))
1175 })
1176 }
1177
1178 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1180 match state {
1181 DocumentReadyState::Loading => {
1182 if self.window().is_top_level() {
1183 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1184 self.webview_id(),
1185 LoadStatus::Started,
1186 ));
1187 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1188 }
1189 },
1190 DocumentReadyState::Complete => {
1191 if self.window().is_top_level() {
1192 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1193 self.webview_id(),
1194 LoadStatus::Complete,
1195 ));
1196 }
1197 update_with_current_instant(&self.dom_complete);
1198 },
1199 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1200 };
1201
1202 self.ready_state.set(state);
1203
1204 self.upcast::<EventTarget>()
1205 .fire_event(atom!("readystatechange"), can_gc);
1206 }
1207
1208 pub(crate) fn scripting_enabled(&self) -> bool {
1211 self.has_browsing_context() &&
1214 !self.has_active_sandboxing_flag(
1218 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1219 )
1220 }
1221
1222 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1225 self.focused.get()
1226 }
1227
1228 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1233 self.focus_sequence.get()
1234 }
1235
1236 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1238 self.focus_sequence.set(FocusSequenceNumber(
1239 self.focus_sequence
1240 .get()
1241 .0
1242 .checked_add(1)
1243 .expect("too many focus messages have been sent"),
1244 ));
1245 self.focus_sequence.get()
1246 }
1247
1248 pub(crate) fn has_focus_transaction(&self) -> bool {
1249 self.focus_transaction.borrow().is_some()
1250 }
1251
1252 pub(crate) fn begin_focus_transaction(&self) {
1255 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1257 element: self.focused.get().as_deref().map(Dom::from_ref),
1258 has_focus: self.has_focus.get(),
1259 focus_options: FocusOptions {
1260 preventScroll: true,
1261 },
1262 });
1263 }
1264
1265 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1267 if Some(not_focusable) != self.focused.get().as_deref() {
1270 return;
1271 }
1272
1273 let implicit_transaction = self.focus_transaction.borrow().is_none();
1274
1275 if implicit_transaction {
1276 self.begin_focus_transaction();
1277 }
1278
1279 {
1282 let mut focus_transaction = self.focus_transaction.borrow_mut();
1283 focus_transaction.as_mut().unwrap().element = None;
1284 }
1285
1286 if implicit_transaction {
1287 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1288 }
1289 }
1290
1291 pub(crate) fn request_focus(
1294 &self,
1295 elem: Option<&Element>,
1296 focus_initiator: FocusInitiator,
1297 can_gc: CanGc,
1298 ) {
1299 self.request_focus_with_options(
1300 elem,
1301 focus_initiator,
1302 FocusOptions {
1303 preventScroll: true,
1304 },
1305 can_gc,
1306 );
1307 }
1308
1309 pub(crate) fn request_focus_with_options(
1315 &self,
1316 elem: Option<&Element>,
1317 focus_initiator: FocusInitiator,
1318 focus_options: FocusOptions,
1319 can_gc: CanGc,
1320 ) {
1321 if elem.is_some_and(|e| !e.is_focusable_area()) {
1324 return;
1325 }
1326
1327 let implicit_transaction = self.focus_transaction.borrow().is_none();
1328
1329 if implicit_transaction {
1330 self.begin_focus_transaction();
1331 }
1332
1333 {
1334 let mut focus_transaction = self.focus_transaction.borrow_mut();
1335 let focus_transaction = focus_transaction.as_mut().unwrap();
1336 focus_transaction.element = elem.map(Dom::from_ref);
1337 focus_transaction.has_focus = true;
1338 focus_transaction.focus_options = focus_options;
1339 }
1340
1341 if implicit_transaction {
1342 self.commit_focus_transaction(focus_initiator, can_gc);
1343 }
1344 }
1345
1346 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1350 if self.window().parent_info().is_none() {
1351 warn!("Top-level document cannot be unfocused");
1352 return;
1353 }
1354
1355 assert!(
1358 self.focus_transaction.borrow().is_none(),
1359 "there mustn't be an in-progress focus transaction at this point"
1360 );
1361
1362 self.begin_focus_transaction();
1364
1365 {
1367 let mut focus_transaction = self.focus_transaction.borrow_mut();
1368 focus_transaction.as_mut().unwrap().has_focus = false;
1369 }
1370
1371 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1373 }
1374
1375 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1378 let (mut new_focused, new_focus_state, prevent_scroll) = {
1379 let focus_transaction = self.focus_transaction.borrow();
1380 let focus_transaction = focus_transaction
1381 .as_ref()
1382 .expect("no focus transaction in progress");
1383 (
1384 focus_transaction
1385 .element
1386 .as_ref()
1387 .map(|e| DomRoot::from_ref(&**e)),
1388 focus_transaction.has_focus,
1389 focus_transaction.focus_options.preventScroll,
1390 )
1391 };
1392 *self.focus_transaction.borrow_mut() = None;
1393
1394 if !new_focus_state {
1395 if new_focused.take().is_some() {
1398 trace!(
1399 "Forgetting the document's focused area because the \
1400 document's container was removed from the top-level BC's \
1401 focus chain"
1402 );
1403 }
1404 }
1405
1406 let old_focused = self.focused.get();
1407 let old_focus_state = self.has_focus.get();
1408
1409 debug!(
1410 "Committing focus transaction: {:?} → {:?}",
1411 (&old_focused, old_focus_state),
1412 (&new_focused, new_focus_state),
1413 );
1414
1415 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1418 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1419
1420 let trace_focus_chain = |name, element, doc| {
1421 trace!(
1422 "{} local focus chain: {}",
1423 name,
1424 match (element, doc) {
1425 (Some(e), _) => format!("[{:?}, document]", e),
1426 (None, true) => "[document]".to_owned(),
1427 (None, false) => "[]".to_owned(),
1428 }
1429 );
1430 };
1431
1432 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1433 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1434
1435 if old_focused_filtered != new_focused_filtered {
1436 if let Some(elem) = &old_focused_filtered {
1437 let node = elem.upcast::<Node>();
1438 elem.set_focus_state(false);
1439 if node.is_connected() {
1441 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1442 }
1443 }
1444 }
1445
1446 if old_focus_state != new_focus_state && !new_focus_state {
1447 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1448 }
1449
1450 self.focused.set(new_focused.as_deref());
1451 self.has_focus.set(new_focus_state);
1452
1453 if old_focus_state != new_focus_state && new_focus_state {
1454 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1455 }
1456
1457 if old_focused_filtered != new_focused_filtered {
1458 if let Some(elem) = &new_focused_filtered {
1459 elem.set_focus_state(true);
1460 let node = elem.upcast::<Node>();
1461 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1463
1464 if !prevent_scroll {
1468 elem.ScrollIntoView(BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(
1469 ScrollIntoViewOptions {
1470 parent: ScrollOptions {
1471 behavior: ScrollBehavior::Smooth,
1472 },
1473 block: ScrollLogicalPosition::Center,
1474 inline: ScrollLogicalPosition::Center,
1475 container: ScrollIntoViewContainer::All,
1476 },
1477 ));
1478 }
1479 }
1480 }
1481
1482 if focus_initiator != FocusInitiator::Local {
1483 return;
1484 }
1485
1486 match (old_focus_state, new_focus_state) {
1489 (_, true) => {
1490 let child_browsing_context_id = new_focused
1511 .as_ref()
1512 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1513 .and_then(|iframe| iframe.browsing_context_id());
1514
1515 let sequence = self.increment_fetch_focus_sequence();
1516
1517 debug!(
1518 "Advertising the focus request to the constellation \
1519 with sequence number {} and child BC ID {}",
1520 sequence,
1521 child_browsing_context_id
1522 .as_ref()
1523 .map(|id| id as &dyn std::fmt::Display)
1524 .unwrap_or(&"(none)"),
1525 );
1526
1527 self.window()
1528 .send_to_constellation(ScriptToConstellationMessage::Focus(
1529 child_browsing_context_id,
1530 sequence,
1531 ));
1532 },
1533 (false, false) => {
1534 },
1537 (true, false) => {
1538 unreachable!(
1539 "Can't lose the document's focus without specifying \
1540 another one to focus"
1541 );
1542 },
1543 }
1544 }
1545
1546 pub(crate) fn title_changed(&self) {
1548 if self.browsing_context().is_some() {
1549 self.send_title_to_embedder();
1550 let title = String::from(self.Title());
1551 self.window
1552 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1553 self.window.pipeline_id(),
1554 title.clone(),
1555 ));
1556 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1557 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1558 self.window.pipeline_id(),
1559 title,
1560 ));
1561 }
1562 }
1563 }
1564
1565 fn title(&self) -> Option<DOMString> {
1569 let title = self.GetDocumentElement().and_then(|root| {
1570 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1571 root.upcast::<Node>()
1573 .child_elements()
1574 .find(|node| {
1575 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1576 })
1577 .map(DomRoot::upcast::<Node>)
1578 } else {
1579 root.upcast::<Node>()
1581 .traverse_preorder(ShadowIncluding::No)
1582 .find(|node| node.is::<HTMLTitleElement>())
1583 }
1584 });
1585
1586 title.map(|title| {
1587 let value = title.child_text_content();
1589 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1590 })
1591 }
1592
1593 pub(crate) fn send_title_to_embedder(&self) {
1595 let window = self.window();
1596 if window.is_top_level() {
1597 let title = self.title().map(String::from);
1598 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1599 }
1600 }
1601
1602 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1603 let window = self.window();
1604 window.send_to_embedder(msg);
1605 }
1606
1607 pub(crate) fn dirty_all_nodes(&self) {
1608 let root = match self.GetDocumentElement() {
1609 Some(root) => root,
1610 None => return,
1611 };
1612 for node in root
1613 .upcast::<Node>()
1614 .traverse_preorder(ShadowIncluding::Yes)
1615 {
1616 node.dirty(NodeDamage::Other)
1617 }
1618 }
1619
1620 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1622 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1634 for target in notify_list.iter() {
1635 if target.downcast::<Document>().is_some() {
1636 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1639 } else if target.downcast::<Element>().is_some() {
1640 target.fire_event(Atom::from("scroll"), can_gc);
1643 }
1644 }
1645
1646 }
1650
1651 pub(crate) fn handle_viewport_scroll_event(&self) {
1655 let target = self.upcast::<EventTarget>();
1664 if self
1665 .pending_scroll_event_targets
1666 .borrow()
1667 .iter()
1668 .any(|other_target| *other_target == target)
1669 {
1670 return;
1671 }
1672
1673 self.pending_scroll_event_targets
1676 .borrow_mut()
1677 .push(Dom::from_ref(target));
1678 }
1679
1680 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1684 let target = element.upcast::<EventTarget>();
1694 if self
1695 .pending_scroll_event_targets
1696 .borrow()
1697 .iter()
1698 .any(|other_target| *other_target == target)
1699 {
1700 return;
1701 }
1702
1703 self.pending_scroll_event_targets
1706 .borrow_mut()
1707 .push(Dom::from_ref(target));
1708 }
1709
1710 pub(crate) fn node_from_nodes_and_strings(
1712 &self,
1713 mut nodes: Vec<NodeOrString>,
1714 can_gc: CanGc,
1715 ) -> Fallible<DomRoot<Node>> {
1716 if nodes.len() == 1 {
1717 Ok(match nodes.pop().unwrap() {
1718 NodeOrString::Node(node) => node,
1719 NodeOrString::String(string) => {
1720 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1721 },
1722 })
1723 } else {
1724 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1725 for node in nodes {
1726 match node {
1727 NodeOrString::Node(node) => {
1728 fragment.AppendChild(&node, can_gc)?;
1729 },
1730 NodeOrString::String(string) => {
1731 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1732 fragment.AppendChild(&node, can_gc).unwrap();
1735 },
1736 }
1737 }
1738 Ok(fragment)
1739 }
1740 }
1741
1742 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1743 match self.GetBody() {
1744 Some(ref body) if body.is_body_element() => {
1745 body.upcast::<Element>().get_string_attribute(local_name)
1746 },
1747 _ => DOMString::new(),
1748 }
1749 }
1750
1751 pub(crate) fn set_body_attribute(
1752 &self,
1753 local_name: &LocalName,
1754 value: DOMString,
1755 can_gc: CanGc,
1756 ) {
1757 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1758 let body = body.upcast::<Element>();
1759 let value = body.parse_attribute(&ns!(), local_name, value);
1760 body.set_attribute(local_name, value, can_gc);
1761 }
1762 }
1763
1764 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1765 self.current_script.set(script);
1766 }
1767
1768 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1769 self.script_blocking_stylesheets_count.get()
1770 }
1771
1772 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1773 let count_cell = &self.script_blocking_stylesheets_count;
1774 count_cell.set(count_cell.get() + 1);
1775 }
1776
1777 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1778 let count_cell = &self.script_blocking_stylesheets_count;
1779 assert!(count_cell.get() > 0);
1780 count_cell.set(count_cell.get() - 1);
1781 }
1782
1783 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1784 self.render_blocking_element_count.get()
1785 }
1786
1787 pub(crate) fn increment_render_blocking_element_count(&self) {
1788 let count_cell = &self.render_blocking_element_count;
1789 count_cell.set(count_cell.get() + 1);
1790 }
1791
1792 pub(crate) fn decrement_render_blocking_element_count(&self) {
1793 let count_cell = &self.render_blocking_element_count;
1794 assert!(count_cell.get() > 0);
1795 count_cell.set(count_cell.get() - 1);
1796 }
1797
1798 pub(crate) fn invalidate_stylesheets(&self) {
1799 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1800
1801 if let Some(element) = self.GetDocumentElement() {
1805 element.upcast::<Node>().dirty(NodeDamage::Style);
1806 }
1807 }
1808
1809 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1812 !self.animation_frame_list.borrow().is_empty()
1813 }
1814
1815 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1817 let ident = self.animation_frame_ident.get() + 1;
1818 self.animation_frame_ident.set(ident);
1819
1820 let had_animation_frame_callbacks;
1821 {
1822 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1823 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1824 animation_frame_list.push_back((ident, Some(callback)));
1825 }
1826
1827 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1833 self.window().send_to_constellation(
1834 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1835 AnimationState::AnimationCallbacksPresent,
1836 ),
1837 );
1838 }
1839
1840 ident
1841 }
1842
1843 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1845 let mut list = self.animation_frame_list.borrow_mut();
1846 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1847 pair.1 = None;
1848 }
1849 }
1850
1851 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1853 let _realm = enter_realm(self);
1854
1855 self.running_animation_callbacks.set(true);
1856 let timing = self.global().performance().Now();
1857
1858 let num_callbacks = self.animation_frame_list.borrow().len();
1859 for _ in 0..num_callbacks {
1860 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1861 if let Some(callback) = maybe_callback {
1862 callback.call(self, *timing, can_gc);
1863 }
1864 }
1865 self.running_animation_callbacks.set(false);
1866
1867 if self.animation_frame_list.borrow().is_empty() {
1868 self.window().send_to_constellation(
1869 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1870 AnimationState::NoAnimationCallbacksPresent,
1871 ),
1872 );
1873 }
1874 }
1875
1876 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1877 self.policy_container.borrow()
1878 }
1879
1880 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1881 *self.policy_container.borrow_mut() = policy_container;
1882 }
1883
1884 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1885 self.policy_container.borrow_mut().set_csp_list(csp_list);
1886 }
1887
1888 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1889 self.policy_container.borrow().csp_list.clone()
1890 }
1891
1892 pub(crate) fn preloaded_resources(&self) -> PreloadedResources {
1893 self.preloaded_resources.clone()
1894 }
1895
1896 pub(crate) fn prepare_request(&self, request: RequestBuilder) -> RequestBuilder {
1900 request
1901 .policy_container(self.policy_container().to_owned())
1902 .https_state(self.https_state.get())
1903 }
1904
1905 pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1906 &self,
1907 load: LoadType,
1908 mut request: RequestBuilder,
1909 listener: Listener,
1910 ) {
1911 request = request
1912 .insecure_requests_policy(self.insecure_requests_policy())
1913 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1914 let callback = NetworkListener {
1915 context: std::sync::Arc::new(Mutex::new(listener)),
1916 task_source: self
1917 .owner_global()
1918 .task_manager()
1919 .networking_task_source()
1920 .into(),
1921 }
1922 .into_callback();
1923 self.loader_mut()
1924 .fetch_async_with_callback(load, request, callback);
1925 }
1926
1927 pub(crate) fn fetch_background<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1928 &self,
1929 mut request: RequestBuilder,
1930 listener: Listener,
1931 ) {
1932 request = request
1933 .insecure_requests_policy(self.insecure_requests_policy())
1934 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1935 let callback = NetworkListener {
1936 context: std::sync::Arc::new(Mutex::new(listener)),
1937 task_source: self
1938 .owner_global()
1939 .task_manager()
1940 .networking_task_source()
1941 .into(),
1942 }
1943 .into_callback();
1944 self.loader_mut().fetch_async_background(request, callback);
1945 }
1946
1947 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
1950 debug!("Document got finish_load: {:?}", load);
1952 self.loader.borrow_mut().finish_load(&load);
1953
1954 match load {
1955 LoadType::Stylesheet(_) => {
1956 self.process_pending_parsing_blocking_script(can_gc);
1959
1960 self.process_deferred_scripts(can_gc);
1962 },
1963 LoadType::PageSource(_) => {
1964 if self.has_browsing_context && self.is_fully_active() {
1967 self.window().allow_layout_if_necessary();
1968 }
1969
1970 self.process_deferred_scripts(can_gc);
1975 },
1976 _ => {},
1977 }
1978
1979 let loader = self.loader.borrow();
1986
1987 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1989 update_with_current_instant(&self.top_level_dom_complete);
1990 }
1991
1992 if loader.is_blocked() || loader.events_inhibited() {
1993 return;
1995 }
1996
1997 ScriptThread::mark_document_with_no_blocked_loads(self);
1998 }
1999
2000 pub(crate) fn prompt_to_unload(&self, recursive_flag: bool, can_gc: CanGc) -> bool {
2002 self.incr_ignore_opens_during_unload_counter();
2005 let beforeunload_event = BeforeUnloadEvent::new(
2007 &self.window,
2008 atom!("beforeunload"),
2009 EventBubbles::Bubbles,
2010 EventCancelable::Cancelable,
2011 can_gc,
2012 );
2013 let event = beforeunload_event.upcast::<Event>();
2014 event.set_trusted(true);
2015 let event_target = self.window.upcast::<EventTarget>();
2016 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2017 self.window
2018 .dispatch_event_with_target_override(event, can_gc);
2019 if has_listeners {
2022 self.salvageable.set(false);
2023 }
2024 let mut can_unload = true;
2025 let default_prevented = event.DefaultPrevented();
2027 let return_value_not_empty = !event
2028 .downcast::<BeforeUnloadEvent>()
2029 .unwrap()
2030 .ReturnValue()
2031 .is_empty();
2032 if default_prevented || return_value_not_empty {
2033 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2034 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2035 self.send_to_embedder(msg);
2036 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2037 }
2038 if !recursive_flag {
2040 let iframes: Vec<_> = self.iframes().iter().collect();
2043 for iframe in &iframes {
2044 let document = iframe.owner_document();
2046 can_unload = document.prompt_to_unload(true, can_gc);
2047 if !document.salvageable() {
2048 self.salvageable.set(false);
2049 }
2050 if !can_unload {
2051 break;
2052 }
2053 }
2054 }
2055 self.decr_ignore_opens_during_unload_counter();
2057 can_unload
2058 }
2059
2060 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2062 self.incr_ignore_opens_during_unload_counter();
2065 if self.page_showing.get() {
2067 self.page_showing.set(false);
2069 let event = PageTransitionEvent::new(
2072 &self.window,
2073 atom!("pagehide"),
2074 false, false, self.salvageable.get(), can_gc,
2078 );
2079 let event = event.upcast::<Event>();
2080 event.set_trusted(true);
2081 self.window
2082 .dispatch_event_with_target_override(event, can_gc);
2083 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2085 }
2086 if !self.fired_unload.get() {
2088 let event = Event::new(
2089 self.window.upcast(),
2090 atom!("unload"),
2091 EventBubbles::Bubbles,
2092 EventCancelable::Cancelable,
2093 can_gc,
2094 );
2095 event.set_trusted(true);
2096 let event_target = self.window.upcast::<EventTarget>();
2097 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2098 self.window
2099 .dispatch_event_with_target_override(&event, can_gc);
2100 self.fired_unload.set(true);
2101 if has_listeners {
2103 self.salvageable.set(false);
2104 }
2105 }
2106 if !recursive_flag {
2110 let iframes: Vec<_> = self.iframes().iter().collect();
2113 for iframe in &iframes {
2114 let document = iframe.owner_document();
2116 document.unload(true, can_gc);
2117 if !document.salvageable() {
2118 self.salvageable.set(false);
2119 }
2120 }
2121 }
2122
2123 self.unloading_cleanup_steps();
2125
2126 self.window.as_global_scope().clean_up_all_file_resources();
2128
2129 self.decr_ignore_opens_during_unload_counter();
2131 }
2132
2133 pub(crate) fn maybe_queue_document_completion(&self) {
2135 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2137 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2138 None => false,
2139 };
2140
2141 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2146 !self.is_fully_active() ||
2147 is_in_delaying_load_events_mode;
2148
2149 if not_ready_for_load {
2150 return;
2152 }
2153
2154 assert!(!self.loader.borrow().events_inhibited());
2155 self.loader.borrow_mut().inhibit_events();
2156
2157 debug!("Document loads are complete.");
2160 let document = Trusted::new(self);
2161 self.owner_global()
2162 .task_manager()
2163 .dom_manipulation_task_source()
2164 .queue(task!(fire_load_event: move || {
2165 let document = document.root();
2166 let window = document.window();
2167 if !window.is_alive() {
2168 return;
2169 }
2170
2171 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2173
2174 if document.browsing_context().is_none() {
2176 return;
2177 }
2178 let event = Event::new(
2179 window.upcast(),
2180 atom!("load"),
2181 EventBubbles::DoesNotBubble,
2182 EventCancelable::NotCancelable,
2183 CanGc::note(),
2184 );
2185 event.set_trusted(true);
2186
2187 update_with_current_instant(&document.load_event_start);
2189
2190 debug!("About to dispatch load for {:?}", document.url());
2191 window.dispatch_event_with_target_override(&event, CanGc::note());
2192
2193 update_with_current_instant(&document.load_event_end);
2195
2196 if let Some(fragment) = document.url().fragment() {
2197 document.check_and_scroll_fragment(fragment);
2198 }
2199 }));
2200
2201 let document = Trusted::new(self);
2203 if document.root().browsing_context().is_some() {
2204 self.owner_global()
2205 .task_manager()
2206 .dom_manipulation_task_source()
2207 .queue(task!(fire_pageshow_event: move || {
2208 let document = document.root();
2209 let window = document.window();
2210 if document.page_showing.get() || !window.is_alive() {
2211 return;
2212 }
2213
2214 document.page_showing.set(true);
2215
2216 let event = PageTransitionEvent::new(
2217 window,
2218 atom!("pageshow"),
2219 false, false, false, CanGc::note(),
2223 );
2224 let event = event.upcast::<Event>();
2225 event.set_trusted(true);
2226
2227 window.dispatch_event_with_target_override(event, CanGc::note());
2228 }));
2229 }
2230
2231 #[cfg(feature = "webxr")]
2246 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2247 self.window.Navigator().Xr().dispatch_sessionavailable();
2248 }
2249
2250 let document = Trusted::new(self);
2254 if document.root().browsing_context().is_some() {
2255 self.owner_global()
2256 .task_manager()
2257 .dom_manipulation_task_source()
2258 .queue(task!(completely_loaded: move || {
2259 let document = document.root();
2260 document.completely_loaded.set(true);
2261 if let Some(DeclarativeRefresh::PendingLoad {
2262 url,
2263 time
2264 }) = &*document.declarative_refresh.borrow() {
2265 document.window.as_global_scope().schedule_callback(
2267 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2268 window: DomRoot::from_ref(document.window()),
2269 url: url.clone(),
2270 }),
2271 Duration::from_secs(*time),
2272 );
2273 }
2274 document.notify_constellation_load();
2277 }));
2278 }
2279 }
2280
2281 pub(crate) fn completely_loaded(&self) -> bool {
2282 self.completely_loaded.get()
2283 }
2284
2285 pub(crate) fn set_pending_parsing_blocking_script(
2287 &self,
2288 script: &HTMLScriptElement,
2289 load: Option<ScriptResult>,
2290 ) {
2291 assert!(!self.has_pending_parsing_blocking_script());
2292 *self.pending_parsing_blocking_script.borrow_mut() =
2293 Some(PendingScript::new_with_load(script, load));
2294 }
2295
2296 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2298 self.pending_parsing_blocking_script.borrow().is_some()
2299 }
2300
2301 pub(crate) fn pending_parsing_blocking_script_loaded(
2303 &self,
2304 element: &HTMLScriptElement,
2305 result: ScriptResult,
2306 can_gc: CanGc,
2307 ) {
2308 {
2309 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2310 let entry = blocking_script.as_mut().unwrap();
2311 assert!(&*entry.element == element);
2312 entry.loaded(result);
2313 }
2314 self.process_pending_parsing_blocking_script(can_gc);
2315 }
2316
2317 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2318 if self.script_blocking_stylesheets_count.get() > 0 {
2319 return;
2320 }
2321 let pair = self
2322 .pending_parsing_blocking_script
2323 .borrow_mut()
2324 .as_mut()
2325 .and_then(PendingScript::take_result);
2326 if let Some((element, result)) = pair {
2327 *self.pending_parsing_blocking_script.borrow_mut() = None;
2328 self.get_current_parser()
2329 .unwrap()
2330 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2331 }
2332 }
2333
2334 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2336 self.asap_scripts_set
2337 .borrow_mut()
2338 .push(Dom::from_ref(script));
2339 }
2340
2341 pub(crate) fn asap_script_loaded(
2344 &self,
2345 element: &HTMLScriptElement,
2346 result: ScriptResult,
2347 can_gc: CanGc,
2348 ) {
2349 {
2350 let mut scripts = self.asap_scripts_set.borrow_mut();
2351 let idx = scripts
2352 .iter()
2353 .position(|entry| &**entry == element)
2354 .unwrap();
2355 scripts.swap_remove(idx);
2356 }
2357 element.execute(result, can_gc);
2358 }
2359
2360 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2362 self.asap_in_order_scripts_list.push(script);
2363 }
2364
2365 pub(crate) fn asap_in_order_script_loaded(
2368 &self,
2369 element: &HTMLScriptElement,
2370 result: ScriptResult,
2371 can_gc: CanGc,
2372 ) {
2373 self.asap_in_order_scripts_list.loaded(element, result);
2374 while let Some((element, result)) = self
2375 .asap_in_order_scripts_list
2376 .take_next_ready_to_be_executed()
2377 {
2378 element.execute(result, can_gc);
2379 }
2380 }
2381
2382 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2384 self.deferred_scripts.push(script);
2385 }
2386
2387 pub(crate) fn deferred_script_loaded(
2390 &self,
2391 element: &HTMLScriptElement,
2392 result: ScriptResult,
2393 can_gc: CanGc,
2394 ) {
2395 self.deferred_scripts.loaded(element, result);
2396 self.process_deferred_scripts(can_gc);
2397 }
2398
2399 fn process_deferred_scripts(&self, can_gc: CanGc) {
2401 if self.ready_state.get() != DocumentReadyState::Interactive {
2402 return;
2403 }
2404 loop {
2406 if self.script_blocking_stylesheets_count.get() > 0 {
2407 return;
2408 }
2409 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2410 {
2411 element.execute(result, can_gc);
2412 } else {
2413 break;
2414 }
2415 }
2416 if self.deferred_scripts.is_empty() {
2417 self.maybe_dispatch_dom_content_loaded();
2419 }
2420 }
2421
2422 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2424 if self.domcontentloaded_dispatched.get() {
2425 return;
2426 }
2427 self.domcontentloaded_dispatched.set(true);
2428 assert_ne!(
2429 self.ReadyState(),
2430 DocumentReadyState::Complete,
2431 "Complete before DOMContentLoaded?"
2432 );
2433
2434 update_with_current_instant(&self.dom_content_loaded_event_start);
2435
2436 let document = Trusted::new(self);
2438 self.owner_global()
2439 .task_manager()
2440 .dom_manipulation_task_source()
2441 .queue(
2442 task!(fire_dom_content_loaded_event: move || {
2443 let document = document.root();
2444 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2445 update_with_current_instant(&document.dom_content_loaded_event_end);
2446 })
2447 );
2448
2449 self.interactive_time
2451 .borrow()
2452 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2453
2454 }
2457
2458 pub(crate) fn abort(&self, can_gc: CanGc) {
2460 self.loader.borrow_mut().inhibit_events();
2462
2463 for iframe in self.iframes().iter() {
2465 if let Some(document) = iframe.GetContentDocument() {
2466 document.abort(can_gc);
2468 }
2470 }
2471
2472 self.script_blocking_stylesheets_count.set(0);
2474 *self.pending_parsing_blocking_script.borrow_mut() = None;
2475 *self.asap_scripts_set.borrow_mut() = vec![];
2476 self.asap_in_order_scripts_list.clear();
2477 self.deferred_scripts.clear();
2478 let loads_cancelled = self.loader.borrow_mut().cancel_all_loads();
2479 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2480 if loads_cancelled || event_sources_canceled {
2481 self.salvageable.set(false);
2483 };
2484
2485 self.owner_global()
2490 .task_manager()
2491 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2492
2493 if let Some(parser) = self.get_current_parser() {
2495 self.active_parser_was_aborted.set(true);
2496 parser.abort(can_gc);
2497 self.salvageable.set(false);
2498 }
2499 }
2500
2501 pub(crate) fn notify_constellation_load(&self) {
2502 self.window()
2503 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2504 }
2505
2506 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2507 self.current_parser.set(script);
2508 }
2509
2510 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2511 self.current_parser.get()
2512 }
2513
2514 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2517 self.iframes.borrow_mut().validate(self);
2518 self.iframes.borrow()
2519 }
2520
2521 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2524 self.iframes.borrow_mut().validate(self);
2525 self.iframes.borrow_mut()
2526 }
2527
2528 pub(crate) fn invalidate_iframes_collection(&self) {
2529 self.iframes.borrow_mut().invalidate();
2530 }
2531
2532 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2533 self.dom_interactive.get()
2534 }
2535
2536 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2537 self.interactive_time
2538 .borrow_mut()
2539 .set_navigation_start(navigation_start);
2540 }
2541
2542 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2543 self.interactive_time.borrow()
2544 }
2545
2546 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2547 self.get_interactive_metrics().get_tti().is_some()
2548 }
2549
2550 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2551 self.dom_content_loaded_event_start.get()
2552 }
2553
2554 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2555 self.dom_content_loaded_event_end.get()
2556 }
2557
2558 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2559 self.dom_complete.get()
2560 }
2561
2562 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2563 self.top_level_dom_complete.get()
2564 }
2565
2566 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2567 self.load_event_start.get()
2568 }
2569
2570 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2571 self.load_event_end.get()
2572 }
2573
2574 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2575 self.unload_event_start.get()
2576 }
2577
2578 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2579 self.unload_event_end.get()
2580 }
2581
2582 pub(crate) fn start_tti(&self) {
2583 if self.get_interactive_metrics().needs_tti() {
2584 self.tti_window.borrow_mut().start_window();
2585 }
2586 }
2587
2588 pub(crate) fn record_tti_if_necessary(&self) {
2592 if self.has_recorded_tti_metric() {
2593 return;
2594 }
2595 if self.tti_window.borrow().needs_check() {
2596 self.get_interactive_metrics()
2597 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2598 self.tti_window.borrow().get_start(),
2599 ));
2600 }
2601 }
2602
2603 fn fire_focus_event(
2605 &self,
2606 focus_event_type: FocusEventType,
2607 event_target: &EventTarget,
2608 related_target: Option<&EventTarget>,
2609 can_gc: CanGc,
2610 ) {
2611 let (event_name, does_bubble) = match focus_event_type {
2612 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2613 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2614 };
2615 let event = FocusEvent::new(
2616 &self.window,
2617 event_name,
2618 does_bubble,
2619 EventCancelable::NotCancelable,
2620 Some(&self.window),
2621 0i32,
2622 related_target,
2623 can_gc,
2624 );
2625 let event = event.upcast::<Event>();
2626 event.set_trusted(true);
2627 event.fire(event_target, can_gc);
2628 }
2629
2630 pub(crate) fn is_cookie_averse(&self) -> bool {
2632 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2633 }
2634
2635 pub(crate) fn lookup_custom_element_definition(
2637 &self,
2638 namespace: &Namespace,
2639 local_name: &LocalName,
2640 is: Option<&LocalName>,
2641 ) -> Option<Rc<CustomElementDefinition>> {
2642 if !pref!(dom_customelements_enabled) {
2643 return None;
2644 }
2645
2646 if *namespace != ns!(html) {
2648 return None;
2649 }
2650
2651 if !self.has_browsing_context {
2653 return None;
2654 }
2655
2656 let registry = self.window.CustomElements();
2658
2659 registry.lookup_definition(local_name, is)
2660 }
2661
2662 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2663 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2664 self.throw_on_dynamic_markup_insertion_counter
2665 .set(counter + 1);
2666 }
2667
2668 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2669 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2670 self.throw_on_dynamic_markup_insertion_counter
2671 .set(counter - 1);
2672 }
2673
2674 pub(crate) fn react_to_environment_changes(&self) {
2675 for image in self.responsive_images.borrow().iter() {
2676 image.react_to_environment_changes();
2677 }
2678 }
2679
2680 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2681 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2682 }
2683
2684 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2685 let index = self
2686 .responsive_images
2687 .borrow()
2688 .iter()
2689 .position(|x| **x == *img);
2690 if let Some(i) = index {
2691 self.responsive_images.borrow_mut().remove(i);
2692 }
2693 }
2694
2695 pub(crate) fn register_media_controls(&self, controls: &ShadowRoot) -> String {
2696 let id = Uuid::new_v4().to_string();
2697 self.media_controls
2698 .borrow_mut()
2699 .insert(id.clone(), Dom::from_ref(controls));
2700 id
2701 }
2702
2703 pub(crate) fn unregister_media_controls(&self, id: &str) {
2704 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2705 debug_assert!(
2706 did_have_these_media_controls,
2707 "Trying to unregister unknown media controls"
2708 );
2709 }
2710
2711 pub(crate) fn add_dirty_webgl_canvas(&self, context: &WebGLRenderingContext) {
2712 self.dirty_webgl_contexts
2713 .borrow_mut()
2714 .entry(context.context_id())
2715 .or_insert_with(|| Dom::from_ref(context));
2716 }
2717
2718 pub(crate) fn add_dirty_2d_canvas(&self, context: &CanvasRenderingContext2D) {
2719 self.dirty_2d_contexts
2720 .borrow_mut()
2721 .entry(context.context_id())
2722 .or_insert_with(|| Dom::from_ref(context));
2723 }
2724
2725 #[cfg(feature = "webgpu")]
2726 pub(crate) fn add_dirty_webgpu_context(&self, context: &GPUCanvasContext) {
2727 self.dirty_webgpu_contexts
2728 .borrow_mut()
2729 .entry(context.context_id())
2730 .or_insert_with(|| Dom::from_ref(context));
2731 }
2732
2733 pub(crate) fn needs_rendering_update(&self) -> bool {
2737 if !self.is_fully_active() {
2738 return false;
2739 }
2740 if !self.window().layout_blocked() &&
2741 (!self.restyle_reason().is_empty() ||
2742 self.window().layout().needs_new_display_list())
2743 {
2744 return true;
2745 }
2746 if !self.rendering_update_reasons.get().is_empty() {
2747 return true;
2748 }
2749 if self.event_handler.has_pending_input_events() {
2750 return true;
2751 }
2752 if self.has_pending_scroll_events() {
2753 return true;
2754 }
2755 if self.window().has_unhandled_resize_event() {
2756 return true;
2757 }
2758 if self.has_pending_animated_image_update.get() ||
2759 !self.dirty_2d_contexts.borrow().is_empty() ||
2760 !self.dirty_webgl_contexts.borrow().is_empty()
2761 {
2762 return true;
2763 }
2764
2765 #[cfg(feature = "webgpu")]
2766 if !self.dirty_webgpu_contexts.borrow().is_empty() {
2767 return true;
2768 }
2769
2770 false
2771 }
2772
2773 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
2781 if self.render_blocking_element_count() > 0 {
2782 return Default::default();
2783 }
2784
2785 let mut results = ReflowPhasesRun::empty();
2786 if self.has_pending_animated_image_update.get() {
2787 self.image_animation_manager
2788 .borrow()
2789 .update_active_frames(&self.window, self.current_animation_timeline_value());
2790 self.has_pending_animated_image_update.set(false);
2791 results.insert(ReflowPhasesRun::UpdatedImageData);
2792 }
2793
2794 self.current_rendering_epoch
2795 .set(self.current_rendering_epoch.get().next());
2796 let current_rendering_epoch = self.current_rendering_epoch.get();
2797
2798 let mut image_keys = Vec::new();
2800 #[cfg(feature = "webgpu")]
2801 image_keys.extend(
2802 self.dirty_webgpu_contexts
2803 .borrow_mut()
2804 .drain()
2805 .filter(|(_, context)| context.update_rendering(current_rendering_epoch))
2806 .map(|(_, context)| {
2807 results.insert(ReflowPhasesRun::UpdatedImageData);
2808 context.image_key()
2809 }),
2810 );
2811
2812 image_keys.extend(
2813 self.dirty_2d_contexts
2814 .borrow_mut()
2815 .drain()
2816 .filter(|(_, context)| context.update_rendering(current_rendering_epoch))
2817 .map(|(_, context)| {
2818 results.insert(ReflowPhasesRun::UpdatedImageData);
2819 context.image_key()
2820 }),
2821 );
2822
2823 let dirty_webgl_context_ids: Vec<_> = self
2824 .dirty_webgl_contexts
2825 .borrow_mut()
2826 .drain()
2827 .filter(|(_, context)| context.onscreen())
2828 .map(|(id, context)| {
2829 image_keys.push(context.image_key());
2830 id
2831 })
2832 .collect();
2833
2834 if !dirty_webgl_context_ids.is_empty() {
2835 results.insert(ReflowPhasesRun::UpdatedImageData);
2836 self.window
2837 .webgl_chan()
2838 .expect("Where's the WebGL channel?")
2839 .send(WebGLMsg::SwapBuffers(
2840 dirty_webgl_context_ids,
2841 Some(current_rendering_epoch),
2842 0,
2843 ))
2844 .unwrap();
2845 }
2846
2847 let pipeline_id = self.window().pipeline_id();
2850 if !image_keys.is_empty() {
2851 self.waiting_on_canvas_image_updates.set(true);
2852 self.window().compositor_api().delay_new_frame_for_canvas(
2853 self.window().pipeline_id(),
2854 current_rendering_epoch,
2855 image_keys.into_iter().flatten().collect(),
2856 );
2857 }
2858
2859 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
2860
2861 self.window().compositor_api().update_epoch(
2862 self.webview_id(),
2863 pipeline_id,
2864 current_rendering_epoch,
2865 );
2866
2867 results
2868 }
2869
2870 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2871 self.waiting_on_canvas_image_updates.set(false);
2872 }
2873
2874 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2875 self.waiting_on_canvas_image_updates.get()
2876 }
2877
2878 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2888 if !self.is_fully_active() {
2889 return false;
2890 }
2891
2892 let fonts = self.Fonts(can_gc);
2893 if !fonts.waiting_to_fullfill_promise() {
2894 return false;
2895 }
2896 if self.window().font_context().web_fonts_still_loading() != 0 {
2897 return false;
2898 }
2899 if self.ReadyState() != DocumentReadyState::Complete {
2900 return false;
2901 }
2902 if !self.restyle_reason().is_empty() {
2903 return false;
2904 }
2905 if !self.rendering_update_reasons.get().is_empty() {
2906 return false;
2907 }
2908
2909 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
2910
2911 if result {
2915 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
2916 }
2917
2918 result
2919 }
2920
2921 pub(crate) fn id_map(
2922 &self,
2923 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2924 self.id_map.borrow()
2925 }
2926
2927 pub(crate) fn name_map(
2928 &self,
2929 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2930 self.name_map.borrow()
2931 }
2932
2933 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
2935 self.resize_observers
2936 .borrow_mut()
2937 .push(Dom::from_ref(resize_observer));
2938 }
2939
2940 pub(crate) fn has_resize_observers(&self) -> bool {
2942 !self.resize_observers.borrow().is_empty()
2943 }
2944
2945 pub(crate) fn gather_active_resize_observations_at_depth(
2948 &self,
2949 depth: &ResizeObservationDepth,
2950 ) -> bool {
2951 let mut has_active_resize_observations = false;
2952 for observer in self.resize_observers.borrow_mut().iter_mut() {
2953 observer.gather_active_resize_observations_at_depth(
2954 depth,
2955 &mut has_active_resize_observations,
2956 );
2957 }
2958 has_active_resize_observations
2959 }
2960
2961 pub(crate) fn broadcast_active_resize_observations(
2963 &self,
2964 can_gc: CanGc,
2965 ) -> ResizeObservationDepth {
2966 let mut shallowest = ResizeObservationDepth::max();
2967 let iterator: Vec<DomRoot<ResizeObserver>> = self
2971 .resize_observers
2972 .borrow()
2973 .iter()
2974 .cloned()
2975 .map(|obs| DomRoot::from_ref(&*obs))
2976 .collect();
2977 for observer in iterator {
2978 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
2979 }
2980 shallowest
2981 }
2982
2983 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
2985 self.resize_observers
2986 .borrow()
2987 .iter()
2988 .any(|observer| observer.has_skipped_resize_observations())
2989 }
2990
2991 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
2993 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
2994 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
2995 ..Default::default()
2996 };
2997 self.window
2998 .as_global_scope()
2999 .report_an_error(error_info, HandleValue::null(), can_gc);
3000 }
3001
3002 pub(crate) fn status_code(&self) -> Option<u16> {
3003 self.status_code
3004 }
3005
3006 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3008 let encoding = self.encoding.get();
3014
3015 let base_url = self.base_url();
3021
3022 url::Url::options()
3024 .base_url(Some(base_url.as_url()))
3025 .encoding_override(Some(&|input| {
3026 servo_url::encoding::encode_as_url_query_string(input, encoding)
3027 }))
3028 .parse(url)
3029 .map(ServoUrl::from)
3030 }
3031
3032 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3034 if !self.has_browsing_context {
3036 return false;
3037 }
3038
3039 if !self.is_fully_active() {
3041 return false;
3042 }
3043
3044 true
3050 }
3051
3052 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3055 self.intersection_observers
3056 .borrow_mut()
3057 .push(Dom::from_ref(intersection_observer));
3058 }
3059
3060 pub(crate) fn remove_intersection_observer(
3064 &self,
3065 intersection_observer: &IntersectionObserver,
3066 ) {
3067 self.intersection_observers
3068 .borrow_mut()
3069 .retain(|observer| *observer != intersection_observer)
3070 }
3071
3072 pub(crate) fn update_intersection_observer_steps(
3074 &self,
3075 time: CrossProcessInstant,
3076 can_gc: CanGc,
3077 ) {
3078 for intersection_observer in &*self.intersection_observers.borrow() {
3080 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3081 }
3082 }
3083
3084 fn update_single_intersection_observer_steps(
3086 &self,
3087 intersection_observer: &IntersectionObserver,
3088 time: CrossProcessInstant,
3089 can_gc: CanGc,
3090 ) {
3091 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3094
3095 intersection_observer.update_intersection_observations_steps(
3099 self,
3100 time,
3101 root_bounds,
3102 can_gc,
3103 );
3104 }
3105
3106 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3108 self.intersection_observer_task_queued.set(false);
3111
3112 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3117
3118 for intersection_observer in notify_list.iter() {
3121 intersection_observer.invoke_callback_if_necessary(can_gc);
3123 }
3124 }
3125
3126 pub(crate) fn queue_an_intersection_observer_task(&self) {
3128 if self.intersection_observer_task_queued.get() {
3131 return;
3132 }
3133
3134 self.intersection_observer_task_queued.set(true);
3137
3138 let document = Trusted::new(self);
3142 self.owner_global()
3143 .task_manager()
3144 .intersection_observer_task_source()
3145 .queue(task!(notify_intersection_observers: move || {
3146 document.root().notify_intersection_observers(CanGc::note());
3147 }));
3148 }
3149
3150 pub(crate) fn handle_paint_metric(
3151 &self,
3152 metric_type: ProgressiveWebMetricType,
3153 metric_value: CrossProcessInstant,
3154 first_reflow: bool,
3155 can_gc: CanGc,
3156 ) {
3157 let metrics = self.interactive_time.borrow();
3158 match metric_type {
3159 ProgressiveWebMetricType::FirstPaint => {
3160 metrics.set_first_paint(metric_value, first_reflow)
3161 },
3162 ProgressiveWebMetricType::FirstContentfulPaint => {
3163 metrics.set_first_contentful_paint(metric_value, first_reflow)
3164 },
3165 ProgressiveWebMetricType::LargestContentfulPaint { area, lcp_type } => {
3166 metrics.set_largest_contentful_paint(metric_value, area, lcp_type)
3167 },
3168 ProgressiveWebMetricType::TimeToInteractive => {
3169 unreachable!("Unexpected non-paint metric.")
3170 },
3171 }
3172
3173 let entry = PerformancePaintTiming::new(
3174 self.window.as_global_scope(),
3175 metric_type,
3176 metric_value,
3177 can_gc,
3178 );
3179 self.window
3180 .Performance()
3181 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
3182 }
3183
3184 fn write(
3186 &self,
3187 text: Vec<TrustedHTMLOrString>,
3188 line_feed: bool,
3189 containing_class: &str,
3190 field: &str,
3191 can_gc: CanGc,
3192 ) -> ErrorResult {
3193 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3195 let mut is_trusted = true;
3197 for value in text {
3199 match value {
3200 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3202 strings.push(trusted_html.to_string().to_owned());
3203 },
3204 TrustedHTMLOrString::String(str_) => {
3205 is_trusted = false;
3207 strings.push(str_.into());
3209 },
3210 };
3211 }
3212 let mut string = itertools::join(strings, "");
3213 if !is_trusted {
3217 string = TrustedHTML::get_trusted_script_compliant_string(
3218 &self.global(),
3219 TrustedHTMLOrString::String(string.into()),
3220 &format!("{} {}", containing_class, field),
3221 can_gc,
3222 )?
3223 .str()
3224 .to_owned();
3225 }
3226 if line_feed {
3228 string.push('\n');
3229 }
3230 if !self.is_html_document() {
3232 return Err(Error::InvalidState(None));
3233 }
3234
3235 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3238 return Err(Error::InvalidState(None));
3239 }
3240
3241 if !self.is_active() || self.active_parser_was_aborted.get() {
3243 return Ok(());
3244 }
3245
3246 let parser = match self.get_current_parser() {
3247 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3248 _ => {
3250 if self.is_prompting_or_unloading() ||
3253 self.ignore_destructive_writes_counter.get() > 0
3254 {
3255 return Ok(());
3256 }
3257 self.Open(None, None, can_gc)?;
3259 self.get_current_parser().unwrap()
3260 },
3261 };
3262
3263 parser.write(string.into(), can_gc);
3265
3266 Ok(())
3267 }
3268}
3269
3270#[derive(MallocSizeOf, PartialEq)]
3271pub(crate) enum DocumentSource {
3272 FromParser,
3273 NotFromParser,
3274}
3275
3276#[allow(unsafe_code)]
3277pub(crate) trait LayoutDocumentHelpers<'dom> {
3278 fn is_html_document_for_layout(&self) -> bool;
3279 fn quirks_mode(self) -> QuirksMode;
3280 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3281 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3282 fn shadow_roots_styles_changed(self) -> bool;
3283 fn flush_shadow_roots_stylesheets(self);
3284}
3285
3286#[allow(unsafe_code)]
3287impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3288 #[inline]
3289 fn is_html_document_for_layout(&self) -> bool {
3290 self.unsafe_get().is_html_document
3291 }
3292
3293 #[inline]
3294 fn quirks_mode(self) -> QuirksMode {
3295 self.unsafe_get().quirks_mode.get()
3296 }
3297
3298 #[inline]
3299 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3300 self.unsafe_get().style_shared_lock()
3301 }
3302
3303 #[inline]
3304 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3305 unsafe {
3310 self.unsafe_get()
3311 .shadow_roots
3312 .borrow_for_layout()
3313 .iter()
3314 .map(|sr| sr.to_layout())
3315 .collect()
3316 }
3317 }
3318
3319 #[inline]
3320 fn shadow_roots_styles_changed(self) -> bool {
3321 self.unsafe_get().shadow_roots_styles_changed.get()
3322 }
3323
3324 #[inline]
3325 fn flush_shadow_roots_stylesheets(self) {
3326 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3327 }
3328}
3329
3330fn get_registrable_domain_suffix_of_or_is_equal_to(
3334 host_suffix_string: &DOMString,
3335 original_host: Host,
3336) -> Option<Host> {
3337 if host_suffix_string.is_empty() {
3339 return None;
3340 }
3341
3342 let host = match Host::parse(&host_suffix_string.str()) {
3344 Ok(host) => host,
3345 Err(_) => return None,
3346 };
3347
3348 if host != original_host {
3350 let host = match host {
3352 Host::Domain(ref host) => host,
3353 _ => return None,
3354 };
3355 let original_host = match original_host {
3356 Host::Domain(ref original_host) => original_host,
3357 _ => return None,
3358 };
3359
3360 let index = original_host.len().checked_sub(host.len())?;
3362 let (prefix, suffix) = original_host.split_at(index);
3363
3364 if !prefix.ends_with('.') {
3365 return None;
3366 }
3367 if suffix != host {
3368 return None;
3369 }
3370
3371 if is_pub_domain(host) {
3373 return None;
3374 }
3375 }
3376
3377 Some(host)
3379}
3380
3381fn url_has_network_scheme(url: &ServoUrl) -> bool {
3383 matches!(url.scheme(), "ftp" | "http" | "https")
3384}
3385
3386#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3387pub(crate) enum HasBrowsingContext {
3388 No,
3389 Yes,
3390}
3391
3392impl Document {
3393 #[allow(clippy::too_many_arguments)]
3394 pub(crate) fn new_inherited(
3395 window: &Window,
3396 has_browsing_context: HasBrowsingContext,
3397 url: Option<ServoUrl>,
3398 origin: MutableOrigin,
3399 is_html_document: IsHTMLDocument,
3400 content_type: Option<Mime>,
3401 last_modified: Option<String>,
3402 activity: DocumentActivity,
3403 source: DocumentSource,
3404 doc_loader: DocumentLoader,
3405 referrer: Option<String>,
3406 status_code: Option<u16>,
3407 canceller: FetchCanceller,
3408 is_initial_about_blank: bool,
3409 allow_declarative_shadow_roots: bool,
3410 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3411 has_trustworthy_ancestor_origin: bool,
3412 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3413 creation_sandboxing_flag_set: SandboxingFlagSet,
3414 ) -> Document {
3415 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3416
3417 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3418 (DocumentReadyState::Loading, false)
3419 } else {
3420 (DocumentReadyState::Complete, true)
3421 };
3422
3423 let frame_type = match window.is_top_level() {
3424 true => TimerMetadataFrameType::RootWindow,
3425 false => TimerMetadataFrameType::IFrame,
3426 };
3427 let interactive_time = ProgressiveWebMetrics::new(
3428 window.time_profiler_chan().clone(),
3429 url.clone(),
3430 frame_type,
3431 );
3432
3433 let content_type = content_type.unwrap_or_else(|| {
3434 match is_html_document {
3435 IsHTMLDocument::HTMLDocument => "text/html",
3437 IsHTMLDocument::NonHTMLDocument => "application/xml",
3439 }
3440 .parse()
3441 .unwrap()
3442 });
3443
3444 let encoding = content_type
3445 .get_parameter(CHARSET)
3446 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3447 .unwrap_or(UTF_8);
3448
3449 let has_focus = window.parent_info().is_none();
3450
3451 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3452
3453 Document {
3454 node: Node::new_document_node(),
3455 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3456 window: Dom::from_ref(window),
3457 has_browsing_context,
3458 implementation: Default::default(),
3459 content_type,
3460 last_modified,
3461 url: DomRefCell::new(url),
3462 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3464 event_handler: DocumentEventHandler::new(window),
3465 embedder_controls: DocumentEmbedderControls::new(window),
3466 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3467 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3468 encoding: Cell::new(encoding),
3470 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3471 activity: Cell::new(activity),
3472 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3473 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3474 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3475 images: Default::default(),
3476 embeds: Default::default(),
3477 links: Default::default(),
3478 forms: Default::default(),
3479 scripts: Default::default(),
3480 anchors: Default::default(),
3481 applets: Default::default(),
3482 iframes: RefCell::new(IFrameCollection::new()),
3483 style_shared_lock: {
3484 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3491 LazyLock::new(StyleSharedRwLock::new);
3492
3493 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3494 },
3496 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3497 stylesheet_list: MutNullableDom::new(None),
3498 ready_state: Cell::new(ready_state),
3499 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3500 focus_transaction: DomRefCell::new(None),
3501 focused: Default::default(),
3502 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3503 has_focus: Cell::new(has_focus),
3504 current_script: Default::default(),
3505 pending_parsing_blocking_script: Default::default(),
3506 script_blocking_stylesheets_count: Default::default(),
3507 render_blocking_element_count: Default::default(),
3508 deferred_scripts: Default::default(),
3509 asap_in_order_scripts_list: Default::default(),
3510 asap_scripts_set: Default::default(),
3511 animation_frame_ident: Cell::new(0),
3512 animation_frame_list: DomRefCell::new(VecDeque::new()),
3513 running_animation_callbacks: Cell::new(false),
3514 loader: DomRefCell::new(doc_loader),
3515 current_parser: Default::default(),
3516 base_element: Default::default(),
3517 appropriate_template_contents_owner_document: Default::default(),
3518 pending_restyles: DomRefCell::new(FxHashMap::default()),
3519 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3520 dom_interactive: Cell::new(Default::default()),
3521 dom_content_loaded_event_start: Cell::new(Default::default()),
3522 dom_content_loaded_event_end: Cell::new(Default::default()),
3523 dom_complete: Cell::new(Default::default()),
3524 top_level_dom_complete: Cell::new(Default::default()),
3525 load_event_start: Cell::new(Default::default()),
3526 load_event_end: Cell::new(Default::default()),
3527 unload_event_start: Cell::new(Default::default()),
3528 unload_event_end: Cell::new(Default::default()),
3529 https_state: Cell::new(HttpsState::None),
3530 origin,
3531 referrer,
3532 target_element: MutNullableDom::new(None),
3533 policy_container: DomRefCell::new(PolicyContainer::default()),
3534 preloaded_resources: Default::default(),
3535 ignore_destructive_writes_counter: Default::default(),
3536 ignore_opens_during_unload_counter: Default::default(),
3537 spurious_animation_frames: Cell::new(0),
3538 dom_count: Cell::new(1),
3539 fullscreen_element: MutNullableDom::new(None),
3540 form_id_listener_map: Default::default(),
3541 interactive_time: DomRefCell::new(interactive_time),
3542 tti_window: DomRefCell::new(InteractiveWindow::default()),
3543 canceller,
3544 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3545 page_showing: Cell::new(false),
3546 salvageable: Cell::new(true),
3547 active_parser_was_aborted: Cell::new(false),
3548 fired_unload: Cell::new(false),
3549 responsive_images: Default::default(),
3550 redirect_count: Cell::new(0),
3551 completely_loaded: Cell::new(false),
3552 script_and_layout_blockers: Cell::new(0),
3553 delayed_tasks: Default::default(),
3554 shadow_roots: DomRefCell::new(HashSet::new()),
3555 shadow_roots_styles_changed: Cell::new(false),
3556 media_controls: DomRefCell::new(HashMap::new()),
3557 dirty_2d_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3558 dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3559 has_pending_animated_image_update: Cell::new(false),
3560 #[cfg(feature = "webgpu")]
3561 dirty_webgpu_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3562 selection: MutNullableDom::new(None),
3563 animation_timeline: if pref!(layout_animations_test_enabled) {
3564 DomRefCell::new(AnimationTimeline::new_for_testing())
3565 } else {
3566 DomRefCell::new(AnimationTimeline::new())
3567 },
3568 animations: Animations::new(),
3569 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3570 dirty_root: Default::default(),
3571 declarative_refresh: Default::default(),
3572 resize_observers: Default::default(),
3573 fonts: Default::default(),
3574 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3575 status_code,
3576 is_initial_about_blank: Cell::new(is_initial_about_blank),
3577 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3578 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3579 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3580 intersection_observer_task_queued: Cell::new(false),
3581 intersection_observers: Default::default(),
3582 highlighted_dom_node: Default::default(),
3583 adopted_stylesheets: Default::default(),
3584 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3585 pending_scroll_event_targets: Default::default(),
3586 rendering_update_reasons: Default::default(),
3587 waiting_on_canvas_image_updates: Cell::new(false),
3588 current_rendering_epoch: Default::default(),
3589 custom_element_reaction_stack,
3590 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3591 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3592 favicon: RefCell::new(None),
3593 websockets: DOMTracker::new(),
3594 }
3595 }
3596
3597 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3599 if let Some(csp_list) = self.get_csp_list() {
3600 for policy in &csp_list.0 {
3601 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3602 policy.disposition == PolicyDisposition::Enforce
3603 {
3604 return InsecureRequestsPolicy::Upgrade;
3605 }
3606 }
3607 }
3608
3609 self.inherited_insecure_requests_policy
3610 .get()
3611 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3612 }
3613
3614 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3616 &self.event_handler
3617 }
3618
3619 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3621 &self.embedder_controls
3622 }
3623
3624 fn has_pending_scroll_events(&self) -> bool {
3627 !self.pending_scroll_event_targets.borrow().is_empty()
3628 }
3629
3630 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3633 self.rendering_update_reasons
3634 .set(self.rendering_update_reasons.get().union(reason));
3635 }
3636
3637 pub(crate) fn clear_rendering_update_reasons(&self) {
3639 self.rendering_update_reasons
3640 .set(RenderingUpdateReason::empty())
3641 }
3642
3643 pub(crate) fn add_script_and_layout_blocker(&self) {
3650 self.script_and_layout_blockers
3651 .set(self.script_and_layout_blockers.get() + 1);
3652 }
3653
3654 pub(crate) fn remove_script_and_layout_blocker(&self) {
3658 assert!(self.script_and_layout_blockers.get() > 0);
3659 self.script_and_layout_blockers
3660 .set(self.script_and_layout_blockers.get() - 1);
3661 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3662 {
3663 let task = self.delayed_tasks.borrow_mut().remove(0);
3664 task.run_box();
3665 }
3666 }
3667
3668 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3670 self.delayed_tasks.borrow_mut().push(Box::new(task));
3671 }
3672
3673 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3676 assert_eq!(
3677 self.script_and_layout_blockers.get(),
3678 0,
3679 "Attempt to use script or layout while DOM not in a stable state"
3680 );
3681 }
3682
3683 #[allow(clippy::too_many_arguments)]
3684 pub(crate) fn new(
3685 window: &Window,
3686 has_browsing_context: HasBrowsingContext,
3687 url: Option<ServoUrl>,
3688 origin: MutableOrigin,
3689 doctype: IsHTMLDocument,
3690 content_type: Option<Mime>,
3691 last_modified: Option<String>,
3692 activity: DocumentActivity,
3693 source: DocumentSource,
3694 doc_loader: DocumentLoader,
3695 referrer: Option<String>,
3696 status_code: Option<u16>,
3697 canceller: FetchCanceller,
3698 is_initial_about_blank: bool,
3699 allow_declarative_shadow_roots: bool,
3700 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3701 has_trustworthy_ancestor_origin: bool,
3702 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3703 creation_sandboxing_flag_set: SandboxingFlagSet,
3704 can_gc: CanGc,
3705 ) -> DomRoot<Document> {
3706 Self::new_with_proto(
3707 window,
3708 None,
3709 has_browsing_context,
3710 url,
3711 origin,
3712 doctype,
3713 content_type,
3714 last_modified,
3715 activity,
3716 source,
3717 doc_loader,
3718 referrer,
3719 status_code,
3720 canceller,
3721 is_initial_about_blank,
3722 allow_declarative_shadow_roots,
3723 inherited_insecure_requests_policy,
3724 has_trustworthy_ancestor_origin,
3725 custom_element_reaction_stack,
3726 creation_sandboxing_flag_set,
3727 can_gc,
3728 )
3729 }
3730
3731 #[allow(clippy::too_many_arguments)]
3732 fn new_with_proto(
3733 window: &Window,
3734 proto: Option<HandleObject>,
3735 has_browsing_context: HasBrowsingContext,
3736 url: Option<ServoUrl>,
3737 origin: MutableOrigin,
3738 doctype: IsHTMLDocument,
3739 content_type: Option<Mime>,
3740 last_modified: Option<String>,
3741 activity: DocumentActivity,
3742 source: DocumentSource,
3743 doc_loader: DocumentLoader,
3744 referrer: Option<String>,
3745 status_code: Option<u16>,
3746 canceller: FetchCanceller,
3747 is_initial_about_blank: bool,
3748 allow_declarative_shadow_roots: bool,
3749 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3750 has_trustworthy_ancestor_origin: bool,
3751 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3752 creation_sandboxing_flag_set: SandboxingFlagSet,
3753 can_gc: CanGc,
3754 ) -> DomRoot<Document> {
3755 let document = reflect_dom_object_with_proto(
3756 Box::new(Document::new_inherited(
3757 window,
3758 has_browsing_context,
3759 url,
3760 origin,
3761 doctype,
3762 content_type,
3763 last_modified,
3764 activity,
3765 source,
3766 doc_loader,
3767 referrer,
3768 status_code,
3769 canceller,
3770 is_initial_about_blank,
3771 allow_declarative_shadow_roots,
3772 inherited_insecure_requests_policy,
3773 has_trustworthy_ancestor_origin,
3774 custom_element_reaction_stack,
3775 creation_sandboxing_flag_set,
3776 )),
3777 window,
3778 proto,
3779 can_gc,
3780 );
3781 {
3782 let node = document.upcast::<Node>();
3783 node.set_owner_doc(&document);
3784 }
3785 document
3786 }
3787
3788 pub(crate) fn get_redirect_count(&self) -> u16 {
3789 self.redirect_count.get()
3790 }
3791
3792 pub(crate) fn set_redirect_count(&self, count: u16) {
3793 self.redirect_count.set(count)
3794 }
3795
3796 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3797 if name.is_empty() {
3798 return 0;
3799 }
3800 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3801 }
3802
3803 pub(crate) fn nth_element_by_name(
3804 &self,
3805 index: u32,
3806 name: &DOMString,
3807 ) -> Option<DomRoot<Node>> {
3808 if name.is_empty() {
3809 return None;
3810 }
3811 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3812 }
3813
3814 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3817 let element = match node.downcast::<Element>() {
3818 Some(element) => element,
3819 None => return false,
3820 };
3821 if element.namespace() != &ns!(html) {
3822 return false;
3823 }
3824 element.get_name().is_some_and(|n| &*n == name)
3825 }
3826
3827 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3828 let doc = self.GetDocumentElement();
3829 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3830 maybe_node
3831 .iter()
3832 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3833 .filter(|node| callback(node))
3834 .count() as u32
3835 }
3836
3837 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3838 &self,
3839 index: u32,
3840 callback: F,
3841 ) -> Option<DomRoot<Node>> {
3842 let doc = self.GetDocumentElement();
3843 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3844 maybe_node
3845 .iter()
3846 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3847 .filter(|node| callback(node))
3848 .nth(index as usize)
3849 .map(|n| DomRoot::from_ref(&*n))
3850 }
3851
3852 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3853 self.GetDocumentElement().and_then(DomRoot::downcast)
3854 }
3855
3856 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3858 &self.style_shared_lock
3859 }
3860
3861 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3863 let mut stylesheets = self.stylesheets.borrow_mut();
3870 let have_changed = stylesheets.has_changed();
3871 stylesheets.flush_without_invalidation();
3872 have_changed
3873 }
3874
3875 pub(crate) fn salvageable(&self) -> bool {
3876 self.salvageable.get()
3877 }
3878
3879 pub(crate) fn appropriate_template_contents_owner_document(
3881 &self,
3882 can_gc: CanGc,
3883 ) -> DomRoot<Document> {
3884 self.appropriate_template_contents_owner_document
3885 .or_init(|| {
3886 let doctype = if self.is_html_document {
3887 IsHTMLDocument::HTMLDocument
3888 } else {
3889 IsHTMLDocument::NonHTMLDocument
3890 };
3891 let new_doc = Document::new(
3892 self.window(),
3893 HasBrowsingContext::No,
3894 None,
3895 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3897 doctype,
3898 None,
3899 None,
3900 DocumentActivity::Inactive,
3901 DocumentSource::NotFromParser,
3902 DocumentLoader::new(&self.loader()),
3903 None,
3904 None,
3905 Default::default(),
3906 false,
3907 self.allow_declarative_shadow_roots(),
3908 Some(self.insecure_requests_policy()),
3909 self.has_trustworthy_ancestor_or_current_origin(),
3910 self.custom_element_reaction_stack.clone(),
3911 self.creation_sandboxing_flag_set(),
3912 can_gc,
3913 );
3914 new_doc
3915 .appropriate_template_contents_owner_document
3916 .set(Some(&new_doc));
3917 new_doc
3918 })
3919 }
3920
3921 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
3922 self.id_map
3923 .borrow()
3924 .get(id)
3925 .map(|elements| DomRoot::from_ref(&*elements[0]))
3926 }
3927
3928 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
3929 let map = self.pending_restyles.borrow_mut();
3930 RefMut::map(map, |m| {
3931 &mut m
3932 .entry(Dom::from_ref(el))
3933 .or_insert_with(|| NoTrace(PendingRestyle::default()))
3934 .0
3935 })
3936 }
3937
3938 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
3939 let mut entry = self.ensure_pending_restyle(el);
3945 if entry.snapshot.is_none() {
3946 entry.snapshot = Some(Snapshot::new());
3947 }
3948 if attr.local_name() == &local_name!("style") {
3949 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
3950 }
3951
3952 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
3953 entry.hint.insert(RestyleHint::RESTYLE_SELF);
3954 }
3955
3956 let snapshot = entry.snapshot.as_mut().unwrap();
3957 if attr.local_name() == &local_name!("id") {
3958 if snapshot.id_changed {
3959 return;
3960 }
3961 snapshot.id_changed = true;
3962 } else if attr.local_name() == &local_name!("class") {
3963 if snapshot.class_changed {
3964 return;
3965 }
3966 snapshot.class_changed = true;
3967 } else {
3968 snapshot.other_attributes_changed = true;
3969 }
3970 let local_name = style::LocalName::cast(attr.local_name());
3971 if !snapshot.changed_attrs.contains(local_name) {
3972 snapshot.changed_attrs.push(local_name.clone());
3973 }
3974 if snapshot.attrs.is_none() {
3975 let attrs = el
3976 .attrs()
3977 .iter()
3978 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
3979 .collect();
3980 snapshot.attrs = Some(attrs);
3981 }
3982 }
3983
3984 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
3985 self.policy_container
3986 .borrow_mut()
3987 .set_referrer_policy(policy);
3988 }
3989
3990 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
3991 self.policy_container.borrow().get_referrer_policy()
3992 }
3993
3994 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
3995 if let Some(ref element) = self.target_element.get() {
3996 element.set_target_state(false);
3997 }
3998
3999 self.target_element.set(node);
4000
4001 if let Some(ref element) = self.target_element.get() {
4002 element.set_target_state(true);
4003 }
4004 }
4005
4006 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4007 self.ignore_destructive_writes_counter
4008 .set(self.ignore_destructive_writes_counter.get() + 1);
4009 }
4010
4011 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4012 self.ignore_destructive_writes_counter
4013 .set(self.ignore_destructive_writes_counter.get() - 1);
4014 }
4015
4016 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4017 self.ignore_opens_during_unload_counter.get() > 0
4018 }
4019
4020 fn incr_ignore_opens_during_unload_counter(&self) {
4021 self.ignore_opens_during_unload_counter
4022 .set(self.ignore_opens_during_unload_counter.get() + 1);
4023 }
4024
4025 fn decr_ignore_opens_during_unload_counter(&self) {
4026 self.ignore_opens_during_unload_counter
4027 .set(self.ignore_opens_during_unload_counter.get() - 1);
4028 }
4029
4030 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4032 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4034 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4035 let mut error = false;
4036
4037 match *pending.namespace() {
4040 ns!(mathml) => {
4041 if pending.local_name().as_ref() != "math" {
4042 error = true;
4043 }
4044 },
4045 ns!(svg) => {
4046 if pending.local_name().as_ref() != "svg" {
4047 error = true;
4048 }
4049 },
4050 ns!(html) => (),
4051 _ => error = true,
4052 }
4053 if !pending.fullscreen_element_ready_check() {
4055 error = true;
4056 }
4057
4058 if pref!(dom_fullscreen_test) {
4059 info!("Tests don't really enter fullscreen.");
4062 } else {
4063 warn!("Fullscreen not supported yet");
4066 }
4067
4068 let window = self.window();
4071 if !error {
4073 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4074 self.send_to_embedder(event);
4075 }
4076
4077 let pipeline_id = self.window().pipeline_id();
4078
4079 let trusted_pending = Trusted::new(pending);
4081 let trusted_promise = TrustedPromise::new(promise.clone());
4082 let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
4083 let script_msg = CommonScriptMsg::Task(
4086 ScriptThreadEventCategory::EnterFullscreen,
4087 handler,
4088 Some(pipeline_id),
4089 TaskSourceName::DOMManipulation,
4090 );
4091 let msg = MainThreadScriptMsg::Common(script_msg);
4092 window.main_thread_script_chan().send(msg).unwrap();
4093
4094 promise
4095 }
4096
4097 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4099 let global = self.global();
4100 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4102 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4103 if self.fullscreen_element.get().is_none() {
4105 promise.reject_error(Error::Type(String::from("fullscreen is null")), can_gc);
4106 return promise;
4107 }
4108 let element = self.fullscreen_element.get().unwrap();
4110
4111 let window = self.window();
4114 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4116 self.send_to_embedder(event);
4117
4118 let trusted_element = Trusted::new(&*element);
4120 let trusted_promise = TrustedPromise::new(promise.clone());
4121 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4122 let pipeline_id = Some(global.pipeline_id());
4123 let script_msg = CommonScriptMsg::Task(
4126 ScriptThreadEventCategory::ExitFullscreen,
4127 handler,
4128 pipeline_id,
4129 TaskSourceName::DOMManipulation,
4130 );
4131 let msg = MainThreadScriptMsg::Common(script_msg);
4132 window.main_thread_script_chan().send(msg).unwrap();
4133
4134 promise
4135 }
4136
4137 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4138 self.fullscreen_element.set(element);
4139 }
4140
4141 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4142 match self.browsing_context() {
4144 None => false,
4146 Some(_) => {
4147 let window = self.window();
4149 if window.is_top_level() {
4150 true
4151 } else {
4152 window
4154 .GetFrameElement()
4155 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4156 }
4157 },
4158 }
4159 }
4160
4161 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4162 let map = self.form_id_listener_map.borrow();
4163 if let Some(listeners) = map.get(id) {
4164 for listener in listeners {
4165 listener
4166 .as_maybe_form_control()
4167 .expect("Element must be a form control")
4168 .reset_form_owner(can_gc);
4169 }
4170 }
4171 }
4172
4173 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4174 self.shadow_roots
4175 .borrow_mut()
4176 .insert(Dom::from_ref(shadow_root));
4177 self.invalidate_shadow_roots_stylesheets();
4178 }
4179
4180 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4181 let mut shadow_roots = self.shadow_roots.borrow_mut();
4182 shadow_roots.remove(&Dom::from_ref(shadow_root));
4183 }
4184
4185 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4186 self.shadow_roots_styles_changed.set(true);
4187 }
4188
4189 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4190 self.shadow_roots_styles_changed.get()
4191 }
4192
4193 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4194 if !self.shadow_roots_styles_changed.get() {
4195 return;
4196 }
4197 self.shadow_roots_styles_changed.set(false);
4198 }
4199
4200 pub(crate) fn stylesheet_count(&self) -> usize {
4201 self.stylesheets.borrow().len()
4202 }
4203
4204 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4205 let stylesheets = self.stylesheets.borrow();
4206
4207 stylesheets
4208 .get(Origin::Author, index)
4209 .and_then(|s| s.owner.get_cssom_object())
4210 }
4211
4212 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4219 let stylesheets = &mut *self.stylesheets.borrow_mut();
4220
4221 let insertion_point = stylesheets
4223 .iter()
4224 .map(|(sheet, _origin)| sheet)
4225 .find(|sheet_in_doc| {
4226 match &sheet_in_doc.owner {
4227 StylesheetSource::Element(other_node) => {
4228 owner_node.upcast::<Node>().is_before(other_node.upcast())
4229 },
4230 StylesheetSource::Constructed(_) => true,
4233 }
4234 })
4235 .cloned();
4236
4237 if self.has_browsing_context() {
4238 self.window.layout_mut().add_stylesheet(
4239 sheet.clone(),
4240 insertion_point.as_ref().map(|s| s.sheet.clone()),
4241 );
4242 }
4243
4244 DocumentOrShadowRoot::add_stylesheet(
4245 StylesheetSource::Element(Dom::from_ref(owner_node)),
4246 StylesheetSetRef::Document(stylesheets),
4247 sheet,
4248 insertion_point,
4249 self.style_shared_lock(),
4250 );
4251 }
4252
4253 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4258 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4259 debug_assert!(cssom_stylesheet.is_constructed());
4260
4261 let stylesheets = &mut *self.stylesheets.borrow_mut();
4262 let sheet = cssom_stylesheet.style_stylesheet().clone();
4263
4264 let insertion_point = stylesheets
4265 .iter()
4266 .last()
4267 .map(|(sheet, _origin)| sheet)
4268 .cloned();
4269
4270 if self.has_browsing_context() {
4271 self.window.layout_mut().add_stylesheet(
4272 sheet.clone(),
4273 insertion_point.as_ref().map(|s| s.sheet.clone()),
4274 );
4275 }
4276
4277 DocumentOrShadowRoot::add_stylesheet(
4278 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4279 StylesheetSetRef::Document(stylesheets),
4280 sheet,
4281 insertion_point,
4282 self.style_shared_lock(),
4283 );
4284 }
4285
4286 pub(crate) fn load_web_fonts_from_stylesheet(&self, stylesheet: &Arc<Stylesheet>) {
4288 self.window
4289 .layout()
4290 .load_web_fonts_from_stylesheet(stylesheet);
4291 }
4292
4293 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4296 if self.has_browsing_context() {
4297 self.window
4298 .layout_mut()
4299 .remove_stylesheet(stylesheet.clone());
4300 }
4301
4302 DocumentOrShadowRoot::remove_stylesheet(
4303 owner,
4304 stylesheet,
4305 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4306 )
4307 }
4308
4309 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4310 Ref::map(self.id_map.borrow(), |map| {
4311 map.get(id).map(|vec| &**vec).unwrap_or_default()
4312 })
4313 }
4314
4315 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4316 Ref::map(self.name_map.borrow(), |map| {
4317 map.get(name).map(|vec| &**vec).unwrap_or_default()
4318 })
4319 }
4320
4321 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4322 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4323 self.pending_restyles
4324 .borrow_mut()
4325 .drain()
4326 .filter_map(|(elem, restyle)| {
4327 let node = elem.upcast::<Node>();
4328 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4329 return None;
4330 }
4331 node.note_dirty_descendants();
4332 Some((node.to_trusted_node_address(), restyle.0))
4333 })
4334 .collect()
4335 }
4336
4337 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4338 self.animation_timeline.borrow_mut().advance_specific(delta);
4339 let current_timeline_value = self.current_animation_timeline_value();
4340 self.animations
4341 .update_for_new_timeline_value(&self.window, current_timeline_value);
4342 }
4343
4344 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4345 let current_timeline_value = self.current_animation_timeline_value();
4346 self.animations
4347 .mark_animating_nodes_as_dirty(current_timeline_value);
4348 }
4349
4350 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4351 self.animation_timeline.borrow().current_value()
4352 }
4353
4354 pub(crate) fn animations(&self) -> &Animations {
4355 &self.animations
4356 }
4357
4358 pub(crate) fn update_animations_post_reflow(&self) {
4359 self.animations
4360 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4361 self.image_animation_manager
4362 .borrow()
4363 .maybe_schedule_update_after_layout(
4364 &self.window,
4365 self.current_animation_timeline_value(),
4366 );
4367 }
4368
4369 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4370 self.animations.cancel_animations_for_node(node);
4371 self.image_animation_manager
4372 .borrow()
4373 .cancel_animations_for_node(node);
4374 }
4375
4376 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4378 if !pref!(layout_animations_test_enabled) {
4380 self.animation_timeline.borrow_mut().update();
4381 }
4382
4383 let current_timeline_value = self.current_animation_timeline_value();
4390 self.animations
4391 .update_for_new_timeline_value(&self.window, current_timeline_value);
4392 self.maybe_mark_animating_nodes_as_dirty();
4393
4394 self.window()
4396 .as_global_scope()
4397 .perform_a_microtask_checkpoint(can_gc);
4398
4399 let _realm = enter_realm(self);
4401 self.animations().send_pending_events(self.window(), can_gc);
4402 }
4403
4404 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4405 self.image_animation_manager.borrow()
4406 }
4407
4408 pub(crate) fn set_has_pending_animated_image_update(&self) {
4409 self.has_pending_animated_image_update.set(true);
4410 }
4411
4412 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4414 if self.will_declaratively_refresh() {
4416 return;
4417 }
4418
4419 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4421 Regex::new(
4425 r#"(?xs)
4426 ^
4427 \s* # 3
4428 ((?<time>[0-9]+)|\.) # 5-6
4429 [0-9.]* # 8
4430 (
4431 (
4432 (\s*;|\s*,|\s) # 10.3
4433 \s* # 10.4
4434 )
4435 (
4436 (
4437 (U|u)(R|r)(L|l) # 11.2-11.4
4438 \s*=\s* # 11.5-11.7
4439 )?
4440 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4441 |
4442 (?<url4>(?s-u:.)*)
4443 )
4444 )?
4445 $
4446 "#,
4447 )
4448 .unwrap()
4449 });
4450
4451 let mut url_record = self.url();
4453 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4454 captures
4455 } else {
4456 return;
4457 };
4458 let time = if let Some(time_string) = captures.name("time") {
4459 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4460 } else {
4461 0
4462 };
4463 let captured_url = captures.name("url1").or(captures
4464 .name("url2")
4465 .or(captures.name("url3").or(captures.name("url4"))));
4466
4467 if let Some(url_match) = captured_url {
4469 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4470 Some(&url_record),
4471 &String::from_utf8_lossy(url_match.as_bytes()),
4472 ) {
4473 info!("Refresh to {}", url.debug_compact());
4474 url
4475 } else {
4476 return;
4478 }
4479 }
4480 if self.completely_loaded() {
4482 self.window.as_global_scope().schedule_callback(
4484 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4485 window: DomRoot::from_ref(self.window()),
4486 url: url_record,
4487 }),
4488 Duration::from_secs(time),
4489 );
4490 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4491 } else {
4492 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4493 url: url_record,
4494 time,
4495 });
4496 }
4497 }
4498
4499 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4500 self.declarative_refresh.borrow().is_some()
4501 }
4502 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4503 *self.declarative_refresh.borrow_mut() = Some(refresh);
4504 }
4505
4506 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4508 if self.visibility_state.get() == visibility_state {
4510 return;
4511 }
4512 self.visibility_state.set(visibility_state);
4514 let entry = VisibilityStateEntry::new(
4517 &self.global(),
4518 visibility_state,
4519 CrossProcessInstant::now(),
4520 can_gc,
4521 );
4522 self.window
4523 .Performance()
4524 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
4525
4526 if visibility_state == DocumentVisibilityState::Hidden {
4537 self.window
4538 .Navigator()
4539 .GetGamepads()
4540 .iter_mut()
4541 .for_each(|gamepad| {
4542 if let Some(g) = gamepad {
4543 g.vibration_actuator().handle_visibility_change();
4544 }
4545 });
4546 }
4547
4548 self.upcast::<EventTarget>()
4550 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4551 }
4552
4553 pub(crate) fn is_initial_about_blank(&self) -> bool {
4555 self.is_initial_about_blank.get()
4556 }
4557
4558 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4560 self.allow_declarative_shadow_roots.get()
4561 }
4562
4563 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4564 self.has_trustworthy_ancestor_origin.get()
4565 }
4566
4567 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4568 self.has_trustworthy_ancestor_origin.get() ||
4569 self.origin().immutable().is_potentially_trustworthy()
4570 }
4571
4572 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4573 self.highlighted_dom_node.set(node);
4574 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4575 }
4576
4577 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4578 self.highlighted_dom_node.get()
4579 }
4580
4581 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4582 self.custom_element_reaction_stack.clone()
4583 }
4584
4585 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4586 self.active_sandboxing_flag_set.get().contains(flag)
4587 }
4588
4589 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4590 self.active_sandboxing_flag_set.set(flags)
4591 }
4592
4593 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4594 self.creation_sandboxing_flag_set.get()
4595 }
4596
4597 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4598 &self,
4599 ) -> SandboxingFlagSet {
4600 self.window()
4601 .window_proxy()
4602 .frame_element()
4603 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4604 .map(HTMLIFrameElement::sandboxing_flag_set)
4605 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4606 }
4607
4608 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4609 self.window()
4610 .scrolling_box_query(None, flags)
4611 .expect("We should always have a ScrollingBox for the Viewport")
4612 }
4613
4614 pub(crate) fn notify_embedder_favicon(&self) {
4615 if let Some(ref image) = *self.favicon.borrow() {
4616 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4617 }
4618 }
4619
4620 pub(crate) fn set_favicon(&self, favicon: Image) {
4621 *self.favicon.borrow_mut() = Some(favicon);
4622 self.notify_embedder_favicon();
4623 }
4624}
4625
4626#[allow(non_snake_case)]
4627impl DocumentMethods<crate::DomTypeHolder> for Document {
4628 fn Constructor(
4630 window: &Window,
4631 proto: Option<HandleObject>,
4632 can_gc: CanGc,
4633 ) -> Fallible<DomRoot<Document>> {
4634 let doc = window.Document();
4635 let docloader = DocumentLoader::new(&doc.loader());
4636 Ok(Document::new_with_proto(
4637 window,
4638 proto,
4639 HasBrowsingContext::No,
4640 None,
4641 doc.origin().clone(),
4642 IsHTMLDocument::NonHTMLDocument,
4643 None,
4644 None,
4645 DocumentActivity::Inactive,
4646 DocumentSource::NotFromParser,
4647 docloader,
4648 None,
4649 None,
4650 Default::default(),
4651 false,
4652 doc.allow_declarative_shadow_roots(),
4653 Some(doc.insecure_requests_policy()),
4654 doc.has_trustworthy_ancestor_or_current_origin(),
4655 doc.custom_element_reaction_stack(),
4656 doc.active_sandboxing_flag_set.get(),
4657 can_gc,
4658 ))
4659 }
4660
4661 fn ParseHTMLUnsafe(
4663 window: &Window,
4664 s: TrustedHTMLOrString,
4665 can_gc: CanGc,
4666 ) -> Fallible<DomRoot<Self>> {
4667 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
4671 window.as_global_scope(),
4672 s,
4673 "Document parseHTMLUnsafe",
4674 can_gc,
4675 )?;
4676
4677 let url = window.get_url();
4678 let doc = window.Document();
4679 let loader = DocumentLoader::new(&doc.loader());
4680
4681 let content_type = "text/html"
4682 .parse()
4683 .expect("Supported type is not a MIME type");
4684 let document = Document::new(
4687 window,
4688 HasBrowsingContext::No,
4689 Some(ServoUrl::parse("about:blank").unwrap()),
4690 doc.origin().clone(),
4691 IsHTMLDocument::HTMLDocument,
4692 Some(content_type),
4693 None,
4694 DocumentActivity::Inactive,
4695 DocumentSource::FromParser,
4696 loader,
4697 None,
4698 None,
4699 Default::default(),
4700 false,
4701 true,
4702 Some(doc.insecure_requests_policy()),
4703 doc.has_trustworthy_ancestor_or_current_origin(),
4704 doc.custom_element_reaction_stack(),
4705 doc.creation_sandboxing_flag_set(),
4706 can_gc,
4707 );
4708 ServoParser::parse_html_document(&document, Some(compliant_html), url, can_gc);
4710 document.set_ready_state(DocumentReadyState::Complete, can_gc);
4712 Ok(document)
4713 }
4714
4715 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
4717 false
4718 }
4719
4720 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4722 self.stylesheet_list.or_init(|| {
4723 StyleSheetList::new(
4724 &self.window,
4725 StyleSheetListOwner::Document(Dom::from_ref(self)),
4726 can_gc,
4727 )
4728 })
4729 }
4730
4731 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4733 self.implementation
4734 .or_init(|| DOMImplementation::new(self, can_gc))
4735 }
4736
4737 fn URL(&self) -> USVString {
4739 USVString(String::from(self.url().as_str()))
4740 }
4741
4742 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4744 self.document_or_shadow_root.get_active_element(
4745 self.get_focused_element(),
4746 self.GetBody(),
4747 self.GetDocumentElement(),
4748 )
4749 }
4750
4751 fn HasFocus(&self) -> bool {
4753 if self.window().parent_info().is_none() {
4775 self.is_fully_active()
4777 } else {
4778 self.is_fully_active() && self.has_focus.get()
4780 }
4781 }
4782
4783 fn Domain(&self) -> DOMString {
4785 if !self.has_browsing_context {
4787 return DOMString::new();
4788 }
4789
4790 match self.origin.effective_domain() {
4792 None => DOMString::new(),
4794 Some(Host::Domain(domain)) => DOMString::from(domain),
4796 Some(host) => DOMString::from(host.to_string()),
4797 }
4798 }
4799
4800 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4802 if !self.has_browsing_context {
4804 return Err(Error::Security);
4805 }
4806
4807 if self.has_active_sandboxing_flag(
4810 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4811 ) {
4812 return Err(Error::Security);
4813 }
4814
4815 let effective_domain = match self.origin.effective_domain() {
4817 Some(effective_domain) => effective_domain,
4818 None => return Err(Error::Security),
4819 };
4820
4821 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
4823 None => return Err(Error::Security),
4824 Some(host) => host,
4825 };
4826
4827 self.origin.set_domain(host);
4829
4830 Ok(())
4831 }
4832
4833 fn Referrer(&self) -> DOMString {
4835 match self.referrer {
4836 Some(ref referrer) => DOMString::from(referrer.to_string()),
4837 None => DOMString::new(),
4838 }
4839 }
4840
4841 fn DocumentURI(&self) -> USVString {
4843 self.URL()
4844 }
4845
4846 fn CompatMode(&self) -> DOMString {
4848 DOMString::from(match self.quirks_mode.get() {
4849 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4850 QuirksMode::Quirks => "BackCompat",
4851 })
4852 }
4853
4854 fn CharacterSet(&self) -> DOMString {
4856 DOMString::from(self.encoding.get().name())
4857 }
4858
4859 fn Charset(&self) -> DOMString {
4861 self.CharacterSet()
4862 }
4863
4864 fn InputEncoding(&self) -> DOMString {
4866 self.CharacterSet()
4867 }
4868
4869 fn ContentType(&self) -> DOMString {
4871 DOMString::from(self.content_type.to_string())
4872 }
4873
4874 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4876 self.upcast::<Node>()
4877 .children()
4878 .filter_map(DomRoot::downcast)
4879 .next()
4880 }
4881
4882 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4884 self.upcast::<Node>().child_elements().next()
4885 }
4886
4887 fn GetElementsByTagName(
4889 &self,
4890 qualified_name: DOMString,
4891 can_gc: CanGc,
4892 ) -> DomRoot<HTMLCollection> {
4893 let qualified_name = LocalName::from(qualified_name);
4894 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4895 return DomRoot::from_ref(entry);
4896 }
4897 let result = HTMLCollection::by_qualified_name(
4898 &self.window,
4899 self.upcast(),
4900 qualified_name.clone(),
4901 can_gc,
4902 );
4903 self.tag_map
4904 .borrow_mut()
4905 .insert(qualified_name, Dom::from_ref(&*result));
4906 result
4907 }
4908
4909 fn GetElementsByTagNameNS(
4911 &self,
4912 maybe_ns: Option<DOMString>,
4913 tag_name: DOMString,
4914 can_gc: CanGc,
4915 ) -> DomRoot<HTMLCollection> {
4916 let ns = namespace_from_domstring(maybe_ns);
4917 let local = LocalName::from(tag_name);
4918 let qname = QualName::new(None, ns, local);
4919 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4920 return DomRoot::from_ref(collection);
4921 }
4922 let result =
4923 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4924 self.tagns_map
4925 .borrow_mut()
4926 .insert(qname, Dom::from_ref(&*result));
4927 result
4928 }
4929
4930 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4932 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4933 .map(Atom::from)
4934 .collect();
4935 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4936 return DomRoot::from_ref(collection);
4937 }
4938 let result = HTMLCollection::by_atomic_class_name(
4939 &self.window,
4940 self.upcast(),
4941 class_atoms.clone(),
4942 can_gc,
4943 );
4944 self.classes_map
4945 .borrow_mut()
4946 .insert(class_atoms, Dom::from_ref(&*result));
4947 result
4948 }
4949
4950 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4952 self.get_element_by_id(&Atom::from(id))
4953 }
4954
4955 fn CreateElement(
4957 &self,
4958 mut local_name: DOMString,
4959 options: StringOrElementCreationOptions,
4960 can_gc: CanGc,
4961 ) -> Fallible<DomRoot<Element>> {
4962 if !is_valid_element_local_name(&local_name.str()) {
4965 debug!("Not a valid element name");
4966 return Err(Error::InvalidCharacter(None));
4967 }
4968
4969 if self.is_html_document {
4970 local_name.make_ascii_lowercase();
4971 }
4972
4973 let ns = if self.is_html_document || self.is_xhtml_document() {
4974 ns!(html)
4975 } else {
4976 ns!()
4977 };
4978
4979 let name = QualName::new(None, ns, LocalName::from(local_name));
4980 let is = match options {
4981 StringOrElementCreationOptions::String(_) => None,
4982 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4983 options.is.as_ref().map(LocalName::from)
4984 },
4985 };
4986 Ok(Element::create(
4987 name,
4988 is,
4989 self,
4990 ElementCreator::ScriptCreated,
4991 CustomElementCreationMode::Synchronous,
4992 None,
4993 can_gc,
4994 ))
4995 }
4996
4997 fn CreateElementNS(
4999 &self,
5000 namespace: Option<DOMString>,
5001 qualified_name: DOMString,
5002 options: StringOrElementCreationOptions,
5003 can_gc: CanGc,
5004 ) -> Fallible<DomRoot<Element>> {
5005 let context = domname::Context::Element;
5008 let (namespace, prefix, local_name) =
5009 domname::validate_and_extract(namespace, &qualified_name, context)?;
5010
5011 let name = QualName::new(prefix, namespace, local_name);
5014 let is = match options {
5015 StringOrElementCreationOptions::String(_) => None,
5016 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5017 options.is.as_ref().map(LocalName::from)
5018 },
5019 };
5020
5021 Ok(Element::create(
5023 name,
5024 is,
5025 self,
5026 ElementCreator::ScriptCreated,
5027 CustomElementCreationMode::Synchronous,
5028 None,
5029 can_gc,
5030 ))
5031 }
5032
5033 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5035 if !is_valid_attribute_local_name(&local_name.str()) {
5038 debug!("Not a valid attribute name");
5039 return Err(Error::InvalidCharacter(None));
5040 }
5041 if self.is_html_document {
5042 local_name.make_ascii_lowercase();
5043 }
5044 let name = LocalName::from(local_name);
5045 let value = AttrValue::String("".to_owned());
5046
5047 Ok(Attr::new(
5048 self,
5049 name.clone(),
5050 value,
5051 name,
5052 ns!(),
5053 None,
5054 None,
5055 can_gc,
5056 ))
5057 }
5058
5059 fn CreateAttributeNS(
5061 &self,
5062 namespace: Option<DOMString>,
5063 qualified_name: DOMString,
5064 can_gc: CanGc,
5065 ) -> Fallible<DomRoot<Attr>> {
5066 let context = domname::Context::Attribute;
5069 let (namespace, prefix, local_name) =
5070 domname::validate_and_extract(namespace, &qualified_name, context)?;
5071 let value = AttrValue::String("".to_owned());
5072 let qualified_name = LocalName::from(qualified_name);
5073 Ok(Attr::new(
5074 self,
5075 local_name,
5076 value,
5077 qualified_name,
5078 namespace,
5079 prefix,
5080 None,
5081 can_gc,
5082 ))
5083 }
5084
5085 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5087 DocumentFragment::new(self, can_gc)
5088 }
5089
5090 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5092 Text::new(data, self, can_gc)
5093 }
5094
5095 fn CreateCDATASection(
5097 &self,
5098 data: DOMString,
5099 can_gc: CanGc,
5100 ) -> Fallible<DomRoot<CDATASection>> {
5101 if self.is_html_document {
5103 return Err(Error::NotSupported);
5104 }
5105
5106 if data.contains("]]>") {
5108 return Err(Error::InvalidCharacter(None));
5109 }
5110
5111 Ok(CDATASection::new(data, self, can_gc))
5113 }
5114
5115 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5117 Comment::new(data, self, None, can_gc)
5118 }
5119
5120 fn CreateProcessingInstruction(
5122 &self,
5123 target: DOMString,
5124 data: DOMString,
5125 can_gc: CanGc,
5126 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5127 if !matches_name_production(&target.str()) {
5129 return Err(Error::InvalidCharacter(None));
5130 }
5131
5132 if data.contains("?>") {
5134 return Err(Error::InvalidCharacter(None));
5135 }
5136
5137 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5139 }
5140
5141 fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5143 if node.is::<Document>() || node.is::<ShadowRoot>() {
5145 return Err(Error::NotSupported);
5146 }
5147
5148 let clone_children = if deep {
5150 CloneChildrenFlag::CloneChildren
5151 } else {
5152 CloneChildrenFlag::DoNotCloneChildren
5153 };
5154
5155 Ok(Node::clone(node, Some(self), clone_children, can_gc))
5156 }
5157
5158 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5160 if node.is::<Document>() {
5162 return Err(Error::NotSupported);
5163 }
5164
5165 if node.is::<ShadowRoot>() {
5167 return Err(Error::HierarchyRequest);
5168 }
5169
5170 Node::adopt(node, self, can_gc);
5172
5173 Ok(DomRoot::from_ref(node))
5175 }
5176
5177 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5179 interface.make_ascii_lowercase();
5180 match &*interface.str() {
5181 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5182 &self.window,
5183 can_gc,
5184 ))),
5185 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5186 CompositionEvent::new_uninitialized(&self.window, can_gc),
5187 )),
5188 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5189 self.window.upcast(),
5190 can_gc,
5191 ))),
5192 "events" | "event" | "htmlevents" | "svgevents" => {
5195 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5196 },
5197 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5198 &self.window,
5199 can_gc,
5200 ))),
5201 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5202 &self.window,
5203 can_gc,
5204 ))),
5205 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5206 &self.window,
5207 can_gc,
5208 ))),
5209 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5210 self.window.upcast(),
5211 can_gc,
5212 ))),
5213 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5214 &self.window,
5215 can_gc,
5216 ))),
5217 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5218 &self.window,
5219 "".into(),
5220 can_gc,
5221 ))),
5222 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5223 &self.window,
5224 &TouchList::new(&self.window, &[], can_gc),
5225 &TouchList::new(&self.window, &[], can_gc),
5226 &TouchList::new(&self.window, &[], can_gc),
5227 can_gc,
5228 ))),
5229 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5230 &self.window,
5231 can_gc,
5232 ))),
5233 _ => Err(Error::NotSupported),
5234 }
5235 }
5236
5237 fn LastModified(&self) -> DOMString {
5239 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5240 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5246 }))
5247 }
5248
5249 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5251 Range::new_with_doc(self, None, can_gc)
5252 }
5253
5254 fn CreateNodeIterator(
5256 &self,
5257 root: &Node,
5258 what_to_show: u32,
5259 filter: Option<Rc<NodeFilter>>,
5260 can_gc: CanGc,
5261 ) -> DomRoot<NodeIterator> {
5262 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5263 }
5264
5265 fn CreateTreeWalker(
5267 &self,
5268 root: &Node,
5269 what_to_show: u32,
5270 filter: Option<Rc<NodeFilter>>,
5271 ) -> DomRoot<TreeWalker> {
5272 TreeWalker::new(self, root, what_to_show, filter)
5273 }
5274
5275 fn Title(&self) -> DOMString {
5277 self.title().unwrap_or_else(|| DOMString::from(""))
5278 }
5279
5280 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5282 let root = match self.GetDocumentElement() {
5283 Some(root) => root,
5284 None => return,
5285 };
5286
5287 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5288 let elem = root.upcast::<Node>().child_elements().find(|node| {
5289 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5290 });
5291 match elem {
5292 Some(elem) => DomRoot::upcast::<Node>(elem),
5293 None => {
5294 let name = QualName::new(None, ns!(svg), local_name!("title"));
5295 let elem = Element::create(
5296 name,
5297 None,
5298 self,
5299 ElementCreator::ScriptCreated,
5300 CustomElementCreationMode::Synchronous,
5301 None,
5302 can_gc,
5303 );
5304 let parent = root.upcast::<Node>();
5305 let child = elem.upcast::<Node>();
5306 parent
5307 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5308 .unwrap()
5309 },
5310 }
5311 } else if root.namespace() == &ns!(html) {
5312 let elem = root
5313 .upcast::<Node>()
5314 .traverse_preorder(ShadowIncluding::No)
5315 .find(|node| node.is::<HTMLTitleElement>());
5316 match elem {
5317 Some(elem) => elem,
5318 None => match self.GetHead() {
5319 Some(head) => {
5320 let name = QualName::new(None, ns!(html), local_name!("title"));
5321 let elem = Element::create(
5322 name,
5323 None,
5324 self,
5325 ElementCreator::ScriptCreated,
5326 CustomElementCreationMode::Synchronous,
5327 None,
5328 can_gc,
5329 );
5330 head.upcast::<Node>()
5331 .AppendChild(elem.upcast(), can_gc)
5332 .unwrap()
5333 },
5334 None => return,
5335 },
5336 }
5337 } else {
5338 return;
5339 };
5340
5341 node.set_text_content_for_element(Some(title), can_gc);
5342 }
5343
5344 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5346 self.get_html_element().and_then(|root| {
5347 root.upcast::<Node>()
5348 .children()
5349 .filter_map(DomRoot::downcast)
5350 .next()
5351 })
5352 }
5353
5354 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5356 self.current_script.get()
5357 }
5358
5359 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5361 self.get_html_element().and_then(|root| {
5362 let node = root.upcast::<Node>();
5363 node.children()
5364 .find(|child| {
5365 matches!(
5366 child.type_id(),
5367 NodeTypeId::Element(ElementTypeId::HTMLElement(
5368 HTMLElementTypeId::HTMLBodyElement,
5369 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5370 HTMLElementTypeId::HTMLFrameSetElement,
5371 ))
5372 )
5373 })
5374 .map(|node| DomRoot::downcast(node).unwrap())
5375 })
5376 }
5377
5378 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5380 let new_body = match new_body {
5382 Some(new_body) => new_body,
5383 None => return Err(Error::HierarchyRequest),
5384 };
5385
5386 let node = new_body.upcast::<Node>();
5387 match node.type_id() {
5388 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5389 NodeTypeId::Element(ElementTypeId::HTMLElement(
5390 HTMLElementTypeId::HTMLFrameSetElement,
5391 )) => {},
5392 _ => return Err(Error::HierarchyRequest),
5393 }
5394
5395 let old_body = self.GetBody();
5397 if old_body.as_deref() == Some(new_body) {
5398 return Ok(());
5399 }
5400
5401 match (self.GetDocumentElement(), &old_body) {
5402 (Some(ref root), Some(child)) => {
5404 let root = root.upcast::<Node>();
5405 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5406 .unwrap();
5407 },
5408
5409 (None, _) => return Err(Error::HierarchyRequest),
5411
5412 (Some(ref root), &None) => {
5414 let root = root.upcast::<Node>();
5415 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5416 },
5417 }
5418 Ok(())
5419 }
5420
5421 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5423 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5424 }
5425
5426 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5428 self.images.or_init(|| {
5429 HTMLCollection::new_with_filter_fn(
5430 &self.window,
5431 self.upcast(),
5432 |element, _| element.is::<HTMLImageElement>(),
5433 can_gc,
5434 )
5435 })
5436 }
5437
5438 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5440 self.embeds.or_init(|| {
5441 HTMLCollection::new_with_filter_fn(
5442 &self.window,
5443 self.upcast(),
5444 |element, _| element.is::<HTMLEmbedElement>(),
5445 can_gc,
5446 )
5447 })
5448 }
5449
5450 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5452 self.Embeds(can_gc)
5453 }
5454
5455 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5457 self.links.or_init(|| {
5458 HTMLCollection::new_with_filter_fn(
5459 &self.window,
5460 self.upcast(),
5461 |element, _| {
5462 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5463 element.has_attribute(&local_name!("href"))
5464 },
5465 can_gc,
5466 )
5467 })
5468 }
5469
5470 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5472 self.forms.or_init(|| {
5473 HTMLCollection::new_with_filter_fn(
5474 &self.window,
5475 self.upcast(),
5476 |element, _| element.is::<HTMLFormElement>(),
5477 can_gc,
5478 )
5479 })
5480 }
5481
5482 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5484 self.scripts.or_init(|| {
5485 HTMLCollection::new_with_filter_fn(
5486 &self.window,
5487 self.upcast(),
5488 |element, _| element.is::<HTMLScriptElement>(),
5489 can_gc,
5490 )
5491 })
5492 }
5493
5494 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5496 self.anchors.or_init(|| {
5497 HTMLCollection::new_with_filter_fn(
5498 &self.window,
5499 self.upcast(),
5500 |element, _| {
5501 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5502 },
5503 can_gc,
5504 )
5505 })
5506 }
5507
5508 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5510 self.applets
5511 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5512 }
5513
5514 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5516 if self.is_fully_active() {
5517 Some(self.window.Location())
5518 } else {
5519 None
5520 }
5521 }
5522
5523 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5525 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5526 }
5527
5528 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5530 self.upcast::<Node>().child_elements().next()
5531 }
5532
5533 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5535 self.upcast::<Node>()
5536 .rev_children()
5537 .filter_map(DomRoot::downcast)
5538 .next()
5539 }
5540
5541 fn ChildElementCount(&self) -> u32 {
5543 self.upcast::<Node>().child_elements().count() as u32
5544 }
5545
5546 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5548 self.upcast::<Node>().prepend(nodes, can_gc)
5549 }
5550
5551 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5553 self.upcast::<Node>().append(nodes, can_gc)
5554 }
5555
5556 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5558 self.upcast::<Node>().replace_children(nodes, can_gc)
5559 }
5560
5561 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5563 let root = self.upcast::<Node>();
5564 root.query_selector(selectors)
5565 }
5566
5567 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5569 let root = self.upcast::<Node>();
5570 root.query_selector_all(selectors)
5571 }
5572
5573 fn ReadyState(&self) -> DocumentReadyState {
5575 self.ready_state.get()
5576 }
5577
5578 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5580 if self.has_browsing_context {
5581 Some(DomRoot::from_ref(&*self.window))
5582 } else {
5583 None
5584 }
5585 }
5586
5587 fn GetCookie(&self) -> Fallible<DOMString> {
5589 if self.is_cookie_averse() {
5590 return Ok(DOMString::new());
5591 }
5592
5593 if !self.origin.is_tuple() {
5594 return Err(Error::Security);
5595 }
5596
5597 let url = self.url();
5598 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5599 let _ = self
5600 .window
5601 .as_global_scope()
5602 .resource_threads()
5603 .send(GetCookiesForUrl(url, tx, NonHTTP));
5604 let cookies = rx.recv().unwrap();
5605 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5606 }
5607
5608 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5610 if self.is_cookie_averse() {
5611 return Ok(());
5612 }
5613
5614 if !self.origin.is_tuple() {
5615 return Err(Error::Security);
5616 }
5617
5618 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5619 vec![cookie]
5620 } else {
5621 vec![]
5622 };
5623
5624 let _ = self
5625 .window
5626 .as_global_scope()
5627 .resource_threads()
5628 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5629 Ok(())
5630 }
5631
5632 fn BgColor(&self) -> DOMString {
5634 self.get_body_attribute(&local_name!("bgcolor"))
5635 }
5636
5637 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5639 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5640 }
5641
5642 fn FgColor(&self) -> DOMString {
5644 self.get_body_attribute(&local_name!("text"))
5645 }
5646
5647 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5649 self.set_body_attribute(&local_name!("text"), value, can_gc)
5650 }
5651
5652 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5654 if name.is_empty() {
5655 return None;
5656 }
5657 let name = Atom::from(name);
5658
5659 let elements_with_name = self.get_elements_with_name(&name);
5662 let name_iter = elements_with_name
5663 .iter()
5664 .filter(|elem| is_named_element_with_name_attribute(elem));
5665 let elements_with_id = self.get_elements_with_id(&name);
5666 let id_iter = elements_with_id
5667 .iter()
5668 .filter(|elem| is_named_element_with_id_attribute(elem));
5669 let mut elements = name_iter.chain(id_iter);
5670
5671 let first = elements.next()?;
5678 if elements.all(|other| first == other) {
5679 if let Some(nested_window_proxy) = first
5680 .downcast::<HTMLIFrameElement>()
5681 .and_then(|iframe| iframe.GetContentWindow())
5682 {
5683 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5684 }
5685
5686 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5688 }
5689
5690 #[derive(JSTraceable, MallocSizeOf)]
5693 struct DocumentNamedGetter {
5694 #[no_trace]
5695 name: Atom,
5696 }
5697 impl CollectionFilter for DocumentNamedGetter {
5698 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5699 let type_ = match elem.upcast::<Node>().type_id() {
5700 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5701 _ => return false,
5702 };
5703 match type_ {
5704 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5705 elem.get_name().as_ref() == Some(&self.name)
5706 },
5707 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5708 name == *self.name ||
5709 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5710 }),
5711 _ => false,
5715 }
5716 }
5717 }
5718 let collection = HTMLCollection::create(
5719 self.window(),
5720 self.upcast(),
5721 Box::new(DocumentNamedGetter { name }),
5722 can_gc,
5723 );
5724 Some(NamedPropertyValue::HTMLCollection(collection))
5725 }
5726
5727 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5729 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5730
5731 let name_map = self.name_map.borrow();
5732 for (name, elements) in &(name_map).0 {
5733 if name.is_empty() {
5734 continue;
5735 }
5736 let mut name_iter = elements
5737 .iter()
5738 .filter(|elem| is_named_element_with_name_attribute(elem));
5739 if let Some(first) = name_iter.next() {
5740 names_with_first_named_element_map.insert(name, first);
5741 }
5742 }
5743 let id_map = self.id_map.borrow();
5744 for (id, elements) in &(id_map).0 {
5745 if id.is_empty() {
5746 continue;
5747 }
5748 let mut id_iter = elements
5749 .iter()
5750 .filter(|elem| is_named_element_with_id_attribute(elem));
5751 if let Some(first) = id_iter.next() {
5752 match names_with_first_named_element_map.entry(id) {
5753 Vacant(entry) => drop(entry.insert(first)),
5754 Occupied(mut entry) => {
5755 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5756 *entry.get_mut() = first;
5757 }
5758 },
5759 }
5760 }
5761 }
5762
5763 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5764 names_with_first_named_element_map
5765 .iter()
5766 .map(|(k, v)| (*k, *v))
5767 .collect();
5768 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5769 if a.1 == b.1 {
5770 a.0.cmp(b.0)
5773 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5774 Ordering::Less
5775 } else {
5776 Ordering::Greater
5777 }
5778 });
5779
5780 names_with_first_named_element_vec
5781 .iter()
5782 .map(|(k, _v)| DOMString::from(&***k))
5783 .collect()
5784 }
5785
5786 fn Clear(&self) {
5788 }
5790
5791 fn CaptureEvents(&self) {
5793 }
5795
5796 fn ReleaseEvents(&self) {
5798 }
5800
5801 global_event_handlers!();
5803
5804 event_handler!(
5806 readystatechange,
5807 GetOnreadystatechange,
5808 SetOnreadystatechange
5809 );
5810
5811 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5813 self.document_or_shadow_root.element_from_point(
5814 x,
5815 y,
5816 self.GetDocumentElement(),
5817 self.has_browsing_context,
5818 )
5819 }
5820
5821 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5823 self.document_or_shadow_root.elements_from_point(
5824 x,
5825 y,
5826 self.GetDocumentElement(),
5827 self.has_browsing_context,
5828 )
5829 }
5830
5831 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5833 if self.quirks_mode() == QuirksMode::Quirks {
5835 if let Some(ref body) = self.GetBody() {
5837 let e = body.upcast::<Element>();
5838 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5842 return Some(DomRoot::from_ref(e));
5843 }
5844 }
5845
5846 return None;
5848 }
5849
5850 self.GetDocumentElement()
5853 }
5854
5855 fn Open(
5857 &self,
5858 _unused1: Option<DOMString>,
5859 _unused2: Option<DOMString>,
5860 can_gc: CanGc,
5861 ) -> Fallible<DomRoot<Document>> {
5862 if !self.is_html_document() {
5864 return Err(Error::InvalidState(None));
5865 }
5866
5867 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5869 return Err(Error::InvalidState(None));
5870 }
5871
5872 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5874
5875 if !self.origin.same_origin(&entry_responsible_document.origin) {
5877 return Err(Error::Security);
5878 }
5879
5880 if self
5882 .get_current_parser()
5883 .is_some_and(|parser| parser.is_active())
5884 {
5885 return Ok(DomRoot::from_ref(self));
5886 }
5887
5888 if self.is_prompting_or_unloading() {
5890 return Ok(DomRoot::from_ref(self));
5891 }
5892
5893 if self.active_parser_was_aborted.get() {
5895 return Ok(DomRoot::from_ref(self));
5896 }
5897
5898 self.window().set_navigation_start();
5902
5903 if self.has_browsing_context() {
5906 self.abort(can_gc);
5909 }
5910
5911 for node in self
5913 .upcast::<Node>()
5914 .traverse_preorder(ShadowIncluding::Yes)
5915 {
5916 node.upcast::<EventTarget>().remove_all_listeners();
5917 }
5918
5919 if self.window.Document() == DomRoot::from_ref(self) {
5921 self.window.upcast::<EventTarget>().remove_all_listeners();
5922 }
5923
5924 Node::replace_all(None, self.upcast::<Node>(), can_gc);
5926
5927 if self.is_fully_active() {
5934 let mut new_url = entry_responsible_document.url();
5936
5937 if entry_responsible_document != DomRoot::from_ref(self) {
5939 new_url.set_fragment(None);
5940 }
5941
5942 self.set_url(new_url);
5945 }
5946
5947 self.is_initial_about_blank.set(false);
5949
5950 self.set_quirks_mode(QuirksMode::NoQuirks);
5956
5957 let resource_threads = self.window.as_global_scope().resource_threads().clone();
5963 *self.loader.borrow_mut() =
5964 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
5965 ServoParser::parse_html_script_input(self, self.url());
5966
5967 self.ready_state.set(DocumentReadyState::Loading);
5973
5974 Ok(DomRoot::from_ref(self))
5976 }
5977
5978 fn Open_(
5980 &self,
5981 url: USVString,
5982 target: DOMString,
5983 features: DOMString,
5984 can_gc: CanGc,
5985 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
5986 self.browsing_context()
5987 .ok_or(Error::InvalidAccess)?
5988 .open(url, target, features, can_gc)
5989 }
5990
5991 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5993 self.write(text, false, "Document", "write", can_gc)
5996 }
5997
5998 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
6000 self.write(text, true, "Document", "writeln", can_gc)
6003 }
6004
6005 fn Close(&self, can_gc: CanGc) -> ErrorResult {
6007 if !self.is_html_document() {
6008 return Err(Error::InvalidState(None));
6010 }
6011
6012 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6014 return Err(Error::InvalidState(None));
6015 }
6016
6017 let parser = match self.get_current_parser() {
6018 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6019 _ => {
6020 return Ok(());
6022 },
6023 };
6024
6025 parser.close(can_gc);
6027
6028 Ok(())
6029 }
6030
6031 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6033
6034 event_handler!(
6036 fullscreenchange,
6037 GetOnfullscreenchange,
6038 SetOnfullscreenchange
6039 );
6040
6041 fn FullscreenEnabled(&self) -> bool {
6043 self.get_allow_fullscreen()
6044 }
6045
6046 fn Fullscreen(&self) -> bool {
6048 self.fullscreen_element.get().is_some()
6049 }
6050
6051 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6053 self.fullscreen_element.get()
6055 }
6056
6057 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6059 self.exit_fullscreen(can_gc)
6060 }
6061
6062 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6066 match self.media_controls.borrow().get(&*id.str()) {
6067 Some(m) => Ok(DomRoot::from_ref(m)),
6068 None => Err(Error::InvalidAccess),
6069 }
6070 }
6071
6072 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6074 if self.has_browsing_context {
6075 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6076 } else {
6077 None
6078 }
6079 }
6080
6081 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6083 self.fonts
6084 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6085 }
6086
6087 fn Hidden(&self) -> bool {
6089 self.visibility_state.get() == DocumentVisibilityState::Hidden
6090 }
6091
6092 fn VisibilityState(&self) -> DocumentVisibilityState {
6094 self.visibility_state.get()
6095 }
6096
6097 fn CreateExpression(
6098 &self,
6099 expression: DOMString,
6100 resolver: Option<Rc<XPathNSResolver>>,
6101 can_gc: CanGc,
6102 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6103 let global = self.global();
6104 let window = global.as_window();
6105 let evaluator = XPathEvaluator::new(window, None, can_gc);
6106 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateExpression(
6107 &*evaluator,
6108 expression,
6109 resolver,
6110 can_gc,
6111 )
6112 }
6113
6114 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6115 let global = self.global();
6116 let window = global.as_window();
6117 let evaluator = XPathEvaluator::new(window, None, can_gc);
6118 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6119 }
6120
6121 fn Evaluate(
6122 &self,
6123 expression: DOMString,
6124 context_node: &Node,
6125 resolver: Option<Rc<XPathNSResolver>>,
6126 type_: u16,
6127 result: Option<&super::types::XPathResult>,
6128 can_gc: CanGc,
6129 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6130 let global = self.global();
6131 let window = global.as_window();
6132 let evaluator = XPathEvaluator::new(window, None, can_gc);
6133 XPathEvaluatorMethods::<crate::DomTypeHolder>::Evaluate(
6134 &*evaluator,
6135 expression,
6136 context_node,
6137 resolver,
6138 type_,
6139 result,
6140 can_gc,
6141 )
6142 }
6143
6144 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6146 self.adopted_stylesheets_frozen_types.get_or_init(
6147 || {
6148 self.adopted_stylesheets
6149 .borrow()
6150 .clone()
6151 .iter()
6152 .map(|sheet| sheet.as_rooted())
6153 .collect()
6154 },
6155 context,
6156 retval,
6157 can_gc,
6158 );
6159 }
6160
6161 fn SetAdoptedStyleSheets(&self, context: JSContext, val: HandleValue) -> ErrorResult {
6163 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6164 context,
6165 self.adopted_stylesheets.borrow_mut().as_mut(),
6166 val,
6167 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6168 );
6169
6170 if result.is_ok() {
6172 self.adopted_stylesheets_frozen_types.clear()
6173 }
6174
6175 result
6176 }
6177}
6178
6179fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6180 if marker.get().is_none() {
6181 marker.set(Some(CrossProcessInstant::now()))
6182 }
6183}
6184
6185#[derive(Clone, Copy, PartialEq)]
6187pub(crate) enum FocusType {
6188 Element, Parent, }
6191
6192#[derive(Clone, Copy, PartialEq)]
6194pub enum FocusInitiator {
6195 Local,
6198 Remote,
6201}
6202
6203pub(crate) enum FocusEventType {
6205 Focus, Blur, }
6208
6209#[derive(JSTraceable, MallocSizeOf)]
6210pub(crate) enum AnimationFrameCallback {
6211 DevtoolsFramerateTick {
6212 actor_name: String,
6213 },
6214 FrameRequestCallback {
6215 #[conditional_malloc_size_of]
6216 callback: Rc<FrameRequestCallback>,
6217 },
6218}
6219
6220impl AnimationFrameCallback {
6221 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6222 match *self {
6223 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6224 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6225 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6226 devtools_sender.send(msg).unwrap();
6227 },
6228 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6229 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6232 },
6233 }
6234 }
6235}
6236
6237#[derive(Default, JSTraceable, MallocSizeOf)]
6238#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6239struct PendingInOrderScriptVec {
6240 scripts: DomRefCell<VecDeque<PendingScript>>,
6241}
6242
6243impl PendingInOrderScriptVec {
6244 fn is_empty(&self) -> bool {
6245 self.scripts.borrow().is_empty()
6246 }
6247
6248 fn push(&self, element: &HTMLScriptElement) {
6249 self.scripts
6250 .borrow_mut()
6251 .push_back(PendingScript::new(element));
6252 }
6253
6254 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6255 let mut scripts = self.scripts.borrow_mut();
6256 let entry = scripts
6257 .iter_mut()
6258 .find(|entry| &*entry.element == element)
6259 .unwrap();
6260 entry.loaded(result);
6261 }
6262
6263 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6264 let mut scripts = self.scripts.borrow_mut();
6265 let pair = scripts.front_mut()?.take_result()?;
6266 scripts.pop_front();
6267 Some(pair)
6268 }
6269
6270 fn clear(&self) {
6271 *self.scripts.borrow_mut() = Default::default();
6272 }
6273}
6274
6275#[derive(JSTraceable, MallocSizeOf)]
6276#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6277struct PendingScript {
6278 element: Dom<HTMLScriptElement>,
6279 load: Option<ScriptResult>,
6281}
6282
6283impl PendingScript {
6284 fn new(element: &HTMLScriptElement) -> Self {
6285 Self {
6286 element: Dom::from_ref(element),
6287 load: None,
6288 }
6289 }
6290
6291 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6292 Self {
6293 element: Dom::from_ref(element),
6294 load,
6295 }
6296 }
6297
6298 fn loaded(&mut self, result: ScriptResult) {
6299 assert!(self.load.is_none());
6300 self.load = Some(result);
6301 }
6302
6303 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6304 self.load
6305 .take()
6306 .map(|result| (DomRoot::from_ref(&*self.element), result))
6307 }
6308}
6309
6310fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6311 let type_ = match elem.upcast::<Node>().type_id() {
6312 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6313 _ => return false,
6314 };
6315 match type_ {
6316 HTMLElementTypeId::HTMLFormElement |
6317 HTMLElementTypeId::HTMLIFrameElement |
6318 HTMLElementTypeId::HTMLImageElement => true,
6319 _ => false,
6323 }
6324}
6325
6326fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6327 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6331}
6332
6333impl DocumentHelpers for Document {
6334 fn ensure_safe_to_run_script_or_layout(&self) {
6335 Document::ensure_safe_to_run_script_or_layout(self)
6336 }
6337}