1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use base::cross_process_instant::CrossProcessInstant;
17use base::generic_channel::GenericSend;
18use base::id::WebViewId;
19use base::{Epoch, generic_channel};
20use bitflags::bitflags;
21use chrono::Local;
22use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
23use content_security_policy::sandboxing_directive::SandboxingFlagSet;
24use content_security_policy::{CspList, PolicyDisposition};
25use cookie::Cookie;
26use data_url::mime::Mime;
27use devtools_traits::ScriptToDevtoolsControlMsg;
28use dom_struct::dom_struct;
29use embedder_traits::{
30 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
31 Image, LoadStatus,
32};
33use encoding_rs::{Encoding, UTF_8};
34use fonts::WebFontDocumentContext;
35use html5ever::{LocalName, Namespace, QualName, local_name, ns};
36use hyper_serde::Serde;
37use js::rust::{HandleObject, HandleValue, MutableHandleValue};
38use layout_api::{
39 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
40 TrustedNodeAddress,
41};
42use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
43use net_traits::CookieSource::NonHTTP;
44use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
45use net_traits::ReferrerPolicy;
46use net_traits::policy_container::PolicyContainer;
47use net_traits::pub_domains::is_pub_domain;
48use net_traits::request::{
49 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
50};
51use net_traits::response::HttpsState;
52use percent_encoding::percent_decode;
53use profile_traits::ipc as profile_ipc;
54use profile_traits::time::TimerMetadataFrameType;
55use regex::bytes::Regex;
56use rustc_hash::{FxBuildHasher, FxHashMap};
57use script_bindings::interfaces::DocumentHelpers;
58use script_bindings::script_runtime::JSContext;
59use script_traits::{DocumentActivity, ProgressiveWebMetricType};
60use servo_arc::Arc;
61use servo_config::pref;
62use servo_media::{ClientContextId, ServoMedia};
63use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
64use style::attr::AttrValue;
65use style::context::QuirksMode;
66use style::invalidation::element::restyle_hints::RestyleHint;
67use style::selector_parser::Snapshot;
68use style::shared_lock::SharedRwLock as StyleSharedRwLock;
69use style::str::{split_html_space_chars, str_join};
70use style::stylesheet_set::DocumentStylesheetSet;
71use style::stylesheets::{Origin, OriginSet, Stylesheet};
72use stylo_atoms::Atom;
73use url::{Host, Position};
74
75use crate::animation_timeline::AnimationTimeline;
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::attr::Attr;
79use crate::dom::beforeunloadevent::BeforeUnloadEvent;
80use crate::dom::bindings::callback::ExceptionHandling;
81use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
82use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
83use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
84 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
85};
86use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
87use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
88use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
90#[cfg(any(feature = "webxr", feature = "gamepad"))]
91use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
92use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
93use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
94use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
95use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
96use crate::dom::bindings::codegen::Bindings::WindowBinding::{
97 FrameRequestCallback, ScrollBehavior, WindowMethods,
98};
99use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
100use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
101use crate::dom::bindings::codegen::UnionTypes::{
102 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
103};
104use crate::dom::bindings::domname::{
105 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
106};
107use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
108use crate::dom::bindings::frozenarray::CachedFrozenArray;
109use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
110use crate::dom::bindings::num::Finite;
111use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
112use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
113use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
114use crate::dom::bindings::str::{DOMString, USVString};
115use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
116use crate::dom::bindings::weakref::DOMTracker;
117use crate::dom::bindings::xmlname::matches_name_production;
118use crate::dom::cdatasection::CDATASection;
119use crate::dom::comment::Comment;
120use crate::dom::compositionevent::CompositionEvent;
121use crate::dom::css::cssstylesheet::CSSStyleSheet;
122use crate::dom::css::fontfaceset::FontFaceSet;
123use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
124use crate::dom::customelementregistry::{
125 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
126};
127use crate::dom::customevent::CustomEvent;
128use crate::dom::document_embedder_controls::DocumentEmbedderControls;
129use crate::dom::document_event_handler::DocumentEventHandler;
130use crate::dom::documentfragment::DocumentFragment;
131use crate::dom::documentorshadowroot::{
132 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
133};
134use crate::dom::documenttype::DocumentType;
135use crate::dom::domimplementation::DOMImplementation;
136use crate::dom::element::{
137 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
138 ElementPerformFullscreenExit,
139};
140use crate::dom::event::{Event, EventBubbles, EventCancelable};
141use crate::dom::eventtarget::EventTarget;
142use crate::dom::execcommand::execcommands::ExecCommandsSupport;
143use crate::dom::focusevent::FocusEvent;
144use crate::dom::globalscope::GlobalScope;
145use crate::dom::hashchangeevent::HashChangeEvent;
146use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
147use crate::dom::html::htmlareaelement::HTMLAreaElement;
148use crate::dom::html::htmlbaseelement::HTMLBaseElement;
149use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
150use crate::dom::html::htmlelement::HTMLElement;
151use crate::dom::html::htmlembedelement::HTMLEmbedElement;
152use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
153use crate::dom::html::htmlheadelement::HTMLHeadElement;
154use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
155use crate::dom::html::htmliframeelement::HTMLIFrameElement;
156use crate::dom::html::htmlimageelement::HTMLImageElement;
157use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
158use crate::dom::html::htmltitleelement::HTMLTitleElement;
159use crate::dom::htmldetailselement::DetailsNameGroups;
160use crate::dom::intersectionobserver::IntersectionObserver;
161use crate::dom::keyboardevent::KeyboardEvent;
162use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
163use crate::dom::location::Location;
164use crate::dom::messageevent::MessageEvent;
165use crate::dom::mouseevent::MouseEvent;
166use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
167use crate::dom::nodeiterator::NodeIterator;
168use crate::dom::nodelist::NodeList;
169use crate::dom::pagetransitionevent::PageTransitionEvent;
170use crate::dom::performance::performanceentry::PerformanceEntry;
171use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
172use crate::dom::processinginstruction::ProcessingInstruction;
173use crate::dom::promise::Promise;
174use crate::dom::range::Range;
175use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
176use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
177use crate::dom::selection::Selection;
178use crate::dom::servoparser::ServoParser;
179use crate::dom::shadowroot::ShadowRoot;
180use crate::dom::storageevent::StorageEvent;
181use crate::dom::text::Text;
182use crate::dom::touchevent::TouchEvent as DomTouchEvent;
183use crate::dom::touchlist::TouchList;
184use crate::dom::treewalker::TreeWalker;
185use crate::dom::trustedhtml::TrustedHTML;
186use crate::dom::types::{HTMLCanvasElement, HTMLDialogElement, VisibilityStateEntry};
187use crate::dom::uievent::UIEvent;
188use crate::dom::virtualmethods::vtable_for;
189use crate::dom::websocket::WebSocket;
190use crate::dom::window::Window;
191use crate::dom::windowproxy::WindowProxy;
192use crate::dom::xpathevaluator::XPathEvaluator;
193use crate::dom::xpathexpression::XPathExpression;
194use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
195use crate::iframe_collection::IFrameCollection;
196use crate::image_animation::ImageAnimationManager;
197use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
198use crate::mime::{APPLICATION, CHARSET};
199use crate::network_listener::{FetchResponseListener, NetworkListener};
200use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
201use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
202use crate::script_thread::ScriptThread;
203use crate::stylesheet_set::StylesheetSetRef;
204use crate::task::NonSendTaskBox;
205use crate::task_source::TaskSourceName;
206use crate::timers::OneshotTimerCallback;
207use crate::xpath::parse_expression;
208
209#[derive(Clone, Copy, PartialEq)]
210pub(crate) enum FireMouseEventType {
211 Move,
212 Over,
213 Out,
214 Enter,
215 Leave,
216}
217
218impl FireMouseEventType {
219 pub(crate) fn as_str(&self) -> &str {
220 match *self {
221 FireMouseEventType::Move => "mousemove",
222 FireMouseEventType::Over => "mouseover",
223 FireMouseEventType::Out => "mouseout",
224 FireMouseEventType::Enter => "mouseenter",
225 FireMouseEventType::Leave => "mouseleave",
226 }
227 }
228}
229
230#[derive(JSTraceable, MallocSizeOf)]
231pub(crate) struct RefreshRedirectDue {
232 #[no_trace]
233 pub(crate) url: ServoUrl,
234 #[ignore_malloc_size_of = "non-owning"]
235 pub(crate) window: DomRoot<Window>,
236}
237impl RefreshRedirectDue {
238 pub(crate) fn invoke(self, can_gc: CanGc) {
240 let load_data = self
250 .window
251 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
252 self.window
253 .load_url(NavigationHistoryBehavior::Replace, false, load_data, can_gc);
254 }
255}
256
257#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
258pub(crate) enum IsHTMLDocument {
259 HTMLDocument,
260 NonHTMLDocument,
261}
262
263#[derive(JSTraceable, MallocSizeOf)]
264#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
265struct FocusTransaction {
266 element: Option<Dom<Element>>,
268 has_focus: bool,
270 focus_options: FocusOptions,
272}
273
274#[derive(JSTraceable, MallocSizeOf)]
276pub(crate) enum DeclarativeRefresh {
277 PendingLoad {
278 #[no_trace]
279 url: ServoUrl,
280 time: u64,
281 },
282 CreatedAfterLoad,
283}
284
285#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
288pub(crate) struct RenderingUpdateReason(u8);
289
290bitflags! {
291 impl RenderingUpdateReason: u8 {
292 const ResizeObserverStartedObservingTarget = 1 << 0;
295 const IntersectionObserverStartedObservingTarget = 1 << 1;
298 const FontReadyPromiseFulfilled = 1 << 2;
302 }
303}
304
305#[dom_struct]
307pub(crate) struct Document {
308 node: Node,
309 document_or_shadow_root: DocumentOrShadowRoot,
310 window: Dom<Window>,
311 implementation: MutNullableDom<DOMImplementation>,
312 #[ignore_malloc_size_of = "type from external crate"]
313 #[no_trace]
314 content_type: Mime,
315 last_modified: Option<String>,
316 #[no_trace]
317 encoding: Cell<&'static Encoding>,
318 has_browsing_context: bool,
319 is_html_document: bool,
320 #[no_trace]
321 activity: Cell<DocumentActivity>,
322 #[no_trace]
324 url: DomRefCell<ServoUrl>,
325 #[no_trace]
327 about_base_url: DomRefCell<Option<ServoUrl>>,
328 #[ignore_malloc_size_of = "defined in selectors"]
329 #[no_trace]
330 quirks_mode: Cell<QuirksMode>,
331 event_handler: DocumentEventHandler,
333 embedder_controls: DocumentEmbedderControls,
335 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
338 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
339 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
340 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
341 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
342 images: MutNullableDom<HTMLCollection>,
343 embeds: MutNullableDom<HTMLCollection>,
344 links: MutNullableDom<HTMLCollection>,
345 forms: MutNullableDom<HTMLCollection>,
346 scripts: MutNullableDom<HTMLCollection>,
347 anchors: MutNullableDom<HTMLCollection>,
348 applets: MutNullableDom<HTMLCollection>,
349 iframes: RefCell<IFrameCollection>,
351 #[no_trace]
354 style_shared_lock: StyleSharedRwLock,
355 #[custom_trace]
357 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
358 stylesheet_list: MutNullableDom<StyleSheetList>,
359 ready_state: Cell<DocumentReadyState>,
360 domcontentloaded_dispatched: Cell<bool>,
362 focus_transaction: DomRefCell<Option<FocusTransaction>>,
364 focused: MutNullableDom<Element>,
366 #[no_trace]
368 focus_sequence: Cell<FocusSequenceNumber>,
369 has_focus: Cell<bool>,
373 current_script: MutNullableDom<HTMLScriptElement>,
375 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
377 script_blocking_stylesheets_count: Cell<u32>,
379 render_blocking_element_count: Cell<u32>,
382 deferred_scripts: PendingInOrderScriptVec,
384 asap_in_order_scripts_list: PendingInOrderScriptVec,
386 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
388 animation_frame_ident: Cell<u32>,
391 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
394 running_animation_callbacks: Cell<bool>,
399 loader: DomRefCell<DocumentLoader>,
401 current_parser: MutNullableDom<ServoParser>,
403 base_element: MutNullableDom<HTMLBaseElement>,
405 target_base_element: MutNullableDom<HTMLBaseElement>,
407 appropriate_template_contents_owner_document: MutNullableDom<Document>,
410 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
413 #[no_trace]
417 needs_restyle: Cell<RestyleReason>,
418 #[no_trace]
421 dom_interactive: Cell<Option<CrossProcessInstant>>,
422 #[no_trace]
423 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
424 #[no_trace]
425 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
426 #[no_trace]
427 dom_complete: Cell<Option<CrossProcessInstant>>,
428 #[no_trace]
429 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
430 #[no_trace]
431 load_event_start: Cell<Option<CrossProcessInstant>>,
432 #[no_trace]
433 load_event_end: Cell<Option<CrossProcessInstant>>,
434 #[no_trace]
435 unload_event_start: Cell<Option<CrossProcessInstant>>,
436 #[no_trace]
437 unload_event_end: Cell<Option<CrossProcessInstant>>,
438 #[no_trace]
440 https_state: Cell<HttpsState>,
441 #[no_trace]
443 origin: MutableOrigin,
444 referrer: Option<String>,
446 target_element: MutNullableDom<Element>,
448 #[no_trace]
450 policy_container: DomRefCell<PolicyContainer>,
451 #[no_trace]
453 preloaded_resources: DomRefCell<PreloadedResources>,
454 ignore_destructive_writes_counter: Cell<u32>,
456 ignore_opens_during_unload_counter: Cell<u32>,
458 spurious_animation_frames: Cell<u8>,
462
463 dom_count: Cell<u32>,
469 fullscreen_element: MutNullableDom<Element>,
471 form_id_listener_map:
478 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
479 #[no_trace]
480 interactive_time: DomRefCell<ProgressiveWebMetrics>,
481 #[no_trace]
482 tti_window: DomRefCell<InteractiveWindow>,
483 canceller: FetchCanceller,
485 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
487 page_showing: Cell<bool>,
489 salvageable: Cell<bool>,
491 active_parser_was_aborted: Cell<bool>,
493 fired_unload: Cell<bool>,
495 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
497 redirect_count: Cell<u16>,
499 script_and_layout_blockers: Cell<u32>,
501 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
503 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
504 completely_loaded: Cell<bool>,
506 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
508 shadow_roots_styles_changed: Cell<bool>,
510 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
516 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
519 has_pending_animated_image_update: Cell<bool>,
521 selection: MutNullableDom<Selection>,
523 animation_timeline: DomRefCell<AnimationTimeline>,
526 animations: Animations,
528 image_animation_manager: DomRefCell<ImageAnimationManager>,
530 dirty_root: MutNullableDom<Element>,
532 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
534 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
543 fonts: MutNullableDom<FontFaceSet>,
546 visibility_state: Cell<DocumentVisibilityState>,
548 status_code: Option<u16>,
550 is_initial_about_blank: Cell<bool>,
552 allow_declarative_shadow_roots: Cell<bool>,
554 #[no_trace]
556 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
557 has_trustworthy_ancestor_origin: Cell<bool>,
559 intersection_observer_task_queued: Cell<bool>,
561 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
573 highlighted_dom_node: MutNullableDom<Node>,
575 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
578 #[ignore_malloc_size_of = "mozjs"]
580 adopted_stylesheets_frozen_types: CachedFrozenArray,
581 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
583 rendering_update_reasons: Cell<RenderingUpdateReason>,
585 waiting_on_canvas_image_updates: Cell<bool>,
589 #[no_trace]
597 current_rendering_epoch: Cell<Epoch>,
598 #[conditional_malloc_size_of]
600 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
601 #[no_trace]
602 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
604 #[no_trace]
605 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
612 #[no_trace]
614 favicon: RefCell<Option<Image>>,
615
616 websockets: DOMTracker<WebSocket>,
618
619 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
621
622 #[no_trace]
624 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
625
626 layout_animations_test_enabled: bool,
628}
629
630impl Document {
631 fn unloading_cleanup_steps(&self) {
633 if self.close_outstanding_websockets() {
636 self.salvageable.set(false);
638 }
639
640 if !self.salvageable.get() {
645 let global_scope = self.window.as_global_scope();
646
647 global_scope.close_event_sources();
649
650 let msg = ScriptToConstellationMessage::DiscardDocument;
655 let _ = global_scope.script_to_constellation_chan().send(msg);
656 }
657 }
658
659 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
660 self.websockets.track(websocket);
661 }
662
663 fn close_outstanding_websockets(&self) -> bool {
664 let mut closed_any_websocket = false;
665 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
666 if websocket.make_disappear() {
667 closed_any_websocket = true;
668 }
669 });
670 closed_any_websocket
671 }
672
673 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
674 debug_assert!(*node.owner_doc() == *self);
675 if !node.is_connected() {
676 return;
677 }
678
679 let parent = match node.parent_in_flat_tree() {
680 Some(parent) => parent,
681 None => {
682 let document_element = match self.GetDocumentElement() {
685 Some(element) => element,
686 None => return,
687 };
688 if let Some(dirty_root) = self.dirty_root.get() {
689 for ancestor in dirty_root
692 .upcast::<Node>()
693 .inclusive_ancestors_in_flat_tree()
694 {
695 if ancestor.is::<Element>() {
696 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
697 }
698 }
699 }
700 self.dirty_root.set(Some(&document_element));
701 return;
702 },
703 };
704
705 if parent.is::<Element>() {
706 if !parent.is_styled() {
707 return;
708 }
709
710 if parent.is_display_none() {
711 return;
712 }
713 }
714
715 let element_parent: DomRoot<Element>;
716 let element = match node.downcast::<Element>() {
717 Some(element) => element,
718 None => {
719 match DomRoot::downcast::<Element>(parent) {
722 Some(parent) => {
723 element_parent = parent;
724 &element_parent
725 },
726 None => {
727 return;
731 },
732 }
733 },
734 };
735
736 let dirty_root = match self.dirty_root.get() {
737 Some(root) if root.is_connected() => root,
738 _ => {
739 element
740 .upcast::<Node>()
741 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
742 self.dirty_root.set(Some(element));
743 return;
744 },
745 };
746
747 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
748 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
749 return;
750 }
751
752 if ancestor.is::<Element>() {
753 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
754 }
755 }
756
757 let new_dirty_root = element
758 .upcast::<Node>()
759 .common_ancestor_in_flat_tree(dirty_root.upcast())
760 .expect("Couldn't find common ancestor");
761
762 let mut has_dirty_descendants = true;
763 for ancestor in dirty_root
764 .upcast::<Node>()
765 .inclusive_ancestors_in_flat_tree()
766 {
767 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
768 has_dirty_descendants &= *ancestor != *new_dirty_root;
769 }
770
771 self.dirty_root
772 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
773 }
774
775 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
776 self.dirty_root.take()
777 }
778
779 #[inline]
780 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
781 self.loader.borrow()
782 }
783
784 #[inline]
785 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
786 self.loader.borrow_mut()
787 }
788
789 #[inline]
790 pub(crate) fn has_browsing_context(&self) -> bool {
791 self.has_browsing_context
792 }
793
794 #[inline]
796 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
797 if self.has_browsing_context {
798 self.window.undiscarded_window_proxy()
799 } else {
800 None
801 }
802 }
803
804 pub(crate) fn webview_id(&self) -> WebViewId {
805 self.window.webview_id()
806 }
807
808 #[inline]
809 pub(crate) fn window(&self) -> &Window {
810 &self.window
811 }
812
813 #[inline]
814 pub(crate) fn is_html_document(&self) -> bool {
815 self.is_html_document
816 }
817
818 pub(crate) fn is_xhtml_document(&self) -> bool {
819 self.content_type.matches(APPLICATION, "xhtml+xml")
820 }
821
822 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
823 self.https_state.set(https_state);
824 }
825
826 pub(crate) fn is_fully_active(&self) -> bool {
827 self.activity.get() == DocumentActivity::FullyActive
828 }
829
830 pub(crate) fn is_active(&self) -> bool {
831 self.activity.get() != DocumentActivity::Inactive
832 }
833
834 #[inline]
835 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
836 self.current_rendering_epoch.get()
837 }
838
839 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
840 assert!(self.has_browsing_context);
842 if activity == self.activity.get() {
843 return;
844 }
845
846 self.activity.set(activity);
848 let media = ServoMedia::get();
849 let pipeline_id = self.window().pipeline_id();
850 let client_context_id =
851 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
852
853 if activity != DocumentActivity::FullyActive {
854 self.window().suspend(can_gc);
855 media.suspend(&client_context_id);
856 return;
857 }
858
859 self.title_changed();
860 self.notify_embedder_favicon();
861 self.dirty_all_nodes();
862 self.window().resume(can_gc);
863 media.resume(&client_context_id);
864
865 if self.ready_state.get() != DocumentReadyState::Complete {
866 return;
867 }
868
869 let document = Trusted::new(self);
873 self.owner_global()
874 .task_manager()
875 .dom_manipulation_task_source()
876 .queue(task!(fire_pageshow_event: move || {
877 let document = document.root();
878 let window = document.window();
879 if document.page_showing.get() {
881 return;
882 }
883 document.page_showing.set(true);
885 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
887 let event = PageTransitionEvent::new(
890 window,
891 atom!("pageshow"),
892 false, false, true, CanGc::note(),
896 );
897 let event = event.upcast::<Event>();
898 event.set_trusted(true);
899 window.dispatch_event_with_target_override(event, CanGc::note());
900 }))
901 }
902
903 pub(crate) fn origin(&self) -> &MutableOrigin {
904 &self.origin
905 }
906
907 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
908 *self.protocol_handler_automation_mode.borrow_mut() = mode;
909 }
910
911 pub(crate) fn url(&self) -> ServoUrl {
913 self.url.borrow().clone()
914 }
915
916 pub(crate) fn set_url(&self, url: ServoUrl) {
917 *self.url.borrow_mut() = url;
918 }
919
920 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
921 self.about_base_url.borrow().clone()
922 }
923
924 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
925 *self.about_base_url.borrow_mut() = about_base_url;
926 }
927
928 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
930 let document_url = self.url();
931 if document_url.as_str() == "about:srcdoc" {
933 return self
936 .about_base_url()
937 .expect("about:srcdoc page should always have an about base URL");
938 }
939
940 if document_url.matches_about_blank() {
943 if let Some(about_base_url) = self.about_base_url() {
944 return about_base_url;
945 }
946 }
947
948 document_url
950 }
951
952 pub(crate) fn base_url(&self) -> ServoUrl {
954 match self.base_element() {
955 None => self.fallback_base_url(),
957 Some(base) => base.frozen_base_url(),
959 }
960 }
961
962 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
963 self.needs_restyle.set(self.needs_restyle.get() | reason)
964 }
965
966 pub(crate) fn clear_restyle_reasons(&self) {
967 self.needs_restyle.set(RestyleReason::empty());
968 }
969
970 pub(crate) fn restyle_reason(&self) -> RestyleReason {
971 let mut condition = self.needs_restyle.get();
972 if self.stylesheets.borrow().has_changed() {
973 condition.insert(RestyleReason::StylesheetsChanged);
974 }
975
976 if let Some(root) = self.GetDocumentElement() {
980 if root.upcast::<Node>().has_dirty_descendants() {
981 condition.insert(RestyleReason::DOMChanged);
982 }
983 }
984
985 if !self.pending_restyles.borrow().is_empty() {
986 condition.insert(RestyleReason::PendingRestyles);
987 }
988
989 condition
990 }
991
992 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
994 self.base_element.get()
995 }
996
997 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
999 self.target_base_element.get()
1000 }
1001
1002 pub(crate) fn refresh_base_element(&self) {
1004 if let Some(base_element) = self.base_element.get() {
1005 base_element.clear_frozen_base_url();
1006 }
1007 let new_base_element = self
1008 .upcast::<Node>()
1009 .traverse_preorder(ShadowIncluding::No)
1010 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1011 .find(|element| {
1012 element
1013 .upcast::<Element>()
1014 .has_attribute(&local_name!("href"))
1015 });
1016 if let Some(ref new_base_element) = new_base_element {
1017 new_base_element.set_frozen_base_url();
1018 }
1019 self.base_element.set(new_base_element.as_deref());
1020
1021 let new_target_base_element = self
1022 .upcast::<Node>()
1023 .traverse_preorder(ShadowIncluding::No)
1024 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1025 .next();
1026 self.target_base_element
1027 .set(new_target_base_element.as_deref());
1028 }
1029
1030 pub(crate) fn dom_count(&self) -> u32 {
1031 self.dom_count.get()
1032 }
1033
1034 pub(crate) fn increment_dom_count(&self) {
1038 self.dom_count.set(self.dom_count.get() + 1);
1039 }
1040
1041 pub(crate) fn decrement_dom_count(&self) {
1043 self.dom_count.set(self.dom_count.get() - 1);
1044 }
1045
1046 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1047 self.quirks_mode.get()
1048 }
1049
1050 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1051 let old_mode = self.quirks_mode.replace(new_mode);
1052
1053 if old_mode != new_mode {
1054 self.window.layout_mut().set_quirks_mode(new_mode);
1055 }
1056 }
1057
1058 pub(crate) fn encoding(&self) -> &'static Encoding {
1059 self.encoding.get()
1060 }
1061
1062 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1063 self.encoding.set(encoding);
1064 }
1065
1066 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1067 if node.is_connected() {
1068 node.note_dirty_descendants();
1069 }
1070
1071 node.dirty(NodeDamage::ContentOrHeritage);
1074 }
1075
1076 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1078 self.document_or_shadow_root
1079 .unregister_named_element(&self.id_map, to_unregister, &id);
1080 self.reset_form_owner_for_listeners(&id, can_gc);
1081 }
1082
1083 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1085 let root = self.GetDocumentElement().expect(
1086 "The element is in the document, so there must be a document \
1087 element.",
1088 );
1089 self.document_or_shadow_root.register_named_element(
1090 &self.id_map,
1091 element,
1092 &id,
1093 DomRoot::from_ref(root.upcast::<Node>()),
1094 );
1095 self.reset_form_owner_for_listeners(&id, can_gc);
1096 }
1097
1098 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1100 self.document_or_shadow_root
1101 .unregister_named_element(&self.name_map, to_unregister, &name);
1102 }
1103
1104 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1106 let root = self.GetDocumentElement().expect(
1107 "The element is in the document, so there must be a document \
1108 element.",
1109 );
1110 self.document_or_shadow_root.register_named_element(
1111 &self.name_map,
1112 element,
1113 &name,
1114 DomRoot::from_ref(root.upcast::<Node>()),
1115 );
1116 }
1117
1118 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1119 &self,
1120 id: DOMString,
1121 listener: &T,
1122 ) {
1123 let mut map = self.form_id_listener_map.borrow_mut();
1124 let listener = listener.to_element();
1125 let set = map.entry(Atom::from(id)).or_default();
1126 set.insert(Dom::from_ref(listener));
1127 }
1128
1129 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1130 &self,
1131 id: DOMString,
1132 listener: &T,
1133 ) {
1134 let mut map = self.form_id_listener_map.borrow_mut();
1135 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1136 entry
1137 .get_mut()
1138 .remove(&Dom::from_ref(listener.to_element()));
1139 if entry.get().is_empty() {
1140 entry.remove();
1141 }
1142 }
1143 }
1144
1145 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1147 self.get_element_by_id(&Atom::from(fragment))
1151 .or_else(|| self.get_anchor_by_name(fragment))
1155 }
1156
1157 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1160 if fragment.is_empty() {
1170 return Some(DomRoot::from_ref(self.upcast()));
1171 }
1172 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1174 {
1175 return Some(DomRoot::upcast(potential_indicated_element));
1177 }
1178 let fragment_bytes = percent_decode(fragment.as_bytes());
1180 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1182 return None;
1183 };
1184 if let Some(potential_indicated_element) =
1186 self.find_a_potential_indicated_element(&decoded_fragment)
1187 {
1188 return Some(DomRoot::upcast(potential_indicated_element));
1190 }
1191 if decoded_fragment.eq_ignore_ascii_case("top") {
1193 return Some(DomRoot::from_ref(self.upcast()));
1194 }
1195 None
1197 }
1198
1199 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str) {
1201 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1206 self.set_target_element(None);
1207 return;
1208 };
1209 if *indicated_part == *self.upcast() {
1211 self.set_target_element(None);
1213 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1218 return;
1220 }
1221 let Some(target) = indicated_part.downcast::<Element>() else {
1224 unreachable!("Indicated part should always be an element");
1226 };
1227 self.set_target_element(Some(target));
1229 target.scroll_into_view_with_options(
1233 ScrollBehavior::Auto,
1234 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1235 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1236 None,
1237 None,
1238 );
1239 }
1244
1245 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1246 let name = Atom::from(name);
1247 self.name_map.borrow().get(&name).and_then(|elements| {
1248 elements
1249 .iter()
1250 .find(|e| e.is::<HTMLAnchorElement>())
1251 .map(|e| DomRoot::from_ref(&**e))
1252 })
1253 }
1254
1255 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1257 match state {
1258 DocumentReadyState::Loading => {
1259 if self.window().is_top_level() {
1260 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1261 self.webview_id(),
1262 LoadStatus::Started,
1263 ));
1264 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1265 }
1266 },
1267 DocumentReadyState::Complete => {
1268 if self.window().is_top_level() {
1269 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1270 self.webview_id(),
1271 LoadStatus::Complete,
1272 ));
1273 }
1274 update_with_current_instant(&self.dom_complete);
1275 },
1276 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1277 };
1278
1279 self.ready_state.set(state);
1280
1281 self.upcast::<EventTarget>()
1282 .fire_event(atom!("readystatechange"), can_gc);
1283 }
1284
1285 pub(crate) fn scripting_enabled(&self) -> bool {
1288 self.has_browsing_context() &&
1291 !self.has_active_sandboxing_flag(
1295 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1296 )
1297 }
1298
1299 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1302 self.focused.get()
1303 }
1304
1305 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1310 self.focus_sequence.get()
1311 }
1312
1313 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1315 self.focus_sequence.set(FocusSequenceNumber(
1316 self.focus_sequence
1317 .get()
1318 .0
1319 .checked_add(1)
1320 .expect("too many focus messages have been sent"),
1321 ));
1322 self.focus_sequence.get()
1323 }
1324
1325 pub(crate) fn has_focus_transaction(&self) -> bool {
1326 self.focus_transaction.borrow().is_some()
1327 }
1328
1329 pub(crate) fn begin_focus_transaction(&self) {
1332 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1334 element: self.focused.get().as_deref().map(Dom::from_ref),
1335 has_focus: self.has_focus.get(),
1336 focus_options: FocusOptions {
1337 preventScroll: true,
1338 },
1339 });
1340 }
1341
1342 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1344 if Some(not_focusable) != self.focused.get().as_deref() {
1347 return;
1348 }
1349
1350 let implicit_transaction = self.focus_transaction.borrow().is_none();
1351
1352 if implicit_transaction {
1353 self.begin_focus_transaction();
1354 }
1355
1356 {
1359 let mut focus_transaction = self.focus_transaction.borrow_mut();
1360 focus_transaction.as_mut().unwrap().element = None;
1361 }
1362
1363 if implicit_transaction {
1364 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1365 }
1366 }
1367
1368 pub(crate) fn request_focus(
1371 &self,
1372 elem: Option<&Element>,
1373 focus_initiator: FocusInitiator,
1374 can_gc: CanGc,
1375 ) {
1376 self.request_focus_with_options(
1377 elem,
1378 focus_initiator,
1379 FocusOptions {
1380 preventScroll: true,
1381 },
1382 can_gc,
1383 );
1384 }
1385
1386 pub(crate) fn request_focus_with_options(
1392 &self,
1393 elem: Option<&Element>,
1394 focus_initiator: FocusInitiator,
1395 focus_options: FocusOptions,
1396 can_gc: CanGc,
1397 ) {
1398 if elem.is_some_and(|e| !e.is_focusable_area()) {
1401 return;
1402 }
1403
1404 let implicit_transaction = self.focus_transaction.borrow().is_none();
1405
1406 if implicit_transaction {
1407 self.begin_focus_transaction();
1408 }
1409
1410 {
1411 let mut focus_transaction = self.focus_transaction.borrow_mut();
1412 let focus_transaction = focus_transaction.as_mut().unwrap();
1413 focus_transaction.element = elem.map(Dom::from_ref);
1414 focus_transaction.has_focus = true;
1415 focus_transaction.focus_options = focus_options;
1416 }
1417
1418 if implicit_transaction {
1419 self.commit_focus_transaction(focus_initiator, can_gc);
1420 }
1421 }
1422
1423 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1427 if self.window().parent_info().is_none() {
1428 warn!("Top-level document cannot be unfocused");
1429 return;
1430 }
1431
1432 assert!(
1435 self.focus_transaction.borrow().is_none(),
1436 "there mustn't be an in-progress focus transaction at this point"
1437 );
1438
1439 self.begin_focus_transaction();
1441
1442 {
1444 let mut focus_transaction = self.focus_transaction.borrow_mut();
1445 focus_transaction.as_mut().unwrap().has_focus = false;
1446 }
1447
1448 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1450 }
1451
1452 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1455 let (mut new_focused, new_focus_state, prevent_scroll) = {
1456 let focus_transaction = self.focus_transaction.borrow();
1457 let focus_transaction = focus_transaction
1458 .as_ref()
1459 .expect("no focus transaction in progress");
1460 (
1461 focus_transaction
1462 .element
1463 .as_ref()
1464 .map(|e| DomRoot::from_ref(&**e)),
1465 focus_transaction.has_focus,
1466 focus_transaction.focus_options.preventScroll,
1467 )
1468 };
1469 *self.focus_transaction.borrow_mut() = None;
1470
1471 if !new_focus_state {
1472 if new_focused.take().is_some() {
1475 trace!(
1476 "Forgetting the document's focused area because the \
1477 document's container was removed from the top-level BC's \
1478 focus chain"
1479 );
1480 }
1481 }
1482
1483 let old_focused = self.focused.get();
1484 let old_focus_state = self.has_focus.get();
1485
1486 debug!(
1487 "Committing focus transaction: {:?} → {:?}",
1488 (&old_focused, old_focus_state),
1489 (&new_focused, new_focus_state),
1490 );
1491
1492 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1495 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1496
1497 let trace_focus_chain = |name, element, doc| {
1498 trace!(
1499 "{} local focus chain: {}",
1500 name,
1501 match (element, doc) {
1502 (Some(e), _) => format!("[{:?}, document]", e),
1503 (None, true) => "[document]".to_owned(),
1504 (None, false) => "[]".to_owned(),
1505 }
1506 );
1507 };
1508
1509 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1510 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1511
1512 if old_focused_filtered != new_focused_filtered {
1513 if let Some(elem) = &old_focused_filtered {
1514 let node = elem.upcast::<Node>();
1515 elem.set_focus_state(false);
1516 if node.is_connected() {
1518 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1519 }
1520 }
1521 }
1522
1523 if old_focus_state != new_focus_state && !new_focus_state {
1524 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1525 }
1526
1527 self.focused.set(new_focused.as_deref());
1528 self.has_focus.set(new_focus_state);
1529
1530 if old_focus_state != new_focus_state && new_focus_state {
1531 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1532 }
1533
1534 if old_focused_filtered != new_focused_filtered {
1535 if let Some(elem) = &new_focused_filtered {
1536 elem.set_focus_state(true);
1537 let node = elem.upcast::<Node>();
1538 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1540
1541 if !prevent_scroll {
1544 let scroll_axis = ScrollAxisState {
1547 position: ScrollLogicalPosition::Center,
1548 requirement: ScrollRequirement::IfNotVisible,
1549 };
1550
1551 elem.scroll_into_view_with_options(
1555 ScrollBehavior::Smooth,
1556 scroll_axis,
1557 scroll_axis,
1558 None,
1559 None,
1560 );
1561 }
1562 }
1563 }
1564
1565 if focus_initiator != FocusInitiator::Local {
1566 return;
1567 }
1568
1569 match (old_focus_state, new_focus_state) {
1572 (_, true) => {
1573 let child_browsing_context_id = new_focused
1594 .as_ref()
1595 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1596 .and_then(|iframe| iframe.browsing_context_id());
1597
1598 let sequence = self.increment_fetch_focus_sequence();
1599
1600 debug!(
1601 "Advertising the focus request to the constellation \
1602 with sequence number {} and child BC ID {}",
1603 sequence,
1604 child_browsing_context_id
1605 .as_ref()
1606 .map(|id| id as &dyn std::fmt::Display)
1607 .unwrap_or(&"(none)"),
1608 );
1609
1610 self.window()
1611 .send_to_constellation(ScriptToConstellationMessage::Focus(
1612 child_browsing_context_id,
1613 sequence,
1614 ));
1615 },
1616 (false, false) => {
1617 },
1620 (true, false) => {
1621 unreachable!(
1622 "Can't lose the document's focus without specifying \
1623 another one to focus"
1624 );
1625 },
1626 }
1627 }
1628
1629 pub(crate) fn title_changed(&self) {
1631 if self.browsing_context().is_some() {
1632 self.send_title_to_embedder();
1633 let title = String::from(self.Title());
1634 self.window
1635 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1636 self.window.pipeline_id(),
1637 title.clone(),
1638 ));
1639 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1640 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1641 self.window.pipeline_id(),
1642 title,
1643 ));
1644 }
1645 }
1646 }
1647
1648 fn title(&self) -> Option<DOMString> {
1652 let title = self.GetDocumentElement().and_then(|root| {
1653 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1654 root.upcast::<Node>()
1656 .child_elements()
1657 .find(|node| {
1658 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1659 })
1660 .map(DomRoot::upcast::<Node>)
1661 } else {
1662 root.upcast::<Node>()
1664 .traverse_preorder(ShadowIncluding::No)
1665 .find(|node| node.is::<HTMLTitleElement>())
1666 }
1667 });
1668
1669 title.map(|title| {
1670 let value = title.child_text_content();
1672 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1673 })
1674 }
1675
1676 pub(crate) fn send_title_to_embedder(&self) {
1678 let window = self.window();
1679 if window.is_top_level() {
1680 let title = self.title().map(String::from);
1681 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1682 }
1683 }
1684
1685 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1686 let window = self.window();
1687 window.send_to_embedder(msg);
1688 }
1689
1690 pub(crate) fn dirty_all_nodes(&self) {
1691 let root = match self.GetDocumentElement() {
1692 Some(root) => root,
1693 None => return,
1694 };
1695 for node in root
1696 .upcast::<Node>()
1697 .traverse_preorder(ShadowIncluding::Yes)
1698 {
1699 node.dirty(NodeDamage::Other)
1700 }
1701 }
1702
1703 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1705 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1717 for target in notify_list.iter() {
1718 if target.downcast::<Document>().is_some() {
1719 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1722 } else if target.downcast::<Element>().is_some() {
1723 target.fire_event(Atom::from("scroll"), can_gc);
1726 }
1727 }
1728
1729 }
1733
1734 pub(crate) fn handle_viewport_scroll_event(&self) {
1738 let target = self.upcast::<EventTarget>();
1747 if self
1748 .pending_scroll_event_targets
1749 .borrow()
1750 .iter()
1751 .any(|other_target| *other_target == target)
1752 {
1753 return;
1754 }
1755
1756 self.pending_scroll_event_targets
1759 .borrow_mut()
1760 .push(Dom::from_ref(target));
1761 }
1762
1763 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1767 let target = element.upcast::<EventTarget>();
1777 if self
1778 .pending_scroll_event_targets
1779 .borrow()
1780 .iter()
1781 .any(|other_target| *other_target == target)
1782 {
1783 return;
1784 }
1785
1786 self.pending_scroll_event_targets
1789 .borrow_mut()
1790 .push(Dom::from_ref(target));
1791 }
1792
1793 pub(crate) fn node_from_nodes_and_strings(
1795 &self,
1796 mut nodes: Vec<NodeOrString>,
1797 can_gc: CanGc,
1798 ) -> Fallible<DomRoot<Node>> {
1799 if nodes.len() == 1 {
1800 Ok(match nodes.pop().unwrap() {
1801 NodeOrString::Node(node) => node,
1802 NodeOrString::String(string) => {
1803 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1804 },
1805 })
1806 } else {
1807 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1808 for node in nodes {
1809 match node {
1810 NodeOrString::Node(node) => {
1811 fragment.AppendChild(&node, can_gc)?;
1812 },
1813 NodeOrString::String(string) => {
1814 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1815 fragment.AppendChild(&node, can_gc).unwrap();
1818 },
1819 }
1820 }
1821 Ok(fragment)
1822 }
1823 }
1824
1825 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1826 match self.GetBody() {
1827 Some(ref body) if body.is_body_element() => {
1828 body.upcast::<Element>().get_string_attribute(local_name)
1829 },
1830 _ => DOMString::new(),
1831 }
1832 }
1833
1834 pub(crate) fn set_body_attribute(
1835 &self,
1836 local_name: &LocalName,
1837 value: DOMString,
1838 can_gc: CanGc,
1839 ) {
1840 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1841 let body = body.upcast::<Element>();
1842 let value = body.parse_attribute(&ns!(), local_name, value);
1843 body.set_attribute(local_name, value, can_gc);
1844 }
1845 }
1846
1847 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1848 self.current_script.set(script);
1849 }
1850
1851 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1852 self.script_blocking_stylesheets_count.get()
1853 }
1854
1855 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1856 let count_cell = &self.script_blocking_stylesheets_count;
1857 count_cell.set(count_cell.get() + 1);
1858 }
1859
1860 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1861 let count_cell = &self.script_blocking_stylesheets_count;
1862 assert!(count_cell.get() > 0);
1863 count_cell.set(count_cell.get() - 1);
1864 }
1865
1866 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1867 self.render_blocking_element_count.get()
1868 }
1869
1870 pub(crate) fn increment_render_blocking_element_count(&self) {
1871 let count_cell = &self.render_blocking_element_count;
1872 count_cell.set(count_cell.get() + 1);
1873 }
1874
1875 pub(crate) fn decrement_render_blocking_element_count(&self) {
1876 let count_cell = &self.render_blocking_element_count;
1877 assert!(count_cell.get() > 0);
1878 count_cell.set(count_cell.get() - 1);
1879 }
1880
1881 pub(crate) fn invalidate_stylesheets(&self) {
1882 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1883
1884 if let Some(element) = self.GetDocumentElement() {
1888 element.upcast::<Node>().dirty(NodeDamage::Style);
1889 }
1890 }
1891
1892 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1895 !self.animation_frame_list.borrow().is_empty()
1896 }
1897
1898 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1900 let ident = self.animation_frame_ident.get() + 1;
1901 self.animation_frame_ident.set(ident);
1902
1903 let had_animation_frame_callbacks;
1904 {
1905 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1906 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1907 animation_frame_list.push_back((ident, Some(callback)));
1908 }
1909
1910 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1916 self.window().send_to_constellation(
1917 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1918 AnimationState::AnimationCallbacksPresent,
1919 ),
1920 );
1921 }
1922
1923 ident
1924 }
1925
1926 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1928 let mut list = self.animation_frame_list.borrow_mut();
1929 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1930 pair.1 = None;
1931 }
1932 }
1933
1934 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1936 let _realm = enter_realm(self);
1937
1938 self.running_animation_callbacks.set(true);
1939 let timing = self.global().performance().Now();
1940
1941 let num_callbacks = self.animation_frame_list.borrow().len();
1942 for _ in 0..num_callbacks {
1943 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1944 if let Some(callback) = maybe_callback {
1945 callback.call(self, *timing, can_gc);
1946 }
1947 }
1948 self.running_animation_callbacks.set(false);
1949
1950 if self.animation_frame_list.borrow().is_empty() {
1951 self.window().send_to_constellation(
1952 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1953 AnimationState::NoAnimationCallbacksPresent,
1954 ),
1955 );
1956 }
1957 }
1958
1959 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1960 self.policy_container.borrow()
1961 }
1962
1963 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1964 *self.policy_container.borrow_mut() = policy_container;
1965 }
1966
1967 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1968 self.policy_container.borrow_mut().set_csp_list(csp_list);
1969 }
1970
1971 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1972 self.policy_container.borrow().csp_list.clone()
1973 }
1974
1975 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1976 self.preloaded_resources.borrow()
1977 }
1978
1979 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1980 self.preloaded_resources
1981 .borrow_mut()
1982 .insert(key, preload_id);
1983 }
1984
1985 pub(crate) fn fetch<Listener: FetchResponseListener>(
1986 &self,
1987 load: LoadType,
1988 mut request: RequestBuilder,
1989 listener: Listener,
1990 ) {
1991 request = request
1992 .insecure_requests_policy(self.insecure_requests_policy())
1993 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1994 let callback = NetworkListener {
1995 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1996 task_source: self
1997 .owner_global()
1998 .task_manager()
1999 .networking_task_source()
2000 .into(),
2001 }
2002 .into_callback();
2003 self.loader_mut()
2004 .fetch_async_with_callback(load, request, callback);
2005 }
2006
2007 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
2008 &self,
2009 mut request: RequestBuilder,
2010 listener: Listener,
2011 ) {
2012 request = request
2013 .insecure_requests_policy(self.insecure_requests_policy())
2014 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2015 let callback = NetworkListener {
2016 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2017 task_source: self
2018 .owner_global()
2019 .task_manager()
2020 .networking_task_source()
2021 .into(),
2022 }
2023 .into_callback();
2024 self.loader_mut().fetch_async_background(request, callback);
2025 }
2026
2027 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
2029 match self.window().window_proxy().frame_element() {
2030 None => DomRoot::from_ref(self),
2033 Some(container) => container.owner_document().deferred_fetch_control_document(),
2035 }
2036 }
2037
2038 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
2040 let control_document = self.deferred_fetch_control_document();
2042 let navigable = control_document.window();
2044 let is_top_level = navigable.is_top_level();
2047 let deferred_fetch_allowed = true;
2051 let deferred_fetch_minimal_allowed = true;
2055 let mut quota = match is_top_level {
2057 true if !deferred_fetch_allowed => 0,
2059 true if !deferred_fetch_minimal_allowed => 640 * 1024,
2061 true => 512 * 1024,
2063 _ if deferred_fetch_allowed => 0,
2067 _ if deferred_fetch_minimal_allowed => 8 * 1024,
2071 _ => 0,
2073 } as isize;
2074 let mut quota_for_request_origin = 64 * 1024_isize;
2076 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
2085 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
2087 continue;
2088 }
2089 let request_length = deferred_fetch.request.total_request_length();
2091 quota -= request_length as isize;
2093 if deferred_fetch.request.url().origin() == origin {
2096 quota_for_request_origin -= request_length as isize;
2097 }
2098 }
2099 if quota <= 0 {
2101 return 0;
2102 }
2103 if quota < quota_for_request_origin {
2105 return quota;
2106 }
2107 quota_for_request_origin
2109 }
2110
2111 pub(crate) fn update_document_for_history_step_application(
2113 &self,
2114 old_url: &ServoUrl,
2115 new_url: &ServoUrl,
2116 ) {
2117 if old_url.as_url()[Position::BeforeFragment..] !=
2147 new_url.as_url()[Position::BeforeFragment..]
2148 {
2149 let window = Trusted::new(self.owner_window().deref());
2150 let old_url = old_url.to_string();
2151 let new_url = new_url.to_string();
2152 self.owner_global()
2153 .task_manager()
2154 .dom_manipulation_task_source()
2155 .queue(task!(hashchange_event: move || {
2156 let window = window.root();
2157 HashChangeEvent::new(
2158 &window,
2159 atom!("hashchange"),
2160 false,
2161 false,
2162 old_url,
2163 new_url,
2164 CanGc::note(),
2165 )
2166 .upcast::<Event>()
2167 .fire(window.upcast(), CanGc::note());
2168 }));
2169 }
2170 }
2171
2172 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
2175 debug!("Document got finish_load: {:?}", load);
2177 self.loader.borrow_mut().finish_load(&load);
2178
2179 match load {
2180 LoadType::Stylesheet(_) => {
2181 self.process_pending_parsing_blocking_script(can_gc);
2184
2185 self.process_deferred_scripts(can_gc);
2187 },
2188 LoadType::PageSource(_) => {
2189 if self.has_browsing_context && self.is_fully_active() {
2192 self.window().allow_layout_if_necessary();
2193 }
2194
2195 self.process_deferred_scripts(can_gc);
2200 },
2201 _ => {},
2202 }
2203
2204 let loader = self.loader.borrow();
2211
2212 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
2214 update_with_current_instant(&self.top_level_dom_complete);
2215 }
2216
2217 if loader.is_blocked() || loader.events_inhibited() {
2218 return;
2220 }
2221
2222 ScriptThread::mark_document_with_no_blocked_loads(self);
2223 }
2224
2225 pub(crate) fn check_if_unloading_is_cancelled(
2227 &self,
2228 recursive_flag: bool,
2229 can_gc: CanGc,
2230 ) -> bool {
2231 self.incr_ignore_opens_during_unload_counter();
2234 let beforeunload_event = BeforeUnloadEvent::new(
2236 &self.window,
2237 atom!("beforeunload"),
2238 EventBubbles::Bubbles,
2239 EventCancelable::Cancelable,
2240 can_gc,
2241 );
2242 let event = beforeunload_event.upcast::<Event>();
2243 event.set_trusted(true);
2244 let event_target = self.window.upcast::<EventTarget>();
2245 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2246 self.window
2247 .dispatch_event_with_target_override(event, can_gc);
2248 if has_listeners {
2251 self.salvageable.set(false);
2252 }
2253 let mut can_unload = true;
2254 let default_prevented = event.DefaultPrevented();
2256 let return_value_not_empty = !event
2257 .downcast::<BeforeUnloadEvent>()
2258 .unwrap()
2259 .ReturnValue()
2260 .is_empty();
2261 if default_prevented || return_value_not_empty {
2262 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2263 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2264 self.send_to_embedder(msg);
2265 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2266 }
2267 if !recursive_flag {
2269 let iframes: Vec<_> = self.iframes().iter().collect();
2272 for iframe in &iframes {
2273 let document = iframe.owner_document();
2275 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2276 if !document.salvageable() {
2277 self.salvageable.set(false);
2278 }
2279 if !can_unload {
2280 break;
2281 }
2282 }
2283 }
2284 self.decr_ignore_opens_during_unload_counter();
2286 can_unload
2287 }
2288
2289 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2291 self.incr_ignore_opens_during_unload_counter();
2294 if self.page_showing.get() {
2296 self.page_showing.set(false);
2298 let event = PageTransitionEvent::new(
2301 &self.window,
2302 atom!("pagehide"),
2303 false, false, self.salvageable.get(), can_gc,
2307 );
2308 let event = event.upcast::<Event>();
2309 event.set_trusted(true);
2310 self.window
2311 .dispatch_event_with_target_override(event, can_gc);
2312 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2314 }
2315 if !self.fired_unload.get() {
2317 let event = Event::new(
2318 self.window.upcast(),
2319 atom!("unload"),
2320 EventBubbles::Bubbles,
2321 EventCancelable::Cancelable,
2322 can_gc,
2323 );
2324 event.set_trusted(true);
2325 let event_target = self.window.upcast::<EventTarget>();
2326 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2327 self.window
2328 .dispatch_event_with_target_override(&event, can_gc);
2329 self.fired_unload.set(true);
2330 if has_listeners {
2332 self.salvageable.set(false);
2333 }
2334 }
2335 if !recursive_flag {
2339 let iframes: Vec<_> = self.iframes().iter().collect();
2342 for iframe in &iframes {
2343 let document = iframe.owner_document();
2345 document.unload(true, can_gc);
2346 if !document.salvageable() {
2347 self.salvageable.set(false);
2348 }
2349 }
2350 }
2351
2352 self.unloading_cleanup_steps();
2354
2355 self.window.as_global_scope().clean_up_all_file_resources();
2357
2358 self.decr_ignore_opens_during_unload_counter();
2360
2361 }
2364
2365 fn completely_finish_loading(&self) {
2367 self.completely_loaded.set(true);
2372 self.notify_constellation_load();
2381
2382 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2391 &*self.declarative_refresh.borrow()
2392 {
2393 self.window.as_global_scope().schedule_callback(
2394 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2395 window: DomRoot::from_ref(self.window()),
2396 url: url.clone(),
2397 }),
2398 Duration::from_secs(*time),
2399 );
2400 }
2401 }
2402
2403 pub(crate) fn maybe_queue_document_completion(&self) {
2405 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2407 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2408 None => false,
2409 };
2410
2411 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2416 !self.is_fully_active() ||
2417 is_in_delaying_load_events_mode ||
2418 self.loader.borrow().events_inhibited();
2421
2422 if not_ready_for_load {
2423 return;
2425 }
2426
2427 self.loader.borrow_mut().inhibit_events();
2428
2429 debug!("Document loads are complete.");
2434 let document = Trusted::new(self);
2435 self.owner_global()
2436 .task_manager()
2437 .dom_manipulation_task_source()
2438 .queue(task!(fire_load_event: move || {
2439 let document = document.root();
2440 let window = document.window();
2442 if !window.is_alive() {
2443 return;
2444 }
2445
2446 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2448
2449 if document.browsing_context().is_none() {
2451 return;
2452 }
2453
2454 update_with_current_instant(&document.load_event_start);
2456
2457 let load_event = Event::new(
2459 window.upcast(),
2460 atom!("load"),
2461 EventBubbles::DoesNotBubble,
2462 EventCancelable::NotCancelable,
2463 CanGc::note(),
2464 );
2465 load_event.set_trusted(true);
2466 debug!("About to dispatch load for {:?}", document.url());
2467 window.dispatch_event_with_target_override(&load_event, CanGc::note());
2468
2469 update_with_current_instant(&document.load_event_end);
2479
2480 document.page_showing.set(true);
2485
2486 let page_show_event = PageTransitionEvent::new(
2488 window,
2489 atom!("pageshow"),
2490 false, false, false, CanGc::note(),
2494 );
2495 let page_show_event = page_show_event.upcast::<Event>();
2496 page_show_event.set_trusted(true);
2497 page_show_event.fire(window.upcast(), CanGc::note());
2498
2499 document.completely_finish_loading();
2501
2502 if let Some(fragment) = document.url().fragment() {
2506 document.scroll_to_the_fragment(fragment);
2507 }
2508 }));
2509
2510 #[cfg(feature = "webxr")]
2525 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2526 self.window.Navigator().Xr().dispatch_sessionavailable();
2527 }
2528 }
2529
2530 pub(crate) fn completely_loaded(&self) -> bool {
2531 self.completely_loaded.get()
2532 }
2533
2534 pub(crate) fn set_pending_parsing_blocking_script(
2536 &self,
2537 script: &HTMLScriptElement,
2538 load: Option<ScriptResult>,
2539 ) {
2540 assert!(!self.has_pending_parsing_blocking_script());
2541 *self.pending_parsing_blocking_script.borrow_mut() =
2542 Some(PendingScript::new_with_load(script, load));
2543 }
2544
2545 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2547 self.pending_parsing_blocking_script.borrow().is_some()
2548 }
2549
2550 pub(crate) fn pending_parsing_blocking_script_loaded(
2552 &self,
2553 element: &HTMLScriptElement,
2554 result: ScriptResult,
2555 can_gc: CanGc,
2556 ) {
2557 {
2558 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2559 let entry = blocking_script.as_mut().unwrap();
2560 assert!(&*entry.element == element);
2561 entry.loaded(result);
2562 }
2563 self.process_pending_parsing_blocking_script(can_gc);
2564 }
2565
2566 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2567 if self.script_blocking_stylesheets_count.get() > 0 {
2568 return;
2569 }
2570 let pair = self
2571 .pending_parsing_blocking_script
2572 .borrow_mut()
2573 .as_mut()
2574 .and_then(PendingScript::take_result);
2575 if let Some((element, result)) = pair {
2576 *self.pending_parsing_blocking_script.borrow_mut() = None;
2577 self.get_current_parser()
2578 .unwrap()
2579 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2580 }
2581 }
2582
2583 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2585 self.asap_scripts_set
2586 .borrow_mut()
2587 .push(Dom::from_ref(script));
2588 }
2589
2590 pub(crate) fn asap_script_loaded(
2593 &self,
2594 element: &HTMLScriptElement,
2595 result: ScriptResult,
2596 can_gc: CanGc,
2597 ) {
2598 {
2599 let mut scripts = self.asap_scripts_set.borrow_mut();
2600 let idx = scripts
2601 .iter()
2602 .position(|entry| &**entry == element)
2603 .unwrap();
2604 scripts.swap_remove(idx);
2605 }
2606 element.execute(result, can_gc);
2607 }
2608
2609 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2611 self.asap_in_order_scripts_list.push(script);
2612 }
2613
2614 pub(crate) fn asap_in_order_script_loaded(
2617 &self,
2618 element: &HTMLScriptElement,
2619 result: ScriptResult,
2620 can_gc: CanGc,
2621 ) {
2622 self.asap_in_order_scripts_list.loaded(element, result);
2623 while let Some((element, result)) = self
2624 .asap_in_order_scripts_list
2625 .take_next_ready_to_be_executed()
2626 {
2627 element.execute(result, can_gc);
2628 }
2629 }
2630
2631 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2633 self.deferred_scripts.push(script);
2634 }
2635
2636 pub(crate) fn deferred_script_loaded(
2639 &self,
2640 element: &HTMLScriptElement,
2641 result: ScriptResult,
2642 can_gc: CanGc,
2643 ) {
2644 self.deferred_scripts.loaded(element, result);
2645 self.process_deferred_scripts(can_gc);
2646 }
2647
2648 fn process_deferred_scripts(&self, can_gc: CanGc) {
2650 if self.ready_state.get() != DocumentReadyState::Interactive {
2651 return;
2652 }
2653 loop {
2655 if self.script_blocking_stylesheets_count.get() > 0 {
2656 return;
2657 }
2658 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2659 {
2660 element.execute(result, can_gc);
2661 } else {
2662 break;
2663 }
2664 }
2665 if self.deferred_scripts.is_empty() {
2666 self.maybe_dispatch_dom_content_loaded();
2668 }
2669 }
2670
2671 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2673 if self.domcontentloaded_dispatched.get() {
2674 return;
2675 }
2676 self.domcontentloaded_dispatched.set(true);
2677 assert_ne!(
2678 self.ReadyState(),
2679 DocumentReadyState::Complete,
2680 "Complete before DOMContentLoaded?"
2681 );
2682
2683 update_with_current_instant(&self.dom_content_loaded_event_start);
2684
2685 let document = Trusted::new(self);
2687 self.owner_global()
2688 .task_manager()
2689 .dom_manipulation_task_source()
2690 .queue(
2691 task!(fire_dom_content_loaded_event: move || {
2692 let document = document.root();
2693 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2694 update_with_current_instant(&document.dom_content_loaded_event_end);
2695 })
2696 );
2697
2698 self.interactive_time
2700 .borrow()
2701 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2702
2703 }
2706
2707 pub(crate) fn destroy_document_and_its_descendants(&self, can_gc: CanGc) {
2709 if !self.is_fully_active() {
2711 self.salvageable.set(false);
2716 }
2720 for exited_iframe in self.iframes().iter() {
2733 debug!("Destroying nested iframe document");
2734 exited_iframe.destroy_document_and_its_descendants(can_gc);
2735 }
2736 self.destroy(can_gc);
2741 }
2744
2745 pub(crate) fn destroy(&self, can_gc: CanGc) {
2747 let exited_window = self.window();
2748 self.abort(can_gc);
2750 self.salvageable.set(false);
2752 self.unloading_cleanup_steps();
2762
2763 exited_window
2766 .as_global_scope()
2767 .task_manager()
2768 .cancel_all_tasks_and_ignore_future_tasks();
2769
2770 exited_window.discard_browsing_context();
2772
2773 }
2785
2786 fn terminate_fetch_group(&self) -> bool {
2788 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2789
2790 for canceller in &mut load_cancellers {
2794 if !canceller.keep_alive() {
2795 canceller.terminate();
2796 }
2797 }
2798 self.owner_global().process_deferred_fetches();
2800
2801 !load_cancellers.is_empty()
2802 }
2803
2804 pub(crate) fn abort(&self, can_gc: CanGc) {
2806 self.loader.borrow_mut().inhibit_events();
2808
2809 for iframe in self.iframes().iter() {
2811 if let Some(document) = iframe.GetContentDocument() {
2812 document.abort(can_gc);
2813 }
2814 }
2815
2816 self.script_blocking_stylesheets_count.set(0);
2822 *self.pending_parsing_blocking_script.borrow_mut() = None;
2823 *self.asap_scripts_set.borrow_mut() = vec![];
2824 self.asap_in_order_scripts_list.clear();
2825 self.deferred_scripts.clear();
2826 let loads_cancelled = self.terminate_fetch_group();
2827 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2828 if loads_cancelled || event_sources_canceled {
2829 self.salvageable.set(false);
2831 };
2832
2833 self.owner_global()
2838 .task_manager()
2839 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2840
2841 if let Some(parser) = self.get_current_parser() {
2846 self.active_parser_was_aborted.set(true);
2848 parser.abort(can_gc);
2850 self.salvageable.set(false);
2852 }
2853 }
2854
2855 pub(crate) fn notify_constellation_load(&self) {
2856 self.window()
2857 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2858 }
2859
2860 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2861 self.current_parser.set(script);
2862 }
2863
2864 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2865 self.current_parser.get()
2866 }
2867
2868 pub(crate) fn get_current_parser_line(&self) -> u32 {
2869 self.get_current_parser()
2870 .map(|parser| parser.get_current_line())
2871 .unwrap_or(0)
2872 }
2873
2874 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2877 self.iframes.borrow_mut().validate(self);
2878 self.iframes.borrow()
2879 }
2880
2881 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2884 self.iframes.borrow_mut().validate(self);
2885 self.iframes.borrow_mut()
2886 }
2887
2888 pub(crate) fn invalidate_iframes_collection(&self) {
2889 self.iframes.borrow_mut().invalidate();
2890 }
2891
2892 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2893 self.dom_interactive.get()
2894 }
2895
2896 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2897 self.interactive_time
2898 .borrow_mut()
2899 .set_navigation_start(navigation_start);
2900 }
2901
2902 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2903 self.interactive_time.borrow()
2904 }
2905
2906 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2907 self.get_interactive_metrics().get_tti().is_some()
2908 }
2909
2910 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2911 self.dom_content_loaded_event_start.get()
2912 }
2913
2914 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2915 self.dom_content_loaded_event_end.get()
2916 }
2917
2918 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2919 self.dom_complete.get()
2920 }
2921
2922 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2923 self.top_level_dom_complete.get()
2924 }
2925
2926 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2927 self.load_event_start.get()
2928 }
2929
2930 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2931 self.load_event_end.get()
2932 }
2933
2934 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2935 self.unload_event_start.get()
2936 }
2937
2938 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2939 self.unload_event_end.get()
2940 }
2941
2942 pub(crate) fn start_tti(&self) {
2943 if self.get_interactive_metrics().needs_tti() {
2944 self.tti_window.borrow_mut().start_window();
2945 }
2946 }
2947
2948 pub(crate) fn record_tti_if_necessary(&self) {
2952 if self.has_recorded_tti_metric() {
2953 return;
2954 }
2955 if self.tti_window.borrow().needs_check() {
2956 self.get_interactive_metrics()
2957 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2958 self.tti_window.borrow().get_start(),
2959 ));
2960 }
2961 }
2962
2963 fn fire_focus_event(
2965 &self,
2966 focus_event_type: FocusEventType,
2967 event_target: &EventTarget,
2968 related_target: Option<&EventTarget>,
2969 can_gc: CanGc,
2970 ) {
2971 let (event_name, does_bubble) = match focus_event_type {
2972 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2973 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2974 };
2975 let event = FocusEvent::new(
2976 &self.window,
2977 event_name,
2978 does_bubble,
2979 EventCancelable::NotCancelable,
2980 Some(&self.window),
2981 0i32,
2982 related_target,
2983 can_gc,
2984 );
2985 let event = event.upcast::<Event>();
2986 event.set_trusted(true);
2987 event.fire(event_target, can_gc);
2988 }
2989
2990 pub(crate) fn is_cookie_averse(&self) -> bool {
2992 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2993 }
2994
2995 pub(crate) fn lookup_custom_element_definition(
2997 &self,
2998 namespace: &Namespace,
2999 local_name: &LocalName,
3000 is: Option<&LocalName>,
3001 ) -> Option<Rc<CustomElementDefinition>> {
3002 if *namespace != ns!(html) {
3004 return None;
3005 }
3006
3007 if !self.has_browsing_context {
3009 return None;
3010 }
3011
3012 let registry = self.window.CustomElements();
3014
3015 registry.lookup_definition(local_name, is)
3016 }
3017
3018 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
3020 self.window.CustomElements()
3021 }
3022
3023 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
3024 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3025 self.throw_on_dynamic_markup_insertion_counter
3026 .set(counter + 1);
3027 }
3028
3029 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
3030 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3031 self.throw_on_dynamic_markup_insertion_counter
3032 .set(counter - 1);
3033 }
3034
3035 pub(crate) fn react_to_environment_changes(&self) {
3036 for image in self.responsive_images.borrow().iter() {
3037 image.react_to_environment_changes();
3038 }
3039 }
3040
3041 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3042 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3043 }
3044
3045 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3046 let index = self
3047 .responsive_images
3048 .borrow()
3049 .iter()
3050 .position(|x| **x == *img);
3051 if let Some(i) = index {
3052 self.responsive_images.borrow_mut().remove(i);
3053 }
3054 }
3055
3056 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3057 let did_have_these_media_controls = self
3058 .media_controls
3059 .borrow_mut()
3060 .insert(id.to_string(), Dom::from_ref(controls))
3061 .is_some();
3062 debug_assert!(
3063 !did_have_these_media_controls,
3064 "Trying to register known media controls"
3065 );
3066 }
3067
3068 pub(crate) fn unregister_media_controls(&self, id: &str) {
3069 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3070 debug_assert!(
3071 did_have_these_media_controls,
3072 "Trying to unregister unknown media controls"
3073 );
3074 }
3075
3076 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3077 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3078 if dirty_canvases
3079 .iter()
3080 .any(|dirty_canvas| dirty_canvas == canvas)
3081 {
3082 return;
3083 }
3084 dirty_canvases.push(canvas.clone());
3085 }
3086
3087 pub(crate) fn needs_rendering_update(&self) -> bool {
3091 if !self.is_fully_active() {
3092 return false;
3093 }
3094 if !self.window().layout_blocked() &&
3095 (!self.restyle_reason().is_empty() ||
3096 self.window().layout().needs_new_display_list())
3097 {
3098 return true;
3099 }
3100 if !self.rendering_update_reasons.get().is_empty() {
3101 return true;
3102 }
3103 if self.event_handler.has_pending_input_events() {
3104 return true;
3105 }
3106 if self.has_pending_scroll_events() {
3107 return true;
3108 }
3109 if self.window().has_unhandled_resize_event() {
3110 return true;
3111 }
3112 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3113 {
3114 return true;
3115 }
3116
3117 false
3118 }
3119
3120 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
3128 if self.render_blocking_element_count() > 0 {
3129 return Default::default();
3130 }
3131
3132 let mut results = ReflowPhasesRun::empty();
3133 if self.has_pending_animated_image_update.get() {
3134 self.image_animation_manager
3135 .borrow()
3136 .update_active_frames(&self.window, self.current_animation_timeline_value());
3137 self.has_pending_animated_image_update.set(false);
3138 results.insert(ReflowPhasesRun::UpdatedImageData);
3139 }
3140
3141 self.current_rendering_epoch
3142 .set(self.current_rendering_epoch.get().next());
3143 let current_rendering_epoch = self.current_rendering_epoch.get();
3144
3145 let image_keys: Vec<_> = self
3147 .dirty_canvases
3148 .borrow_mut()
3149 .drain(..)
3150 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3151 .collect();
3152
3153 let pipeline_id = self.window().pipeline_id();
3156 if !image_keys.is_empty() {
3157 results.insert(ReflowPhasesRun::UpdatedImageData);
3158 self.waiting_on_canvas_image_updates.set(true);
3159 self.window().paint_api().delay_new_frame_for_canvas(
3160 self.webview_id(),
3161 self.window().pipeline_id(),
3162 current_rendering_epoch,
3163 image_keys,
3164 );
3165 }
3166
3167 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
3168
3169 self.window().paint_api().update_epoch(
3170 self.webview_id(),
3171 pipeline_id,
3172 current_rendering_epoch,
3173 );
3174
3175 results
3176 }
3177
3178 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3179 self.waiting_on_canvas_image_updates.set(false);
3180 }
3181
3182 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3183 self.waiting_on_canvas_image_updates.get()
3184 }
3185
3186 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
3196 if !self.is_fully_active() {
3197 return false;
3198 }
3199
3200 let fonts = self.Fonts(can_gc);
3201 if !fonts.waiting_to_fullfill_promise() {
3202 return false;
3203 }
3204 if self.window().font_context().web_fonts_still_loading() != 0 {
3205 return false;
3206 }
3207 if self.ReadyState() != DocumentReadyState::Complete {
3208 return false;
3209 }
3210 if !self.restyle_reason().is_empty() {
3211 return false;
3212 }
3213 if !self.rendering_update_reasons.get().is_empty() {
3214 return false;
3215 }
3216
3217 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
3218
3219 if result {
3223 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3224 }
3225
3226 result
3227 }
3228
3229 pub(crate) fn id_map(
3230 &self,
3231 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3232 self.id_map.borrow()
3233 }
3234
3235 pub(crate) fn name_map(
3236 &self,
3237 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3238 self.name_map.borrow()
3239 }
3240
3241 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3243 self.resize_observers
3244 .borrow_mut()
3245 .push(Dom::from_ref(resize_observer));
3246 }
3247
3248 pub(crate) fn has_resize_observers(&self) -> bool {
3250 !self.resize_observers.borrow().is_empty()
3251 }
3252
3253 pub(crate) fn gather_active_resize_observations_at_depth(
3256 &self,
3257 depth: &ResizeObservationDepth,
3258 ) -> bool {
3259 let mut has_active_resize_observations = false;
3260 for observer in self.resize_observers.borrow_mut().iter_mut() {
3261 observer.gather_active_resize_observations_at_depth(
3262 depth,
3263 &mut has_active_resize_observations,
3264 );
3265 }
3266 has_active_resize_observations
3267 }
3268
3269 #[expect(clippy::redundant_iter_cloned)]
3271 pub(crate) fn broadcast_active_resize_observations(
3272 &self,
3273 can_gc: CanGc,
3274 ) -> ResizeObservationDepth {
3275 let mut shallowest = ResizeObservationDepth::max();
3276 let iterator: Vec<DomRoot<ResizeObserver>> = self
3280 .resize_observers
3281 .borrow()
3282 .iter()
3283 .cloned()
3284 .map(|obs| DomRoot::from_ref(&*obs))
3285 .collect();
3286 for observer in iterator {
3287 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3288 }
3289 shallowest
3290 }
3291
3292 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3294 self.resize_observers
3295 .borrow()
3296 .iter()
3297 .any(|observer| observer.has_skipped_resize_observations())
3298 }
3299
3300 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3302 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3303 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3304 ..Default::default()
3305 };
3306 self.window
3307 .as_global_scope()
3308 .report_an_error(error_info, HandleValue::null(), can_gc);
3309 }
3310
3311 pub(crate) fn status_code(&self) -> Option<u16> {
3312 self.status_code
3313 }
3314
3315 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3317 let encoding = self.encoding.get();
3323
3324 let base_url = self.base_url();
3330
3331 url::Url::options()
3333 .base_url(Some(base_url.as_url()))
3334 .encoding_override(Some(&|input| {
3335 servo_url::encoding::encode_as_url_query_string(input, encoding)
3336 }))
3337 .parse(url)
3338 .map(ServoUrl::from)
3339 }
3340
3341 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3343 if !self.has_browsing_context {
3345 return false;
3346 }
3347
3348 if !self.is_fully_active() {
3350 return false;
3351 }
3352
3353 true
3359 }
3360
3361 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3364 self.intersection_observers
3365 .borrow_mut()
3366 .push(Dom::from_ref(intersection_observer));
3367 }
3368
3369 pub(crate) fn remove_intersection_observer(
3373 &self,
3374 intersection_observer: &IntersectionObserver,
3375 ) {
3376 self.intersection_observers
3377 .borrow_mut()
3378 .retain(|observer| *observer != intersection_observer)
3379 }
3380
3381 pub(crate) fn update_intersection_observer_steps(
3383 &self,
3384 time: CrossProcessInstant,
3385 can_gc: CanGc,
3386 ) {
3387 for intersection_observer in &*self.intersection_observers.borrow() {
3389 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3390 }
3391 }
3392
3393 fn update_single_intersection_observer_steps(
3395 &self,
3396 intersection_observer: &IntersectionObserver,
3397 time: CrossProcessInstant,
3398 can_gc: CanGc,
3399 ) {
3400 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3403
3404 intersection_observer.update_intersection_observations_steps(
3408 self,
3409 time,
3410 root_bounds,
3411 can_gc,
3412 );
3413 }
3414
3415 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3417 self.intersection_observer_task_queued.set(false);
3420
3421 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3426
3427 for intersection_observer in notify_list.iter() {
3430 intersection_observer.invoke_callback_if_necessary(can_gc);
3432 }
3433 }
3434
3435 pub(crate) fn queue_an_intersection_observer_task(&self) {
3437 if self.intersection_observer_task_queued.get() {
3440 return;
3441 }
3442
3443 self.intersection_observer_task_queued.set(true);
3446
3447 let document = Trusted::new(self);
3451 self.owner_global()
3452 .task_manager()
3453 .intersection_observer_task_source()
3454 .queue(task!(notify_intersection_observers: move || {
3455 document.root().notify_intersection_observers(CanGc::note());
3456 }));
3457 }
3458
3459 pub(crate) fn handle_paint_metric(
3460 &self,
3461 metric_type: ProgressiveWebMetricType,
3462 metric_value: CrossProcessInstant,
3463 first_reflow: bool,
3464 can_gc: CanGc,
3465 ) {
3466 let metrics = self.interactive_time.borrow();
3467 match metric_type {
3468 ProgressiveWebMetricType::FirstPaint |
3469 ProgressiveWebMetricType::FirstContentfulPaint => {
3470 let binding = PerformancePaintTiming::new(
3471 self.window.as_global_scope(),
3472 metric_type,
3473 metric_value,
3474 can_gc,
3475 );
3476 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3477 let entry = binding.upcast::<PerformanceEntry>();
3478 self.window.Performance().queue_entry(entry);
3479 },
3480 ProgressiveWebMetricType::LargestContentfulPaint { area } => {
3481 let binding = LargestContentfulPaint::new(
3482 self.window.as_global_scope(),
3483 metric_type,
3484 metric_value,
3485 can_gc,
3486 );
3487 metrics.set_largest_contentful_paint(metric_value, area);
3488 let entry = binding.upcast::<PerformanceEntry>();
3489 self.window.Performance().queue_entry(entry);
3490 },
3491 ProgressiveWebMetricType::TimeToInteractive => {
3492 unreachable!("Unexpected non-paint metric.")
3493 },
3494 }
3495 }
3496
3497 fn write(
3499 &self,
3500 text: Vec<TrustedHTMLOrString>,
3501 line_feed: bool,
3502 containing_class: &str,
3503 field: &str,
3504 can_gc: CanGc,
3505 ) -> ErrorResult {
3506 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3508 let mut is_trusted = true;
3510 for value in text {
3512 match value {
3513 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3515 strings.push(trusted_html.to_string());
3516 },
3517 TrustedHTMLOrString::String(str_) => {
3518 is_trusted = false;
3520 strings.push(str_.into());
3522 },
3523 };
3524 }
3525 let mut string = itertools::join(strings, "");
3526 if !is_trusted {
3530 string = TrustedHTML::get_trusted_script_compliant_string(
3531 &self.global(),
3532 TrustedHTMLOrString::String(string.into()),
3533 &format!("{} {}", containing_class, field),
3534 can_gc,
3535 )?
3536 .str()
3537 .to_owned();
3538 }
3539 if line_feed {
3541 string.push('\n');
3542 }
3543 if !self.is_html_document() {
3545 return Err(Error::InvalidState(None));
3546 }
3547
3548 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3551 return Err(Error::InvalidState(None));
3552 }
3553
3554 if !self.is_active() || self.active_parser_was_aborted.get() {
3556 return Ok(());
3557 }
3558
3559 let parser = match self.get_current_parser() {
3560 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3561 _ => {
3563 if self.is_prompting_or_unloading() ||
3566 self.ignore_destructive_writes_counter.get() > 0
3567 {
3568 return Ok(());
3569 }
3570 self.Open(None, None, can_gc)?;
3572 self.get_current_parser().unwrap()
3573 },
3574 };
3575
3576 parser.write(string.into(), can_gc);
3578
3579 Ok(())
3580 }
3581
3582 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3583 RefMut::map(
3584 self.details_name_groups.borrow_mut(),
3585 |details_name_groups| details_name_groups.get_or_insert_default(),
3586 )
3587 }
3588}
3589
3590#[derive(MallocSizeOf, PartialEq)]
3591pub(crate) enum DocumentSource {
3592 FromParser,
3593 NotFromParser,
3594}
3595
3596pub(crate) trait LayoutDocumentHelpers<'dom> {
3597 fn is_html_document_for_layout(&self) -> bool;
3598 fn quirks_mode(self) -> QuirksMode;
3599 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3600 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3601 fn shadow_roots_styles_changed(self) -> bool;
3602 fn flush_shadow_roots_stylesheets(self);
3603}
3604
3605#[expect(unsafe_code)]
3606impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3607 #[inline]
3608 fn is_html_document_for_layout(&self) -> bool {
3609 self.unsafe_get().is_html_document
3610 }
3611
3612 #[inline]
3613 fn quirks_mode(self) -> QuirksMode {
3614 self.unsafe_get().quirks_mode.get()
3615 }
3616
3617 #[inline]
3618 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3619 self.unsafe_get().style_shared_lock()
3620 }
3621
3622 #[inline]
3623 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3624 unsafe {
3629 self.unsafe_get()
3630 .shadow_roots
3631 .borrow_for_layout()
3632 .iter()
3633 .map(|sr| sr.to_layout())
3634 .collect()
3635 }
3636 }
3637
3638 #[inline]
3639 fn shadow_roots_styles_changed(self) -> bool {
3640 self.unsafe_get().shadow_roots_styles_changed.get()
3641 }
3642
3643 #[inline]
3644 fn flush_shadow_roots_stylesheets(self) {
3645 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3646 }
3647}
3648
3649pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3653 host_suffix_string: &str,
3654 original_host: Host,
3655) -> Option<Host> {
3656 if host_suffix_string.is_empty() {
3658 return None;
3659 }
3660
3661 let host = match Host::parse(host_suffix_string) {
3663 Ok(host) => host,
3664 Err(_) => return None,
3665 };
3666
3667 if host != original_host {
3669 let host = match host {
3671 Host::Domain(ref host) => host,
3672 _ => return None,
3673 };
3674 let original_host = match original_host {
3675 Host::Domain(ref original_host) => original_host,
3676 _ => return None,
3677 };
3678
3679 let index = original_host.len().checked_sub(host.len())?;
3681 let (prefix, suffix) = original_host.split_at(index);
3682
3683 if !prefix.ends_with('.') {
3684 return None;
3685 }
3686 if suffix != host {
3687 return None;
3688 }
3689
3690 if is_pub_domain(host) {
3692 return None;
3693 }
3694 }
3695
3696 Some(host)
3698}
3699
3700fn url_has_network_scheme(url: &ServoUrl) -> bool {
3702 matches!(url.scheme(), "ftp" | "http" | "https")
3703}
3704
3705#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3706pub(crate) enum HasBrowsingContext {
3707 No,
3708 Yes,
3709}
3710
3711impl Document {
3712 #[allow(clippy::too_many_arguments)]
3713 pub(crate) fn new_inherited(
3714 window: &Window,
3715 has_browsing_context: HasBrowsingContext,
3716 url: Option<ServoUrl>,
3717 about_base_url: Option<ServoUrl>,
3718 origin: MutableOrigin,
3719 is_html_document: IsHTMLDocument,
3720 content_type: Option<Mime>,
3721 last_modified: Option<String>,
3722 activity: DocumentActivity,
3723 source: DocumentSource,
3724 doc_loader: DocumentLoader,
3725 referrer: Option<String>,
3726 status_code: Option<u16>,
3727 canceller: FetchCanceller,
3728 is_initial_about_blank: bool,
3729 allow_declarative_shadow_roots: bool,
3730 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3731 has_trustworthy_ancestor_origin: bool,
3732 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3733 creation_sandboxing_flag_set: SandboxingFlagSet,
3734 ) -> Document {
3735 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3736
3737 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3738 (DocumentReadyState::Loading, false)
3739 } else {
3740 (DocumentReadyState::Complete, true)
3741 };
3742
3743 let frame_type = match window.is_top_level() {
3744 true => TimerMetadataFrameType::RootWindow,
3745 false => TimerMetadataFrameType::IFrame,
3746 };
3747 let interactive_time = ProgressiveWebMetrics::new(
3748 window.time_profiler_chan().clone(),
3749 url.clone(),
3750 frame_type,
3751 );
3752
3753 let content_type = content_type.unwrap_or_else(|| {
3754 match is_html_document {
3755 IsHTMLDocument::HTMLDocument => "text/html",
3757 IsHTMLDocument::NonHTMLDocument => "application/xml",
3759 }
3760 .parse()
3761 .unwrap()
3762 });
3763
3764 let encoding = content_type
3765 .get_parameter(CHARSET)
3766 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3767 .unwrap_or(UTF_8);
3768
3769 let has_focus = window.parent_info().is_none();
3770
3771 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3772
3773 Document {
3774 node: Node::new_document_node(),
3775 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3776 window: Dom::from_ref(window),
3777 has_browsing_context,
3778 implementation: Default::default(),
3779 content_type,
3780 last_modified,
3781 url: DomRefCell::new(url),
3782 about_base_url: DomRefCell::new(about_base_url),
3783 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3785 event_handler: DocumentEventHandler::new(window),
3786 embedder_controls: DocumentEmbedderControls::new(window),
3787 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3788 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3789 encoding: Cell::new(encoding),
3791 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3792 activity: Cell::new(activity),
3793 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3794 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3795 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3796 images: Default::default(),
3797 embeds: Default::default(),
3798 links: Default::default(),
3799 forms: Default::default(),
3800 scripts: Default::default(),
3801 anchors: Default::default(),
3802 applets: Default::default(),
3803 iframes: RefCell::new(IFrameCollection::new()),
3804 style_shared_lock: {
3805 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3812 LazyLock::new(StyleSharedRwLock::new);
3813
3814 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3815 },
3817 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3818 stylesheet_list: MutNullableDom::new(None),
3819 ready_state: Cell::new(ready_state),
3820 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3821 focus_transaction: DomRefCell::new(None),
3822 focused: Default::default(),
3823 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3824 has_focus: Cell::new(has_focus),
3825 current_script: Default::default(),
3826 pending_parsing_blocking_script: Default::default(),
3827 script_blocking_stylesheets_count: Default::default(),
3828 render_blocking_element_count: Default::default(),
3829 deferred_scripts: Default::default(),
3830 asap_in_order_scripts_list: Default::default(),
3831 asap_scripts_set: Default::default(),
3832 animation_frame_ident: Cell::new(0),
3833 animation_frame_list: DomRefCell::new(VecDeque::new()),
3834 running_animation_callbacks: Cell::new(false),
3835 loader: DomRefCell::new(doc_loader),
3836 current_parser: Default::default(),
3837 base_element: Default::default(),
3838 target_base_element: Default::default(),
3839 appropriate_template_contents_owner_document: Default::default(),
3840 pending_restyles: DomRefCell::new(FxHashMap::default()),
3841 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3842 dom_interactive: Cell::new(Default::default()),
3843 dom_content_loaded_event_start: Cell::new(Default::default()),
3844 dom_content_loaded_event_end: Cell::new(Default::default()),
3845 dom_complete: Cell::new(Default::default()),
3846 top_level_dom_complete: Cell::new(Default::default()),
3847 load_event_start: Cell::new(Default::default()),
3848 load_event_end: Cell::new(Default::default()),
3849 unload_event_start: Cell::new(Default::default()),
3850 unload_event_end: Cell::new(Default::default()),
3851 https_state: Cell::new(HttpsState::None),
3852 origin,
3853 referrer,
3854 target_element: MutNullableDom::new(None),
3855 policy_container: DomRefCell::new(PolicyContainer::default()),
3856 preloaded_resources: Default::default(),
3857 ignore_destructive_writes_counter: Default::default(),
3858 ignore_opens_during_unload_counter: Default::default(),
3859 spurious_animation_frames: Cell::new(0),
3860 dom_count: Cell::new(1),
3861 fullscreen_element: MutNullableDom::new(None),
3862 form_id_listener_map: Default::default(),
3863 interactive_time: DomRefCell::new(interactive_time),
3864 tti_window: DomRefCell::new(InteractiveWindow::default()),
3865 canceller,
3866 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3867 page_showing: Cell::new(false),
3868 salvageable: Cell::new(true),
3869 active_parser_was_aborted: Cell::new(false),
3870 fired_unload: Cell::new(false),
3871 responsive_images: Default::default(),
3872 redirect_count: Cell::new(0),
3873 completely_loaded: Cell::new(false),
3874 script_and_layout_blockers: Cell::new(0),
3875 delayed_tasks: Default::default(),
3876 shadow_roots: DomRefCell::new(HashSet::new()),
3877 shadow_roots_styles_changed: Cell::new(false),
3878 media_controls: DomRefCell::new(HashMap::new()),
3879 dirty_canvases: DomRefCell::new(Default::default()),
3880 has_pending_animated_image_update: Cell::new(false),
3881 selection: MutNullableDom::new(None),
3882 animation_timeline: if pref!(layout_animations_test_enabled) {
3883 DomRefCell::new(AnimationTimeline::new_for_testing())
3884 } else {
3885 DomRefCell::new(AnimationTimeline::new())
3886 },
3887 animations: Animations::new(),
3888 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3889 dirty_root: Default::default(),
3890 declarative_refresh: Default::default(),
3891 resize_observers: Default::default(),
3892 fonts: Default::default(),
3893 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3894 status_code,
3895 is_initial_about_blank: Cell::new(is_initial_about_blank),
3896 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3897 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3898 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3899 intersection_observer_task_queued: Cell::new(false),
3900 intersection_observers: Default::default(),
3901 highlighted_dom_node: Default::default(),
3902 adopted_stylesheets: Default::default(),
3903 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3904 pending_scroll_event_targets: Default::default(),
3905 rendering_update_reasons: Default::default(),
3906 waiting_on_canvas_image_updates: Cell::new(false),
3907 current_rendering_epoch: Default::default(),
3908 custom_element_reaction_stack,
3909 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3910 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3911 favicon: RefCell::new(None),
3912 websockets: DOMTracker::new(),
3913 details_name_groups: Default::default(),
3914 protocol_handler_automation_mode: Default::default(),
3915 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3916 }
3917 }
3918
3919 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3921 if let Some(csp_list) = self.get_csp_list() {
3922 for policy in &csp_list.0 {
3923 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3924 policy.disposition == PolicyDisposition::Enforce
3925 {
3926 return InsecureRequestsPolicy::Upgrade;
3927 }
3928 }
3929 }
3930
3931 self.inherited_insecure_requests_policy
3932 .get()
3933 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3934 }
3935
3936 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3938 &self.event_handler
3939 }
3940
3941 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3943 &self.embedder_controls
3944 }
3945
3946 fn has_pending_scroll_events(&self) -> bool {
3949 !self.pending_scroll_event_targets.borrow().is_empty()
3950 }
3951
3952 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3955 self.rendering_update_reasons
3956 .set(self.rendering_update_reasons.get().union(reason));
3957 }
3958
3959 pub(crate) fn clear_rendering_update_reasons(&self) {
3961 self.rendering_update_reasons
3962 .set(RenderingUpdateReason::empty())
3963 }
3964
3965 pub(crate) fn add_script_and_layout_blocker(&self) {
3972 self.script_and_layout_blockers
3973 .set(self.script_and_layout_blockers.get() + 1);
3974 }
3975
3976 #[expect(unsafe_code)]
3977 pub(crate) fn remove_script_and_layout_blocker(&self) {
3981 assert!(self.script_and_layout_blockers.get() > 0);
3982 self.script_and_layout_blockers
3983 .set(self.script_and_layout_blockers.get() - 1);
3984 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3985 {
3986 let task = self.delayed_tasks.borrow_mut().remove(0);
3987 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
3988 task.run_box(&mut cx);
3989 }
3990 }
3991
3992 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3994 self.delayed_tasks.borrow_mut().push(Box::new(task));
3995 }
3996
3997 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
4000 assert_eq!(
4001 self.script_and_layout_blockers.get(),
4002 0,
4003 "Attempt to use script or layout while DOM not in a stable state"
4004 );
4005 }
4006
4007 #[allow(clippy::too_many_arguments)]
4008 pub(crate) fn new(
4009 window: &Window,
4010 has_browsing_context: HasBrowsingContext,
4011 url: Option<ServoUrl>,
4012 about_base_url: Option<ServoUrl>,
4013 origin: MutableOrigin,
4014 doctype: IsHTMLDocument,
4015 content_type: Option<Mime>,
4016 last_modified: Option<String>,
4017 activity: DocumentActivity,
4018 source: DocumentSource,
4019 doc_loader: DocumentLoader,
4020 referrer: Option<String>,
4021 status_code: Option<u16>,
4022 canceller: FetchCanceller,
4023 is_initial_about_blank: bool,
4024 allow_declarative_shadow_roots: bool,
4025 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4026 has_trustworthy_ancestor_origin: bool,
4027 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4028 creation_sandboxing_flag_set: SandboxingFlagSet,
4029 can_gc: CanGc,
4030 ) -> DomRoot<Document> {
4031 Self::new_with_proto(
4032 window,
4033 None,
4034 has_browsing_context,
4035 url,
4036 about_base_url,
4037 origin,
4038 doctype,
4039 content_type,
4040 last_modified,
4041 activity,
4042 source,
4043 doc_loader,
4044 referrer,
4045 status_code,
4046 canceller,
4047 is_initial_about_blank,
4048 allow_declarative_shadow_roots,
4049 inherited_insecure_requests_policy,
4050 has_trustworthy_ancestor_origin,
4051 custom_element_reaction_stack,
4052 creation_sandboxing_flag_set,
4053 can_gc,
4054 )
4055 }
4056
4057 #[allow(clippy::too_many_arguments)]
4058 fn new_with_proto(
4059 window: &Window,
4060 proto: Option<HandleObject>,
4061 has_browsing_context: HasBrowsingContext,
4062 url: Option<ServoUrl>,
4063 about_base_url: Option<ServoUrl>,
4064 origin: MutableOrigin,
4065 doctype: IsHTMLDocument,
4066 content_type: Option<Mime>,
4067 last_modified: Option<String>,
4068 activity: DocumentActivity,
4069 source: DocumentSource,
4070 doc_loader: DocumentLoader,
4071 referrer: Option<String>,
4072 status_code: Option<u16>,
4073 canceller: FetchCanceller,
4074 is_initial_about_blank: bool,
4075 allow_declarative_shadow_roots: bool,
4076 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4077 has_trustworthy_ancestor_origin: bool,
4078 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4079 creation_sandboxing_flag_set: SandboxingFlagSet,
4080 can_gc: CanGc,
4081 ) -> DomRoot<Document> {
4082 let document = reflect_dom_object_with_proto(
4083 Box::new(Document::new_inherited(
4084 window,
4085 has_browsing_context,
4086 url,
4087 about_base_url,
4088 origin,
4089 doctype,
4090 content_type,
4091 last_modified,
4092 activity,
4093 source,
4094 doc_loader,
4095 referrer,
4096 status_code,
4097 canceller,
4098 is_initial_about_blank,
4099 allow_declarative_shadow_roots,
4100 inherited_insecure_requests_policy,
4101 has_trustworthy_ancestor_origin,
4102 custom_element_reaction_stack,
4103 creation_sandboxing_flag_set,
4104 )),
4105 window,
4106 proto,
4107 can_gc,
4108 );
4109 {
4110 let node = document.upcast::<Node>();
4111 node.set_owner_doc(&document);
4112 }
4113 document
4114 }
4115
4116 pub(crate) fn get_redirect_count(&self) -> u16 {
4117 self.redirect_count.get()
4118 }
4119
4120 pub(crate) fn set_redirect_count(&self, count: u16) {
4121 self.redirect_count.set(count)
4122 }
4123
4124 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4125 if name.is_empty() {
4126 return 0;
4127 }
4128 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4129 }
4130
4131 pub(crate) fn nth_element_by_name(
4132 &self,
4133 index: u32,
4134 name: &DOMString,
4135 ) -> Option<DomRoot<Node>> {
4136 if name.is_empty() {
4137 return None;
4138 }
4139 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4140 }
4141
4142 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4145 let element = match node.downcast::<Element>() {
4146 Some(element) => element,
4147 None => return false,
4148 };
4149 if element.namespace() != &ns!(html) {
4150 return false;
4151 }
4152 element.get_name().is_some_and(|n| &*n == name)
4153 }
4154
4155 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4156 let doc = self.GetDocumentElement();
4157 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4158 maybe_node
4159 .iter()
4160 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4161 .filter(|node| callback(node))
4162 .count() as u32
4163 }
4164
4165 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4166 &self,
4167 index: u32,
4168 callback: F,
4169 ) -> Option<DomRoot<Node>> {
4170 let doc = self.GetDocumentElement();
4171 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4172 maybe_node
4173 .iter()
4174 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4175 .filter(|node| callback(node))
4176 .nth(index as usize)
4177 .map(|n| DomRoot::from_ref(&*n))
4178 }
4179
4180 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4181 self.GetDocumentElement().and_then(DomRoot::downcast)
4182 }
4183
4184 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
4186 &self.style_shared_lock
4187 }
4188
4189 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4191 let mut stylesheets = self.stylesheets.borrow_mut();
4198 let have_changed = stylesheets.has_changed();
4199 stylesheets.flush_without_invalidation();
4200 have_changed
4201 }
4202
4203 pub(crate) fn salvageable(&self) -> bool {
4204 self.salvageable.get()
4205 }
4206
4207 pub(crate) fn appropriate_template_contents_owner_document(
4209 &self,
4210 can_gc: CanGc,
4211 ) -> DomRoot<Document> {
4212 self.appropriate_template_contents_owner_document
4213 .or_init(|| {
4214 let doctype = if self.is_html_document {
4215 IsHTMLDocument::HTMLDocument
4216 } else {
4217 IsHTMLDocument::NonHTMLDocument
4218 };
4219 let new_doc = Document::new(
4220 self.window(),
4221 HasBrowsingContext::No,
4222 None,
4223 None,
4224 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4226 doctype,
4227 None,
4228 None,
4229 DocumentActivity::Inactive,
4230 DocumentSource::NotFromParser,
4231 DocumentLoader::new(&self.loader()),
4232 None,
4233 None,
4234 Default::default(),
4235 false,
4236 self.allow_declarative_shadow_roots(),
4237 Some(self.insecure_requests_policy()),
4238 self.has_trustworthy_ancestor_or_current_origin(),
4239 self.custom_element_reaction_stack.clone(),
4240 self.creation_sandboxing_flag_set(),
4241 can_gc,
4242 );
4243 new_doc
4244 .appropriate_template_contents_owner_document
4245 .set(Some(&new_doc));
4246 new_doc
4247 })
4248 }
4249
4250 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4251 self.id_map
4252 .borrow()
4253 .get(id)
4254 .map(|elements| DomRoot::from_ref(&*elements[0]))
4255 }
4256
4257 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4258 let map = self.pending_restyles.borrow_mut();
4259 RefMut::map(map, |m| {
4260 &mut m
4261 .entry(Dom::from_ref(el))
4262 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4263 .0
4264 })
4265 }
4266
4267 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4268 let mut entry = self.ensure_pending_restyle(el);
4274 if entry.snapshot.is_none() {
4275 entry.snapshot = Some(Snapshot::new());
4276 }
4277 if attr.local_name() == &local_name!("style") {
4278 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4279 }
4280
4281 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4282 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4283 }
4284
4285 let snapshot = entry.snapshot.as_mut().unwrap();
4286 if attr.local_name() == &local_name!("id") {
4287 if snapshot.id_changed {
4288 return;
4289 }
4290 snapshot.id_changed = true;
4291 } else if attr.local_name() == &local_name!("class") {
4292 if snapshot.class_changed {
4293 return;
4294 }
4295 snapshot.class_changed = true;
4296 } else {
4297 snapshot.other_attributes_changed = true;
4298 }
4299 let local_name = style::LocalName::cast(attr.local_name());
4300 if !snapshot.changed_attrs.contains(local_name) {
4301 snapshot.changed_attrs.push(local_name.clone());
4302 }
4303 if snapshot.attrs.is_none() {
4304 let attrs = el
4305 .attrs()
4306 .iter()
4307 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4308 .collect();
4309 snapshot.attrs = Some(attrs);
4310 }
4311 }
4312
4313 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4314 self.policy_container
4315 .borrow_mut()
4316 .set_referrer_policy(policy);
4317 }
4318
4319 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4320 self.policy_container.borrow().get_referrer_policy()
4321 }
4322
4323 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4324 if let Some(ref element) = self.target_element.get() {
4325 element.set_target_state(false);
4326 }
4327
4328 self.target_element.set(node);
4329
4330 if let Some(ref element) = self.target_element.get() {
4331 element.set_target_state(true);
4332 }
4333 }
4334
4335 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4336 self.ignore_destructive_writes_counter
4337 .set(self.ignore_destructive_writes_counter.get() + 1);
4338 }
4339
4340 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4341 self.ignore_destructive_writes_counter
4342 .set(self.ignore_destructive_writes_counter.get() - 1);
4343 }
4344
4345 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4346 self.ignore_opens_during_unload_counter.get() > 0
4347 }
4348
4349 fn incr_ignore_opens_during_unload_counter(&self) {
4350 self.ignore_opens_during_unload_counter
4351 .set(self.ignore_opens_during_unload_counter.get() + 1);
4352 }
4353
4354 fn decr_ignore_opens_during_unload_counter(&self) {
4355 self.ignore_opens_during_unload_counter
4356 .set(self.ignore_opens_during_unload_counter.get() - 1);
4357 }
4358
4359 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4361 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4368 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4369
4370 if !self.is_fully_active() {
4373 promise.reject_error(
4374 Error::Type(c"Document is not fully active".to_owned()),
4375 can_gc,
4376 );
4377 return promise;
4378 }
4379
4380 let mut error = false;
4383
4384 {
4387 match *pending.namespace() {
4389 ns!(mathml) => {
4390 if pending.local_name().as_ref() != "math" {
4391 error = true;
4392 }
4393 },
4394 ns!(svg) => {
4395 if pending.local_name().as_ref() != "svg" {
4396 error = true;
4397 }
4398 },
4399 ns!(html) => (),
4400 _ => error = true,
4401 }
4402
4403 if pending.is::<HTMLDialogElement>() {
4405 error = true;
4406 }
4407
4408 if !pending.fullscreen_element_ready_check() {
4410 error = true;
4411 }
4412
4413 if !pending.owner_window().has_transient_activation() {
4421 error = true;
4422 }
4423 }
4424
4425 if pref!(dom_fullscreen_test) {
4426 info!("Tests don't really enter fullscreen.");
4429 } else {
4430 warn!("Fullscreen not supported yet");
4433 }
4434
4435 if !error {
4438 pending.owner_window().consume_user_activation();
4439 }
4440
4441 if !error {
4447 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4448 self.send_to_embedder(event);
4449 }
4450
4451 let pipeline_id = self.window().pipeline_id();
4454
4455 let trusted_pending = Trusted::new(pending);
4456 let trusted_pending_doc = Trusted::new(self);
4457 let trusted_promise = TrustedPromise::new(promise.clone());
4458 let handler = ElementPerformFullscreenEnter::new(
4459 trusted_pending,
4460 trusted_pending_doc,
4461 trusted_promise,
4462 error,
4463 );
4464 let script_msg = CommonScriptMsg::Task(
4465 ScriptThreadEventCategory::EnterFullscreen,
4466 handler,
4467 Some(pipeline_id),
4468 TaskSourceName::DOMManipulation,
4469 );
4470 let msg = MainThreadScriptMsg::Common(script_msg);
4471 self.window().main_thread_script_chan().send(msg).unwrap();
4472
4473 promise
4474 }
4475
4476 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4478 let global = self.global();
4479
4480 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4483 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4484
4485 if !self.is_fully_active() || self.fullscreen_element.get().is_none() {
4488 promise.reject_error(
4489 Error::Type(
4490 c"No fullscreen element to exit or document is not fully active".to_owned(),
4491 ),
4492 can_gc,
4493 );
4494 return promise;
4495 }
4496
4497 let element = self.fullscreen_element.get().unwrap();
4500 let window = self.window();
4501
4502 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4506 self.send_to_embedder(event);
4507
4508 let trusted_element = Trusted::new(&*element);
4511 let trusted_promise = TrustedPromise::new(promise.clone());
4512 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4513 let pipeline_id = Some(global.pipeline_id());
4514 let script_msg = CommonScriptMsg::Task(
4515 ScriptThreadEventCategory::ExitFullscreen,
4516 handler,
4517 pipeline_id,
4518 TaskSourceName::DOMManipulation,
4519 );
4520 let msg = MainThreadScriptMsg::Common(script_msg);
4521 window.main_thread_script_chan().send(msg).unwrap();
4522
4523 promise
4524 }
4525
4526 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4527 self.fullscreen_element.set(element);
4528 }
4529
4530 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4531 match self.browsing_context() {
4533 None => false,
4535 Some(_) => {
4536 let window = self.window();
4538 if window.is_top_level() {
4539 true
4540 } else {
4541 window
4543 .GetFrameElement()
4544 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4545 }
4546 },
4547 }
4548 }
4549
4550 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4551 let map = self.form_id_listener_map.borrow();
4552 if let Some(listeners) = map.get(id) {
4553 for listener in listeners {
4554 listener
4555 .as_maybe_form_control()
4556 .expect("Element must be a form control")
4557 .reset_form_owner(can_gc);
4558 }
4559 }
4560 }
4561
4562 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4563 self.shadow_roots
4564 .borrow_mut()
4565 .insert(Dom::from_ref(shadow_root));
4566 self.invalidate_shadow_roots_stylesheets();
4567 }
4568
4569 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4570 let mut shadow_roots = self.shadow_roots.borrow_mut();
4571 shadow_roots.remove(&Dom::from_ref(shadow_root));
4572 }
4573
4574 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4575 self.shadow_roots_styles_changed.set(true);
4576 }
4577
4578 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4579 self.shadow_roots_styles_changed.get()
4580 }
4581
4582 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4583 if !self.shadow_roots_styles_changed.get() {
4584 return;
4585 }
4586 self.shadow_roots_styles_changed.set(false);
4587 }
4588
4589 pub(crate) fn stylesheet_count(&self) -> usize {
4590 self.stylesheets.borrow().len()
4591 }
4592
4593 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4594 let stylesheets = self.stylesheets.borrow();
4595
4596 stylesheets
4597 .get(Origin::Author, index)
4598 .and_then(|s| s.owner.get_cssom_object())
4599 }
4600
4601 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4608 let stylesheets = &mut *self.stylesheets.borrow_mut();
4609
4610 let insertion_point = stylesheets
4612 .iter()
4613 .map(|(sheet, _origin)| sheet)
4614 .find(|sheet_in_doc| {
4615 match &sheet_in_doc.owner {
4616 StylesheetSource::Element(other_node) => {
4617 owner_node.upcast::<Node>().is_before(other_node.upcast())
4618 },
4619 StylesheetSource::Constructed(_) => true,
4622 }
4623 })
4624 .cloned();
4625
4626 if self.has_browsing_context() {
4627 let document_context = self.window.web_font_context();
4628
4629 self.window.layout_mut().add_stylesheet(
4630 sheet.clone(),
4631 insertion_point.as_ref().map(|s| s.sheet.clone()),
4632 &document_context,
4633 );
4634 }
4635
4636 DocumentOrShadowRoot::add_stylesheet(
4637 StylesheetSource::Element(Dom::from_ref(owner_node)),
4638 StylesheetSetRef::Document(stylesheets),
4639 sheet,
4640 insertion_point,
4641 self.style_shared_lock(),
4642 );
4643 }
4644
4645 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4650 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4651 debug_assert!(cssom_stylesheet.is_constructed());
4652
4653 let stylesheets = &mut *self.stylesheets.borrow_mut();
4654 let sheet = cssom_stylesheet.style_stylesheet().clone();
4655
4656 let insertion_point = stylesheets
4657 .iter()
4658 .last()
4659 .map(|(sheet, _origin)| sheet)
4660 .cloned();
4661
4662 if self.has_browsing_context() {
4663 self.window.layout_mut().add_stylesheet(
4664 sheet.clone(),
4665 insertion_point.as_ref().map(|s| s.sheet.clone()),
4666 &self.window.web_font_context(),
4667 );
4668 }
4669
4670 DocumentOrShadowRoot::add_stylesheet(
4671 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4672 StylesheetSetRef::Document(stylesheets),
4673 sheet,
4674 insertion_point,
4675 self.style_shared_lock(),
4676 );
4677 }
4678
4679 pub(crate) fn load_web_fonts_from_stylesheet(
4681 &self,
4682 stylesheet: &Arc<Stylesheet>,
4683 document_context: &WebFontDocumentContext,
4684 ) {
4685 self.window
4686 .layout()
4687 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4688 }
4689
4690 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4693 if self.has_browsing_context() {
4694 self.window
4695 .layout_mut()
4696 .remove_stylesheet(stylesheet.clone());
4697 }
4698
4699 DocumentOrShadowRoot::remove_stylesheet(
4700 owner,
4701 stylesheet,
4702 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4703 )
4704 }
4705
4706 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4707 Ref::map(self.id_map.borrow(), |map| {
4708 map.get(id).map(|vec| &**vec).unwrap_or_default()
4709 })
4710 }
4711
4712 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4713 Ref::map(self.name_map.borrow(), |map| {
4714 map.get(name).map(|vec| &**vec).unwrap_or_default()
4715 })
4716 }
4717
4718 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4719 self.pending_restyles
4720 .borrow_mut()
4721 .drain()
4722 .filter_map(|(elem, restyle)| {
4723 let node = elem.upcast::<Node>();
4724 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4725 return None;
4726 }
4727 node.note_dirty_descendants();
4728 Some((node.to_trusted_node_address(), restyle.0))
4729 })
4730 .collect()
4731 }
4732
4733 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4734 self.animation_timeline.borrow_mut().advance_specific(delta);
4735 let current_timeline_value = self.current_animation_timeline_value();
4736 self.animations
4737 .update_for_new_timeline_value(&self.window, current_timeline_value);
4738 }
4739
4740 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4741 let current_timeline_value = self.current_animation_timeline_value();
4742 self.animations
4743 .mark_animating_nodes_as_dirty(current_timeline_value);
4744 }
4745
4746 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4747 self.animation_timeline.borrow().current_value()
4748 }
4749
4750 pub(crate) fn animations(&self) -> &Animations {
4751 &self.animations
4752 }
4753
4754 pub(crate) fn update_animations_post_reflow(&self) {
4755 self.animations
4756 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4757 self.image_animation_manager
4758 .borrow()
4759 .maybe_schedule_update_after_layout(
4760 &self.window,
4761 self.current_animation_timeline_value(),
4762 );
4763 }
4764
4765 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4766 self.animations.cancel_animations_for_node(node);
4767 self.image_animation_manager
4768 .borrow()
4769 .cancel_animations_for_node(node);
4770 }
4771
4772 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4774 if !self.layout_animations_test_enabled {
4776 self.animation_timeline.borrow_mut().update();
4777 }
4778
4779 let current_timeline_value = self.current_animation_timeline_value();
4786 self.animations
4787 .update_for_new_timeline_value(&self.window, current_timeline_value);
4788 self.maybe_mark_animating_nodes_as_dirty();
4789
4790 self.window().perform_a_microtask_checkpoint(can_gc);
4792
4793 let _realm = enter_realm(self);
4795 self.animations().send_pending_events(self.window(), can_gc);
4796 }
4797
4798 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4799 self.image_animation_manager.borrow()
4800 }
4801
4802 pub(crate) fn set_has_pending_animated_image_update(&self) {
4803 self.has_pending_animated_image_update.set(true);
4804 }
4805
4806 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4808 if self.will_declaratively_refresh() {
4810 return;
4811 }
4812
4813 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4815 Regex::new(
4819 r#"(?xs)
4820 ^
4821 \s* # 3
4822 ((?<time>[0-9]+)|\.) # 5-6
4823 [0-9.]* # 8
4824 (
4825 (
4826 (\s*;|\s*,|\s) # 10.3
4827 \s* # 10.4
4828 )
4829 (
4830 (
4831 (U|u)(R|r)(L|l) # 11.2-11.4
4832 \s*=\s* # 11.5-11.7
4833 )?
4834 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4835 |
4836 (?<url4>(?s-u:.)*)
4837 )
4838 )?
4839 $
4840 "#,
4841 )
4842 .unwrap()
4843 });
4844
4845 let mut url_record = self.url();
4847 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4848 captures
4849 } else {
4850 return;
4851 };
4852 let time = if let Some(time_string) = captures.name("time") {
4853 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4854 } else {
4855 0
4856 };
4857 let captured_url = captures.name("url1").or(captures
4858 .name("url2")
4859 .or(captures.name("url3").or(captures.name("url4"))));
4860
4861 if let Some(url_match) = captured_url {
4863 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4864 Some(&url_record),
4865 &String::from_utf8_lossy(url_match.as_bytes()),
4866 ) {
4867 info!("Refresh to {}", url.debug_compact());
4868 url
4869 } else {
4870 return;
4872 }
4873 }
4874 if self.completely_loaded() {
4876 self.window.as_global_scope().schedule_callback(
4878 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4879 window: DomRoot::from_ref(self.window()),
4880 url: url_record,
4881 }),
4882 Duration::from_secs(time),
4883 );
4884 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4885 } else {
4886 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4887 url: url_record,
4888 time,
4889 });
4890 }
4891 }
4892
4893 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4894 self.declarative_refresh.borrow().is_some()
4895 }
4896 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4897 *self.declarative_refresh.borrow_mut() = Some(refresh);
4898 }
4899
4900 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4902 if self.visibility_state.get() == visibility_state {
4904 return;
4905 }
4906 self.visibility_state.set(visibility_state);
4908 let entry = VisibilityStateEntry::new(
4911 &self.global(),
4912 visibility_state,
4913 CrossProcessInstant::now(),
4914 can_gc,
4915 );
4916 self.window
4917 .Performance()
4918 .queue_entry(entry.upcast::<PerformanceEntry>());
4919
4920 #[cfg(feature = "gamepad")]
4931 if visibility_state == DocumentVisibilityState::Hidden {
4932 self.window
4933 .Navigator()
4934 .GetGamepads()
4935 .iter_mut()
4936 .for_each(|gamepad| {
4937 if let Some(g) = gamepad {
4938 g.vibration_actuator().handle_visibility_change();
4939 }
4940 });
4941 }
4942
4943 self.upcast::<EventTarget>()
4945 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4946 }
4947
4948 pub(crate) fn is_initial_about_blank(&self) -> bool {
4950 self.is_initial_about_blank.get()
4951 }
4952
4953 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4955 self.allow_declarative_shadow_roots.get()
4956 }
4957
4958 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4959 self.has_trustworthy_ancestor_origin.get()
4960 }
4961
4962 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4963 self.has_trustworthy_ancestor_origin.get() ||
4964 self.origin().immutable().is_potentially_trustworthy()
4965 }
4966
4967 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4968 self.highlighted_dom_node.set(node);
4969 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4970 }
4971
4972 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4973 self.highlighted_dom_node.get()
4974 }
4975
4976 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4977 self.custom_element_reaction_stack.clone()
4978 }
4979
4980 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4981 self.active_sandboxing_flag_set.get().contains(flag)
4982 }
4983
4984 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4985 self.active_sandboxing_flag_set.set(flags)
4986 }
4987
4988 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4989 self.creation_sandboxing_flag_set.get()
4990 }
4991
4992 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4993 &self,
4994 ) -> SandboxingFlagSet {
4995 self.window()
4996 .window_proxy()
4997 .frame_element()
4998 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4999 .map(HTMLIFrameElement::sandboxing_flag_set)
5000 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
5001 }
5002
5003 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
5004 self.window()
5005 .scrolling_box_query(None, flags)
5006 .expect("We should always have a ScrollingBox for the Viewport")
5007 }
5008
5009 pub(crate) fn notify_embedder_favicon(&self) {
5010 if let Some(ref image) = *self.favicon.borrow() {
5011 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
5012 }
5013 }
5014
5015 pub(crate) fn set_favicon(&self, favicon: Image) {
5016 *self.favicon.borrow_mut() = Some(favicon);
5017 self.notify_embedder_favicon();
5018 }
5019
5020 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
5021 self.fullscreen_element.get()
5022 }
5023}
5024
5025impl DocumentMethods<crate::DomTypeHolder> for Document {
5026 fn Constructor(
5028 window: &Window,
5029 proto: Option<HandleObject>,
5030 can_gc: CanGc,
5031 ) -> Fallible<DomRoot<Document>> {
5032 let doc = window.Document();
5034 let docloader = DocumentLoader::new(&doc.loader());
5035 Ok(Document::new_with_proto(
5036 window,
5037 proto,
5038 HasBrowsingContext::No,
5039 None,
5040 None,
5041 doc.origin().clone(),
5042 IsHTMLDocument::NonHTMLDocument,
5043 None,
5044 None,
5045 DocumentActivity::Inactive,
5046 DocumentSource::NotFromParser,
5047 docloader,
5048 None,
5049 None,
5050 Default::default(),
5051 false,
5052 doc.allow_declarative_shadow_roots(),
5053 Some(doc.insecure_requests_policy()),
5054 doc.has_trustworthy_ancestor_or_current_origin(),
5055 doc.custom_element_reaction_stack(),
5056 doc.active_sandboxing_flag_set.get(),
5057 can_gc,
5058 ))
5059 }
5060
5061 fn ParseHTMLUnsafe(
5063 window: &Window,
5064 s: TrustedHTMLOrString,
5065 can_gc: CanGc,
5066 ) -> Fallible<DomRoot<Self>> {
5067 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
5071 window.as_global_scope(),
5072 s,
5073 "Document parseHTMLUnsafe",
5074 can_gc,
5075 )?;
5076
5077 let url = window.get_url();
5078 let doc = window.Document();
5079 let loader = DocumentLoader::new(&doc.loader());
5080
5081 let content_type = "text/html"
5082 .parse()
5083 .expect("Supported type is not a MIME type");
5084 let document = Document::new(
5087 window,
5088 HasBrowsingContext::No,
5089 Some(ServoUrl::parse("about:blank").unwrap()),
5090 None,
5091 doc.origin().clone(),
5092 IsHTMLDocument::HTMLDocument,
5093 Some(content_type),
5094 None,
5095 DocumentActivity::Inactive,
5096 DocumentSource::FromParser,
5097 loader,
5098 None,
5099 None,
5100 Default::default(),
5101 false,
5102 true,
5103 Some(doc.insecure_requests_policy()),
5104 doc.has_trustworthy_ancestor_or_current_origin(),
5105 doc.custom_element_reaction_stack(),
5106 doc.creation_sandboxing_flag_set(),
5107 can_gc,
5108 );
5109 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, can_gc);
5111 document.set_ready_state(DocumentReadyState::Complete, can_gc);
5113 Ok(document)
5114 }
5115
5116 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
5118 false
5119 }
5120
5121 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
5123 self.stylesheet_list.or_init(|| {
5124 StyleSheetList::new(
5125 &self.window,
5126 StyleSheetListOwner::Document(Dom::from_ref(self)),
5127 can_gc,
5128 )
5129 })
5130 }
5131
5132 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
5134 self.implementation
5135 .or_init(|| DOMImplementation::new(self, can_gc))
5136 }
5137
5138 fn URL(&self) -> USVString {
5140 USVString(String::from(self.url().as_str()))
5141 }
5142
5143 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5145 self.document_or_shadow_root.get_active_element(
5146 self.get_focused_element(),
5147 self.GetBody(),
5148 self.GetDocumentElement(),
5149 )
5150 }
5151
5152 fn HasFocus(&self) -> bool {
5154 if self.window().parent_info().is_none() {
5176 self.is_fully_active()
5178 } else {
5179 self.is_fully_active() && self.has_focus.get()
5181 }
5182 }
5183
5184 fn Domain(&self) -> DOMString {
5186 match self.origin.effective_domain() {
5188 None => DOMString::new(),
5190 Some(Host::Domain(domain)) => DOMString::from(domain),
5192 Some(host) => DOMString::from(host.to_string()),
5193 }
5194 }
5195
5196 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5198 if !self.has_browsing_context {
5200 return Err(Error::Security(None));
5201 }
5202
5203 if self.has_active_sandboxing_flag(
5206 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5207 ) {
5208 return Err(Error::Security(None));
5209 }
5210
5211 let effective_domain = match self.origin.effective_domain() {
5213 Some(effective_domain) => effective_domain,
5214 None => return Err(Error::Security(None)),
5216 };
5217
5218 let host =
5220 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5221 None => return Err(Error::Security(None)),
5222 Some(host) => host,
5223 };
5224
5225 self.origin.set_domain(host);
5230
5231 Ok(())
5232 }
5233
5234 fn Referrer(&self) -> DOMString {
5236 match self.referrer {
5237 Some(ref referrer) => DOMString::from(referrer.to_string()),
5238 None => DOMString::new(),
5239 }
5240 }
5241
5242 fn DocumentURI(&self) -> USVString {
5244 self.URL()
5245 }
5246
5247 fn CompatMode(&self) -> DOMString {
5249 DOMString::from(match self.quirks_mode.get() {
5250 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5251 QuirksMode::Quirks => "BackCompat",
5252 })
5253 }
5254
5255 fn CharacterSet(&self) -> DOMString {
5257 DOMString::from(self.encoding.get().name())
5258 }
5259
5260 fn Charset(&self) -> DOMString {
5262 self.CharacterSet()
5263 }
5264
5265 fn InputEncoding(&self) -> DOMString {
5267 self.CharacterSet()
5268 }
5269
5270 fn ContentType(&self) -> DOMString {
5272 DOMString::from(self.content_type.to_string())
5273 }
5274
5275 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5277 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5278 }
5279
5280 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5282 self.upcast::<Node>().child_elements().next()
5283 }
5284
5285 fn GetElementsByTagName(
5287 &self,
5288 qualified_name: DOMString,
5289 can_gc: CanGc,
5290 ) -> DomRoot<HTMLCollection> {
5291 let qualified_name = LocalName::from(qualified_name);
5292 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5293 return DomRoot::from_ref(entry);
5294 }
5295 let result = HTMLCollection::by_qualified_name(
5296 &self.window,
5297 self.upcast(),
5298 qualified_name.clone(),
5299 can_gc,
5300 );
5301 self.tag_map
5302 .borrow_mut()
5303 .insert(qualified_name, Dom::from_ref(&*result));
5304 result
5305 }
5306
5307 fn GetElementsByTagNameNS(
5309 &self,
5310 maybe_ns: Option<DOMString>,
5311 tag_name: DOMString,
5312 can_gc: CanGc,
5313 ) -> DomRoot<HTMLCollection> {
5314 let ns = namespace_from_domstring(maybe_ns);
5315 let local = LocalName::from(tag_name);
5316 let qname = QualName::new(None, ns, local);
5317 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5318 return DomRoot::from_ref(collection);
5319 }
5320 let result =
5321 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
5322 self.tagns_map
5323 .borrow_mut()
5324 .insert(qname, Dom::from_ref(&*result));
5325 result
5326 }
5327
5328 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5330 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5331 .map(Atom::from)
5332 .collect();
5333 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5334 return DomRoot::from_ref(collection);
5335 }
5336 let result = HTMLCollection::by_atomic_class_name(
5337 &self.window,
5338 self.upcast(),
5339 class_atoms.clone(),
5340 can_gc,
5341 );
5342 self.classes_map
5343 .borrow_mut()
5344 .insert(class_atoms, Dom::from_ref(&*result));
5345 result
5346 }
5347
5348 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5350 self.get_element_by_id(&Atom::from(id))
5351 }
5352
5353 fn CreateElement(
5355 &self,
5356 mut local_name: DOMString,
5357 options: StringOrElementCreationOptions,
5358 can_gc: CanGc,
5359 ) -> Fallible<DomRoot<Element>> {
5360 if !is_valid_element_local_name(&local_name.str()) {
5363 debug!("Not a valid element name");
5364 return Err(Error::InvalidCharacter(None));
5365 }
5366
5367 if self.is_html_document {
5368 local_name.make_ascii_lowercase();
5369 }
5370
5371 let ns = if self.is_html_document || self.is_xhtml_document() {
5372 ns!(html)
5373 } else {
5374 ns!()
5375 };
5376
5377 let name = QualName::new(None, ns, LocalName::from(local_name));
5378 let is = match options {
5379 StringOrElementCreationOptions::String(_) => None,
5380 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5381 options.is.as_ref().map(LocalName::from)
5382 },
5383 };
5384 Ok(Element::create(
5385 name,
5386 is,
5387 self,
5388 ElementCreator::ScriptCreated,
5389 CustomElementCreationMode::Synchronous,
5390 None,
5391 can_gc,
5392 ))
5393 }
5394
5395 fn CreateElementNS(
5397 &self,
5398 namespace: Option<DOMString>,
5399 qualified_name: DOMString,
5400 options: StringOrElementCreationOptions,
5401 can_gc: CanGc,
5402 ) -> Fallible<DomRoot<Element>> {
5403 let context = domname::Context::Element;
5406 let (namespace, prefix, local_name) =
5407 domname::validate_and_extract(namespace, &qualified_name, context)?;
5408
5409 let name = QualName::new(prefix, namespace, local_name);
5412 let is = match options {
5413 StringOrElementCreationOptions::String(_) => None,
5414 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5415 options.is.as_ref().map(LocalName::from)
5416 },
5417 };
5418
5419 Ok(Element::create(
5421 name,
5422 is,
5423 self,
5424 ElementCreator::ScriptCreated,
5425 CustomElementCreationMode::Synchronous,
5426 None,
5427 can_gc,
5428 ))
5429 }
5430
5431 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5433 if !is_valid_attribute_local_name(&local_name.str()) {
5436 debug!("Not a valid attribute name");
5437 return Err(Error::InvalidCharacter(None));
5438 }
5439 if self.is_html_document {
5440 local_name.make_ascii_lowercase();
5441 }
5442 let name = LocalName::from(local_name);
5443 let value = AttrValue::String("".to_owned());
5444
5445 Ok(Attr::new(
5446 self,
5447 name.clone(),
5448 value,
5449 name,
5450 ns!(),
5451 None,
5452 None,
5453 can_gc,
5454 ))
5455 }
5456
5457 fn CreateAttributeNS(
5459 &self,
5460 namespace: Option<DOMString>,
5461 qualified_name: DOMString,
5462 can_gc: CanGc,
5463 ) -> Fallible<DomRoot<Attr>> {
5464 let context = domname::Context::Attribute;
5467 let (namespace, prefix, local_name) =
5468 domname::validate_and_extract(namespace, &qualified_name, context)?;
5469 let value = AttrValue::String("".to_owned());
5470 let qualified_name = LocalName::from(qualified_name);
5471 Ok(Attr::new(
5472 self,
5473 local_name,
5474 value,
5475 qualified_name,
5476 namespace,
5477 prefix,
5478 None,
5479 can_gc,
5480 ))
5481 }
5482
5483 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5485 DocumentFragment::new(self, can_gc)
5486 }
5487
5488 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5490 Text::new(data, self, can_gc)
5491 }
5492
5493 fn CreateCDATASection(
5495 &self,
5496 data: DOMString,
5497 can_gc: CanGc,
5498 ) -> Fallible<DomRoot<CDATASection>> {
5499 if self.is_html_document {
5501 return Err(Error::NotSupported(None));
5502 }
5503
5504 if data.contains("]]>") {
5506 return Err(Error::InvalidCharacter(None));
5507 }
5508
5509 Ok(CDATASection::new(data, self, can_gc))
5511 }
5512
5513 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5515 Comment::new(data, self, None, can_gc)
5516 }
5517
5518 fn CreateProcessingInstruction(
5520 &self,
5521 target: DOMString,
5522 data: DOMString,
5523 can_gc: CanGc,
5524 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5525 if !matches_name_production(&target.str()) {
5527 return Err(Error::InvalidCharacter(None));
5528 }
5529
5530 if data.contains("?>") {
5532 return Err(Error::InvalidCharacter(None));
5533 }
5534
5535 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5537 }
5538
5539 fn ImportNode(
5541 &self,
5542 node: &Node,
5543 options: BooleanOrImportNodeOptions,
5544 can_gc: CanGc,
5545 ) -> Fallible<DomRoot<Node>> {
5546 if node.is::<Document>() || node.is::<ShadowRoot>() {
5548 return Err(Error::NotSupported(None));
5549 }
5550 let (subtree, registry) = match options {
5552 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5555 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5557 let subtree = (!options.selfOnly).into();
5559 let registry = options.customElementRegistry;
5561 (subtree, registry)
5565 },
5566 };
5567 let registry = registry
5570 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5571
5572 Ok(Node::clone(node, Some(self), subtree, registry, can_gc))
5575 }
5576
5577 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5579 if node.is::<Document>() {
5581 return Err(Error::NotSupported(None));
5582 }
5583
5584 if node.is::<ShadowRoot>() {
5586 return Err(Error::HierarchyRequest(None));
5587 }
5588
5589 Node::adopt(node, self, can_gc);
5591
5592 Ok(DomRoot::from_ref(node))
5594 }
5595
5596 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5598 interface.make_ascii_lowercase();
5599 match &*interface.str() {
5600 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5601 &self.window,
5602 can_gc,
5603 ))),
5604 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5605 CompositionEvent::new_uninitialized(&self.window, can_gc),
5606 )),
5607 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5608 self.window.upcast(),
5609 can_gc,
5610 ))),
5611 "events" | "event" | "htmlevents" | "svgevents" => {
5614 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5615 },
5616 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5617 &self.window,
5618 can_gc,
5619 ))),
5620 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5621 &self.window,
5622 can_gc,
5623 ))),
5624 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5625 &self.window,
5626 can_gc,
5627 ))),
5628 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5629 self.window.upcast(),
5630 can_gc,
5631 ))),
5632 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5633 &self.window,
5634 can_gc,
5635 ))),
5636 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5637 &self.window,
5638 "".into(),
5639 can_gc,
5640 ))),
5641 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5642 &self.window,
5643 &TouchList::new(&self.window, &[], can_gc),
5644 &TouchList::new(&self.window, &[], can_gc),
5645 &TouchList::new(&self.window, &[], can_gc),
5646 can_gc,
5647 ))),
5648 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5649 &self.window,
5650 can_gc,
5651 ))),
5652 _ => Err(Error::NotSupported(None)),
5653 }
5654 }
5655
5656 fn LastModified(&self) -> DOMString {
5658 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5659 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5665 }))
5666 }
5667
5668 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5670 Range::new_with_doc(self, None, can_gc)
5671 }
5672
5673 fn CreateNodeIterator(
5675 &self,
5676 root: &Node,
5677 what_to_show: u32,
5678 filter: Option<Rc<NodeFilter>>,
5679 can_gc: CanGc,
5680 ) -> DomRoot<NodeIterator> {
5681 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5682 }
5683
5684 fn CreateTreeWalker(
5686 &self,
5687 root: &Node,
5688 what_to_show: u32,
5689 filter: Option<Rc<NodeFilter>>,
5690 ) -> DomRoot<TreeWalker> {
5691 TreeWalker::new(self, root, what_to_show, filter)
5692 }
5693
5694 fn Title(&self) -> DOMString {
5696 self.title().unwrap_or_else(|| DOMString::from(""))
5697 }
5698
5699 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5701 let root = match self.GetDocumentElement() {
5702 Some(root) => root,
5703 None => return,
5704 };
5705
5706 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5707 let elem = root.upcast::<Node>().child_elements().find(|node| {
5708 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5709 });
5710 match elem {
5711 Some(elem) => DomRoot::upcast::<Node>(elem),
5712 None => {
5713 let name = QualName::new(None, ns!(svg), local_name!("title"));
5714 let elem = Element::create(
5715 name,
5716 None,
5717 self,
5718 ElementCreator::ScriptCreated,
5719 CustomElementCreationMode::Synchronous,
5720 None,
5721 can_gc,
5722 );
5723 let parent = root.upcast::<Node>();
5724 let child = elem.upcast::<Node>();
5725 parent
5726 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5727 .unwrap()
5728 },
5729 }
5730 } else if root.namespace() == &ns!(html) {
5731 let elem = root
5732 .upcast::<Node>()
5733 .traverse_preorder(ShadowIncluding::No)
5734 .find(|node| node.is::<HTMLTitleElement>());
5735 match elem {
5736 Some(elem) => elem,
5737 None => match self.GetHead() {
5738 Some(head) => {
5739 let name = QualName::new(None, ns!(html), local_name!("title"));
5740 let elem = Element::create(
5741 name,
5742 None,
5743 self,
5744 ElementCreator::ScriptCreated,
5745 CustomElementCreationMode::Synchronous,
5746 None,
5747 can_gc,
5748 );
5749 head.upcast::<Node>()
5750 .AppendChild(elem.upcast(), can_gc)
5751 .unwrap()
5752 },
5753 None => return,
5754 },
5755 }
5756 } else {
5757 return;
5758 };
5759
5760 node.set_text_content_for_element(Some(title), can_gc);
5761 }
5762
5763 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5765 self.get_html_element()
5766 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5767 }
5768
5769 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5771 self.current_script.get()
5772 }
5773
5774 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5776 self.get_html_element().and_then(|root| {
5777 let node = root.upcast::<Node>();
5778 node.children()
5779 .find(|child| {
5780 matches!(
5781 child.type_id(),
5782 NodeTypeId::Element(ElementTypeId::HTMLElement(
5783 HTMLElementTypeId::HTMLBodyElement,
5784 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5785 HTMLElementTypeId::HTMLFrameSetElement,
5786 ))
5787 )
5788 })
5789 .map(|node| DomRoot::downcast(node).unwrap())
5790 })
5791 }
5792
5793 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5795 let new_body = match new_body {
5797 Some(new_body) => new_body,
5798 None => return Err(Error::HierarchyRequest(None)),
5799 };
5800
5801 let node = new_body.upcast::<Node>();
5802 match node.type_id() {
5803 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5804 NodeTypeId::Element(ElementTypeId::HTMLElement(
5805 HTMLElementTypeId::HTMLFrameSetElement,
5806 )) => {},
5807 _ => return Err(Error::HierarchyRequest(None)),
5808 }
5809
5810 let old_body = self.GetBody();
5812 if old_body.as_deref() == Some(new_body) {
5813 return Ok(());
5814 }
5815
5816 match (self.GetDocumentElement(), &old_body) {
5817 (Some(ref root), Some(child)) => {
5819 let root = root.upcast::<Node>();
5820 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5821 .unwrap();
5822 },
5823
5824 (None, _) => return Err(Error::HierarchyRequest(None)),
5826
5827 (Some(ref root), &None) => {
5829 let root = root.upcast::<Node>();
5830 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5831 },
5832 }
5833 Ok(())
5834 }
5835
5836 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5838 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5839 }
5840
5841 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5843 self.images.or_init(|| {
5844 HTMLCollection::new_with_filter_fn(
5845 &self.window,
5846 self.upcast(),
5847 |element, _| element.is::<HTMLImageElement>(),
5848 can_gc,
5849 )
5850 })
5851 }
5852
5853 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5855 self.embeds.or_init(|| {
5856 HTMLCollection::new_with_filter_fn(
5857 &self.window,
5858 self.upcast(),
5859 |element, _| element.is::<HTMLEmbedElement>(),
5860 can_gc,
5861 )
5862 })
5863 }
5864
5865 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5867 self.Embeds(can_gc)
5868 }
5869
5870 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5872 self.links.or_init(|| {
5873 HTMLCollection::new_with_filter_fn(
5874 &self.window,
5875 self.upcast(),
5876 |element, _| {
5877 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5878 element.has_attribute(&local_name!("href"))
5879 },
5880 can_gc,
5881 )
5882 })
5883 }
5884
5885 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5887 self.forms.or_init(|| {
5888 HTMLCollection::new_with_filter_fn(
5889 &self.window,
5890 self.upcast(),
5891 |element, _| element.is::<HTMLFormElement>(),
5892 can_gc,
5893 )
5894 })
5895 }
5896
5897 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5899 self.scripts.or_init(|| {
5900 HTMLCollection::new_with_filter_fn(
5901 &self.window,
5902 self.upcast(),
5903 |element, _| element.is::<HTMLScriptElement>(),
5904 can_gc,
5905 )
5906 })
5907 }
5908
5909 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5911 self.anchors.or_init(|| {
5912 HTMLCollection::new_with_filter_fn(
5913 &self.window,
5914 self.upcast(),
5915 |element, _| {
5916 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5917 },
5918 can_gc,
5919 )
5920 })
5921 }
5922
5923 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5925 self.applets
5926 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5927 }
5928
5929 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5931 if self.is_fully_active() {
5932 Some(self.window.Location())
5933 } else {
5934 None
5935 }
5936 }
5937
5938 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5940 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5941 }
5942
5943 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5945 self.upcast::<Node>().child_elements().next()
5946 }
5947
5948 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5950 self.upcast::<Node>()
5951 .rev_children()
5952 .find_map(DomRoot::downcast)
5953 }
5954
5955 fn ChildElementCount(&self) -> u32 {
5957 self.upcast::<Node>().child_elements().count() as u32
5958 }
5959
5960 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5962 self.upcast::<Node>().prepend(nodes, can_gc)
5963 }
5964
5965 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5967 self.upcast::<Node>().append(nodes, can_gc)
5968 }
5969
5970 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5972 self.upcast::<Node>().replace_children(nodes, can_gc)
5973 }
5974
5975 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5977 let root = self.upcast::<Node>();
5978 root.query_selector(selectors)
5979 }
5980
5981 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5983 let root = self.upcast::<Node>();
5984 root.query_selector_all(selectors)
5985 }
5986
5987 fn ReadyState(&self) -> DocumentReadyState {
5989 self.ready_state.get()
5990 }
5991
5992 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5994 if self.has_browsing_context {
5995 Some(DomRoot::from_ref(&*self.window))
5996 } else {
5997 None
5998 }
5999 }
6000
6001 fn GetCookie(&self) -> Fallible<DOMString> {
6003 if self.is_cookie_averse() {
6004 return Ok(DOMString::new());
6005 }
6006
6007 if !self.origin.is_tuple() {
6008 return Err(Error::Security(None));
6009 }
6010
6011 let url = self.url();
6012 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
6013 let _ = self
6014 .window
6015 .as_global_scope()
6016 .resource_threads()
6017 .send(GetCookiesForUrl(url, tx, NonHTTP));
6018 let cookies = rx.recv().unwrap();
6019 Ok(cookies.map_or(DOMString::new(), DOMString::from))
6020 }
6021
6022 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
6024 if self.is_cookie_averse() {
6025 return Ok(());
6026 }
6027
6028 if !self.origin.is_tuple() {
6029 return Err(Error::Security(None));
6030 }
6031
6032 if !cookie.is_valid_for_cookie() {
6033 return Ok(());
6034 }
6035
6036 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6037 vec![cookie]
6038 } else {
6039 vec![]
6040 };
6041
6042 let _ = self
6043 .window
6044 .as_global_scope()
6045 .resource_threads()
6046 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6047 Ok(())
6048 }
6049
6050 fn BgColor(&self) -> DOMString {
6052 self.get_body_attribute(&local_name!("bgcolor"))
6053 }
6054
6055 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
6057 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
6058 }
6059
6060 fn FgColor(&self) -> DOMString {
6062 self.get_body_attribute(&local_name!("text"))
6063 }
6064
6065 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
6067 self.set_body_attribute(&local_name!("text"), value, can_gc)
6068 }
6069
6070 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
6072 if name.is_empty() {
6073 return None;
6074 }
6075 let name = Atom::from(name);
6076
6077 let elements_with_name = self.get_elements_with_name(&name);
6080 let name_iter = elements_with_name
6081 .iter()
6082 .filter(|elem| is_named_element_with_name_attribute(elem));
6083 let elements_with_id = self.get_elements_with_id(&name);
6084 let id_iter = elements_with_id
6085 .iter()
6086 .filter(|elem| is_named_element_with_id_attribute(elem));
6087 let mut elements = name_iter.chain(id_iter);
6088
6089 let first = elements.next()?;
6096 if elements.all(|other| first == other) {
6097 if let Some(nested_window_proxy) = first
6098 .downcast::<HTMLIFrameElement>()
6099 .and_then(|iframe| iframe.GetContentWindow())
6100 {
6101 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6102 }
6103
6104 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6106 }
6107
6108 #[derive(JSTraceable, MallocSizeOf)]
6111 struct DocumentNamedGetter {
6112 #[no_trace]
6113 name: Atom,
6114 }
6115 impl CollectionFilter for DocumentNamedGetter {
6116 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6117 let type_ = match elem.upcast::<Node>().type_id() {
6118 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6119 _ => return false,
6120 };
6121 match type_ {
6122 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6123 elem.get_name().as_ref() == Some(&self.name)
6124 },
6125 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6126 name == *self.name ||
6127 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6128 }),
6129 _ => false,
6133 }
6134 }
6135 }
6136 let collection = HTMLCollection::create(
6137 self.window(),
6138 self.upcast(),
6139 Box::new(DocumentNamedGetter { name }),
6140 can_gc,
6141 );
6142 Some(NamedPropertyValue::HTMLCollection(collection))
6143 }
6144
6145 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
6147 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
6148
6149 let name_map = self.name_map.borrow();
6150 for (name, elements) in &(name_map).0 {
6151 if name.is_empty() {
6152 continue;
6153 }
6154 let mut name_iter = elements
6155 .iter()
6156 .filter(|elem| is_named_element_with_name_attribute(elem));
6157 if let Some(first) = name_iter.next() {
6158 names_with_first_named_element_map.insert(name, first);
6159 }
6160 }
6161 let id_map = self.id_map.borrow();
6162 for (id, elements) in &(id_map).0 {
6163 if id.is_empty() {
6164 continue;
6165 }
6166 let mut id_iter = elements
6167 .iter()
6168 .filter(|elem| is_named_element_with_id_attribute(elem));
6169 if let Some(first) = id_iter.next() {
6170 match names_with_first_named_element_map.entry(id) {
6171 Vacant(entry) => drop(entry.insert(first)),
6172 Occupied(mut entry) => {
6173 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6174 *entry.get_mut() = first;
6175 }
6176 },
6177 }
6178 }
6179 }
6180
6181 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
6182 names_with_first_named_element_map
6183 .iter()
6184 .map(|(k, v)| (*k, *v))
6185 .collect();
6186 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6187 if a.1 == b.1 {
6188 a.0.cmp(b.0)
6191 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6192 Ordering::Less
6193 } else {
6194 Ordering::Greater
6195 }
6196 });
6197
6198 names_with_first_named_element_vec
6199 .iter()
6200 .map(|(k, _v)| DOMString::from(&***k))
6201 .collect()
6202 }
6203
6204 fn Clear(&self) {
6206 }
6208
6209 fn CaptureEvents(&self) {
6211 }
6213
6214 fn ReleaseEvents(&self) {
6216 }
6218
6219 global_event_handlers!();
6221
6222 event_handler!(
6224 readystatechange,
6225 GetOnreadystatechange,
6226 SetOnreadystatechange
6227 );
6228
6229 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6231 self.document_or_shadow_root.element_from_point(
6232 x,
6233 y,
6234 self.GetDocumentElement(),
6235 self.has_browsing_context,
6236 )
6237 }
6238
6239 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6241 self.document_or_shadow_root.elements_from_point(
6242 x,
6243 y,
6244 self.GetDocumentElement(),
6245 self.has_browsing_context,
6246 )
6247 }
6248
6249 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6251 if self.quirks_mode() == QuirksMode::Quirks {
6253 if let Some(ref body) = self.GetBody() {
6255 let e = body.upcast::<Element>();
6256 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6260 return Some(DomRoot::from_ref(e));
6261 }
6262 }
6263
6264 return None;
6266 }
6267
6268 self.GetDocumentElement()
6271 }
6272
6273 fn Open(
6275 &self,
6276 _unused1: Option<DOMString>,
6277 _unused2: Option<DOMString>,
6278 can_gc: CanGc,
6279 ) -> Fallible<DomRoot<Document>> {
6280 if !self.is_html_document() {
6282 return Err(Error::InvalidState(None));
6283 }
6284
6285 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6287 return Err(Error::InvalidState(None));
6288 }
6289
6290 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6292
6293 if !self.origin.same_origin(&entry_responsible_document.origin) {
6295 return Err(Error::Security(None));
6296 }
6297
6298 if self
6300 .get_current_parser()
6301 .is_some_and(|parser| parser.is_active())
6302 {
6303 return Ok(DomRoot::from_ref(self));
6304 }
6305
6306 if self.is_prompting_or_unloading() {
6308 return Ok(DomRoot::from_ref(self));
6309 }
6310
6311 if self.active_parser_was_aborted.get() {
6313 return Ok(DomRoot::from_ref(self));
6314 }
6315
6316 self.window().set_navigation_start();
6320
6321 if self.has_browsing_context() {
6324 self.abort(can_gc);
6327 }
6328
6329 for node in self
6331 .upcast::<Node>()
6332 .traverse_preorder(ShadowIncluding::Yes)
6333 {
6334 node.upcast::<EventTarget>().remove_all_listeners();
6335 }
6336
6337 if self.window.Document() == DomRoot::from_ref(self) {
6339 self.window.upcast::<EventTarget>().remove_all_listeners();
6340 }
6341
6342 Node::replace_all(None, self.upcast::<Node>(), can_gc);
6344
6345 if self.is_fully_active() {
6352 let mut new_url = entry_responsible_document.url();
6354
6355 if entry_responsible_document != DomRoot::from_ref(self) {
6357 new_url.set_fragment(None);
6358 }
6359
6360 self.set_url(new_url);
6363 }
6364
6365 self.is_initial_about_blank.set(false);
6367
6368 self.set_quirks_mode(QuirksMode::NoQuirks);
6374
6375 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6381 *self.loader.borrow_mut() =
6382 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6383 ServoParser::parse_html_script_input(self, self.url());
6384
6385 self.ready_state.set(DocumentReadyState::Loading);
6391
6392 Ok(DomRoot::from_ref(self))
6394 }
6395
6396 fn Open_(
6398 &self,
6399 url: USVString,
6400 target: DOMString,
6401 features: DOMString,
6402 can_gc: CanGc,
6403 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6404 self.browsing_context()
6405 .ok_or(Error::InvalidAccess(None))?
6406 .open(url, target, features, can_gc)
6407 }
6408
6409 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
6411 self.write(text, false, "Document", "write", can_gc)
6414 }
6415
6416 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
6418 self.write(text, true, "Document", "writeln", can_gc)
6421 }
6422
6423 fn Close(&self, can_gc: CanGc) -> ErrorResult {
6425 if !self.is_html_document() {
6426 return Err(Error::InvalidState(None));
6428 }
6429
6430 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6432 return Err(Error::InvalidState(None));
6433 }
6434
6435 let parser = match self.get_current_parser() {
6436 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6437 _ => {
6438 return Ok(());
6440 },
6441 };
6442
6443 parser.close(can_gc);
6445
6446 Ok(())
6447 }
6448
6449 fn ExecCommand(
6451 &self,
6452 command_id: DOMString,
6453 _show_ui: bool,
6454 value: TrustedHTMLOrString,
6455 can_gc: CanGc,
6456 ) -> Fallible<bool> {
6457 let value = if command_id == "insertHTML" {
6458 TrustedHTML::get_trusted_script_compliant_string(
6459 self.window.as_global_scope(),
6460 value,
6461 "Document execCommand",
6462 can_gc,
6463 )?
6464 } else {
6465 match value {
6466 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6467 TrustedHTMLOrString::String(value) => value,
6468 }
6469 };
6470
6471 Ok(self.exec_command_for_command_id(command_id, value, can_gc))
6472 }
6473
6474 fn QueryCommandEnabled(&self, command_id: DOMString, can_gc: CanGc) -> bool {
6476 self.check_support_and_enabled(command_id, can_gc).is_some()
6477 }
6478
6479 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6481
6482 event_handler!(
6484 fullscreenchange,
6485 GetOnfullscreenchange,
6486 SetOnfullscreenchange
6487 );
6488
6489 fn FullscreenEnabled(&self) -> bool {
6491 self.get_allow_fullscreen()
6492 }
6493
6494 fn Fullscreen(&self) -> bool {
6496 self.fullscreen_element.get().is_some()
6497 }
6498
6499 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6501 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6502 }
6503
6504 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6506 self.exit_fullscreen(can_gc)
6507 }
6508
6509 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6513 match self.media_controls.borrow().get(&*id.str()) {
6514 Some(m) => Ok(DomRoot::from_ref(m)),
6515 None => Err(Error::InvalidAccess(None)),
6516 }
6517 }
6518
6519 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6521 if self.has_browsing_context {
6522 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6523 } else {
6524 None
6525 }
6526 }
6527
6528 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6530 self.fonts
6531 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6532 }
6533
6534 fn Hidden(&self) -> bool {
6536 self.visibility_state.get() == DocumentVisibilityState::Hidden
6537 }
6538
6539 fn VisibilityState(&self) -> DocumentVisibilityState {
6541 self.visibility_state.get()
6542 }
6543
6544 fn CreateExpression(
6545 &self,
6546 expression: DOMString,
6547 resolver: Option<Rc<XPathNSResolver>>,
6548 can_gc: CanGc,
6549 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6550 let parsed_expression =
6551 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6552 Ok(XPathExpression::new(
6553 &self.window,
6554 None,
6555 can_gc,
6556 parsed_expression,
6557 ))
6558 }
6559
6560 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6561 let global = self.global();
6562 let window = global.as_window();
6563 let evaluator = XPathEvaluator::new(window, None, can_gc);
6564 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6565 }
6566
6567 fn Evaluate(
6568 &self,
6569 expression: DOMString,
6570 context_node: &Node,
6571 resolver: Option<Rc<XPathNSResolver>>,
6572 result_type: u16,
6573 result: Option<&super::types::XPathResult>,
6574 can_gc: CanGc,
6575 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6576 let parsed_expression =
6577 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6578 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6579 context_node,
6580 result_type,
6581 result,
6582 can_gc,
6583 )
6584 }
6585
6586 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6588 self.adopted_stylesheets_frozen_types.get_or_init(
6589 || {
6590 self.adopted_stylesheets
6591 .borrow()
6592 .clone()
6593 .iter()
6594 .map(|sheet| sheet.as_rooted())
6595 .collect()
6596 },
6597 context,
6598 retval,
6599 can_gc,
6600 );
6601 }
6602
6603 fn SetAdoptedStyleSheets(
6605 &self,
6606 context: JSContext,
6607 val: HandleValue,
6608 can_gc: CanGc,
6609 ) -> ErrorResult {
6610 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6611 context,
6612 self.adopted_stylesheets.borrow_mut().as_mut(),
6613 val,
6614 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6615 can_gc,
6616 );
6617
6618 if result.is_ok() {
6620 self.adopted_stylesheets_frozen_types.clear()
6621 }
6622
6623 result
6624 }
6625}
6626
6627fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6628 if marker.get().is_none() {
6629 marker.set(Some(CrossProcessInstant::now()))
6630 }
6631}
6632
6633#[derive(Clone, Copy, PartialEq)]
6635pub(crate) enum FocusType {
6636 Element, Parent, }
6639
6640#[derive(Clone, Copy, PartialEq)]
6642pub enum FocusInitiator {
6643 Local,
6646 Remote,
6649}
6650
6651pub(crate) enum FocusEventType {
6653 Focus, Blur, }
6656
6657#[derive(JSTraceable, MallocSizeOf)]
6658pub(crate) enum AnimationFrameCallback {
6659 DevtoolsFramerateTick {
6660 actor_name: String,
6661 },
6662 FrameRequestCallback {
6663 #[conditional_malloc_size_of]
6664 callback: Rc<FrameRequestCallback>,
6665 },
6666}
6667
6668impl AnimationFrameCallback {
6669 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6670 match *self {
6671 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6672 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6673 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6674 devtools_sender.send(msg).unwrap();
6675 },
6676 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6677 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6680 },
6681 }
6682 }
6683}
6684
6685#[derive(Default, JSTraceable, MallocSizeOf)]
6686#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6687struct PendingInOrderScriptVec {
6688 scripts: DomRefCell<VecDeque<PendingScript>>,
6689}
6690
6691impl PendingInOrderScriptVec {
6692 fn is_empty(&self) -> bool {
6693 self.scripts.borrow().is_empty()
6694 }
6695
6696 fn push(&self, element: &HTMLScriptElement) {
6697 self.scripts
6698 .borrow_mut()
6699 .push_back(PendingScript::new(element));
6700 }
6701
6702 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6703 let mut scripts = self.scripts.borrow_mut();
6704 let entry = scripts
6705 .iter_mut()
6706 .find(|entry| &*entry.element == element)
6707 .unwrap();
6708 entry.loaded(result);
6709 }
6710
6711 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6712 let mut scripts = self.scripts.borrow_mut();
6713 let pair = scripts.front_mut()?.take_result()?;
6714 scripts.pop_front();
6715 Some(pair)
6716 }
6717
6718 fn clear(&self) {
6719 *self.scripts.borrow_mut() = Default::default();
6720 }
6721}
6722
6723#[derive(JSTraceable, MallocSizeOf)]
6724#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6725struct PendingScript {
6726 element: Dom<HTMLScriptElement>,
6727 load: Option<ScriptResult>,
6729}
6730
6731impl PendingScript {
6732 fn new(element: &HTMLScriptElement) -> Self {
6733 Self {
6734 element: Dom::from_ref(element),
6735 load: None,
6736 }
6737 }
6738
6739 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6740 Self {
6741 element: Dom::from_ref(element),
6742 load,
6743 }
6744 }
6745
6746 fn loaded(&mut self, result: ScriptResult) {
6747 assert!(self.load.is_none());
6748 self.load = Some(result);
6749 }
6750
6751 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6752 self.load
6753 .take()
6754 .map(|result| (DomRoot::from_ref(&*self.element), result))
6755 }
6756}
6757
6758fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6759 let type_ = match elem.upcast::<Node>().type_id() {
6760 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6761 _ => return false,
6762 };
6763 match type_ {
6764 HTMLElementTypeId::HTMLFormElement |
6765 HTMLElementTypeId::HTMLIFrameElement |
6766 HTMLElementTypeId::HTMLImageElement => true,
6767 _ => false,
6771 }
6772}
6773
6774fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6775 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6779}
6780
6781impl DocumentHelpers for Document {
6782 fn ensure_safe_to_run_script_or_layout(&self) {
6783 Document::ensure_safe_to_run_script_or_layout(self)
6784 }
6785}
6786
6787pub(crate) struct SameoriginAncestorNavigablesIterator {
6791 document: DomRoot<Document>,
6792}
6793
6794impl SameoriginAncestorNavigablesIterator {
6795 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6796 Self { document }
6797 }
6798}
6799
6800impl Iterator for SameoriginAncestorNavigablesIterator {
6801 type Item = DomRoot<Document>;
6802
6803 fn next(&mut self) -> Option<Self::Item> {
6804 let window_proxy = self.document.browsing_context()?;
6805 self.document = window_proxy.parent()?.document()?;
6806 Some(self.document.clone())
6807 }
6808}
6809
6810pub(crate) struct SameOriginDescendantNavigablesIterator {
6815 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6816}
6817
6818impl SameOriginDescendantNavigablesIterator {
6819 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6820 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6821 Self {
6822 stack: vec![Box::new(iframes.into_iter())],
6823 }
6824 }
6825
6826 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6827 let mut cur_iframe = self.stack.last_mut()?.next();
6828 while cur_iframe.is_none() {
6829 self.stack.pop();
6830 cur_iframe = self.stack.last_mut()?.next();
6831 }
6832 cur_iframe
6833 }
6834}
6835
6836impl Iterator for SameOriginDescendantNavigablesIterator {
6837 type Item = DomRoot<Document>;
6838
6839 fn next(&mut self) -> Option<Self::Item> {
6840 while let Some(iframe) = self.get_next_iframe() {
6841 let Some(pipeline_id) = iframe.pipeline_id() else {
6842 continue;
6843 };
6844
6845 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6846 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6847 document.iframes().iter().collect();
6848 self.stack.push(Box::new(child_iframes.into_iter()));
6849 return Some(document);
6850 } else {
6851 continue;
6852 };
6853 }
6854 None
6855 }
6856}