1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use bitflags::bitflags;
17use chrono::Local;
18use content_security_policy::sandboxing_directive::SandboxingFlagSet;
19use content_security_policy::{CspList, Policy as CspPolicy, PolicyDisposition};
20use cookie::Cookie;
21use data_url::mime::Mime;
22use devtools_traits::ScriptToDevtoolsControlMsg;
23use dom_struct::dom_struct;
24use embedder_traits::{
25 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
26 Image, LoadStatus,
27};
28use encoding_rs::{Encoding, UTF_8};
29use fonts::WebFontDocumentContext;
30use html5ever::{LocalName, Namespace, QualName, local_name, ns};
31use hyper_serde::Serde;
32use js::rust::{HandleObject, HandleValue, MutableHandleValue};
33use layout_api::{
34 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
35 ScrollContainerQueryFlags, TrustedNodeAddress,
36};
37use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
38use net_traits::CookieSource::NonHTTP;
39use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
40use net_traits::ReferrerPolicy;
41use net_traits::policy_container::PolicyContainer;
42use net_traits::pub_domains::is_pub_domain;
43use net_traits::request::{
44 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
45};
46use net_traits::response::HttpsState;
47use percent_encoding::percent_decode;
48use profile_traits::generic_channel as profile_generic_channel;
49use profile_traits::time::TimerMetadataFrameType;
50use regex::bytes::Regex;
51use rustc_hash::{FxBuildHasher, FxHashMap};
52use script_bindings::interfaces::DocumentHelpers;
53use script_bindings::script_runtime::JSContext;
54use script_traits::{DocumentActivity, ProgressiveWebMetricType};
55use servo_arc::Arc;
56use servo_base::cross_process_instant::CrossProcessInstant;
57use servo_base::generic_channel::GenericSend;
58use servo_base::id::WebViewId;
59use servo_base::{Epoch, generic_channel};
60use servo_config::pref;
61use servo_constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
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 time::Duration as TimeDuration;
74use url::{Host, Position};
75
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::animationtimeline::AnimationTimeline;
79use crate::dom::attr::Attr;
80use crate::dom::beforeunloadevent::BeforeUnloadEvent;
81use crate::dom::bindings::callback::ExceptionHandling;
82use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
83use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
84use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
85 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
86};
87use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
88use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
90use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
91#[cfg(any(feature = "webxr", feature = "gamepad"))]
92use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
93use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
94use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
95use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
96use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
97use crate::dom::bindings::codegen::Bindings::WindowBinding::{
98 FrameRequestCallback, ScrollBehavior, WindowMethods,
99};
100use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
101use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
102use crate::dom::bindings::codegen::UnionTypes::{
103 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
104};
105use crate::dom::bindings::domname::{
106 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
107};
108use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
109use crate::dom::bindings::frozenarray::CachedFrozenArray;
110use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
111use crate::dom::bindings::num::Finite;
112use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
113use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
114use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
115use crate::dom::bindings::str::{DOMString, USVString};
116use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
117use crate::dom::bindings::weakref::DOMTracker;
118use crate::dom::bindings::xmlname::matches_name_production;
119use crate::dom::cdatasection::CDATASection;
120use crate::dom::comment::Comment;
121use crate::dom::compositionevent::CompositionEvent;
122use crate::dom::css::cssstylesheet::CSSStyleSheet;
123use crate::dom::css::fontfaceset::FontFaceSet;
124use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
125use crate::dom::customelementregistry::{
126 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
127};
128use crate::dom::customevent::CustomEvent;
129use crate::dom::document_embedder_controls::DocumentEmbedderControls;
130use crate::dom::document_event_handler::DocumentEventHandler;
131use crate::dom::documentfragment::DocumentFragment;
132use crate::dom::documentorshadowroot::{
133 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
134};
135use crate::dom::documenttimeline::DocumentTimeline;
136use crate::dom::documenttype::DocumentType;
137use crate::dom::domimplementation::DOMImplementation;
138use crate::dom::element::{
139 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
140 ElementPerformFullscreenExit,
141};
142use crate::dom::event::{Event, EventBubbles, EventCancelable};
143use crate::dom::eventtarget::EventTarget;
144use crate::dom::execcommand::basecommand::{CommandName, DefaultSingleLineContainerName};
145use crate::dom::execcommand::contenteditable::ContentEditableRange;
146use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
147use crate::dom::focusevent::FocusEvent;
148use crate::dom::globalscope::GlobalScope;
149use crate::dom::hashchangeevent::HashChangeEvent;
150use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
151use crate::dom::html::htmlareaelement::HTMLAreaElement;
152use crate::dom::html::htmlbaseelement::HTMLBaseElement;
153use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
154use crate::dom::html::htmlelement::HTMLElement;
155use crate::dom::html::htmlembedelement::HTMLEmbedElement;
156use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
157use crate::dom::html::htmlheadelement::HTMLHeadElement;
158use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
159use crate::dom::html::htmliframeelement::HTMLIFrameElement;
160use crate::dom::html::htmlimageelement::HTMLImageElement;
161use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
162use crate::dom::html::htmltitleelement::HTMLTitleElement;
163use crate::dom::htmldetailselement::DetailsNameGroups;
164use crate::dom::intersectionobserver::IntersectionObserver;
165use crate::dom::keyboardevent::KeyboardEvent;
166use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
167use crate::dom::location::Location;
168use crate::dom::messageevent::MessageEvent;
169use crate::dom::mouseevent::MouseEvent;
170use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
171use crate::dom::nodeiterator::NodeIterator;
172use crate::dom::nodelist::NodeList;
173use crate::dom::pagetransitionevent::PageTransitionEvent;
174use crate::dom::performance::performanceentry::PerformanceEntry;
175use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
176use crate::dom::processinginstruction::ProcessingInstruction;
177use crate::dom::promise::Promise;
178use crate::dom::range::Range;
179use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
180use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
181use crate::dom::selection::Selection;
182use crate::dom::servoparser::ServoParser;
183use crate::dom::shadowroot::ShadowRoot;
184use crate::dom::storageevent::StorageEvent;
185use crate::dom::text::Text;
186use crate::dom::touchevent::TouchEvent as DomTouchEvent;
187use crate::dom::touchlist::TouchList;
188use crate::dom::treewalker::TreeWalker;
189use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
190use crate::dom::types::{HTMLCanvasElement, HTMLDialogElement, VisibilityStateEntry};
191use crate::dom::uievent::UIEvent;
192use crate::dom::virtualmethods::vtable_for;
193use crate::dom::websocket::WebSocket;
194use crate::dom::window::Window;
195use crate::dom::windowproxy::WindowProxy;
196use crate::dom::xpathevaluator::XPathEvaluator;
197use crate::dom::xpathexpression::XPathExpression;
198use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
199use crate::iframe_collection::IFrameCollection;
200use crate::image_animation::ImageAnimationManager;
201use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
202use crate::mime::{APPLICATION, CHARSET};
203use crate::navigation::navigate;
204use crate::network_listener::{FetchResponseListener, NetworkListener};
205use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
206use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
207use crate::script_thread::ScriptThread;
208use crate::stylesheet_set::StylesheetSetRef;
209use crate::task::NonSendTaskBox;
210use crate::task_source::TaskSourceName;
211use crate::timers::OneshotTimerCallback;
212use crate::xpath::parse_expression;
213
214#[derive(Clone, Copy, PartialEq)]
215pub(crate) enum FireMouseEventType {
216 Move,
217 Over,
218 Out,
219 Enter,
220 Leave,
221}
222
223impl FireMouseEventType {
224 pub(crate) fn as_str(&self) -> &str {
225 match *self {
226 FireMouseEventType::Move => "mousemove",
227 FireMouseEventType::Over => "mouseover",
228 FireMouseEventType::Out => "mouseout",
229 FireMouseEventType::Enter => "mouseenter",
230 FireMouseEventType::Leave => "mouseleave",
231 }
232 }
233}
234
235#[derive(JSTraceable, MallocSizeOf)]
236pub(crate) struct RefreshRedirectDue {
237 #[no_trace]
238 pub(crate) url: ServoUrl,
239 #[ignore_malloc_size_of = "non-owning"]
240 pub(crate) window: DomRoot<Window>,
241}
242impl RefreshRedirectDue {
243 pub(crate) fn invoke(self, cx: &mut js::context::JSContext) {
245 let load_data = self
255 .window
256 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
257 navigate(
258 cx,
259 &self.window,
260 NavigationHistoryBehavior::Replace,
261 false,
262 load_data,
263 );
264 }
265}
266
267#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
268pub(crate) enum IsHTMLDocument {
269 HTMLDocument,
270 NonHTMLDocument,
271}
272
273#[derive(JSTraceable, MallocSizeOf)]
274#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
275struct FocusTransaction {
276 element: Option<Dom<Element>>,
278 has_focus: bool,
280 focus_options: FocusOptions,
282}
283
284#[derive(JSTraceable, MallocSizeOf)]
286pub(crate) enum DeclarativeRefresh {
287 PendingLoad {
288 #[no_trace]
289 url: ServoUrl,
290 time: u64,
291 },
292 CreatedAfterLoad,
293}
294
295#[derive(JSTraceable, MallocSizeOf, PartialEq)]
296#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
297struct PendingScrollEvent {
298 target: Dom<EventTarget>,
300 #[no_trace]
302 event: Atom,
303}
304
305impl PendingScrollEvent {
306 fn equivalent(&self, target: &EventTarget, event: &Atom) -> bool {
307 &*self.target == target && self.event == *event
308 }
309}
310
311#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
314pub(crate) struct RenderingUpdateReason(u8);
315
316bitflags! {
317 impl RenderingUpdateReason: u8 {
318 const ResizeObserverStartedObservingTarget = 1 << 0;
321 const IntersectionObserverStartedObservingTarget = 1 << 1;
324 const FontReadyPromiseFulfilled = 1 << 2;
328 }
329}
330
331#[dom_struct]
333pub(crate) struct Document {
334 node: Node,
335 document_or_shadow_root: DocumentOrShadowRoot,
336 window: Dom<Window>,
337 implementation: MutNullableDom<DOMImplementation>,
338 #[ignore_malloc_size_of = "type from external crate"]
339 #[no_trace]
340 content_type: Mime,
341 last_modified: Option<String>,
342 #[no_trace]
343 encoding: Cell<&'static Encoding>,
344 has_browsing_context: bool,
345 is_html_document: bool,
346 #[no_trace]
347 activity: Cell<DocumentActivity>,
348 #[no_trace]
350 url: DomRefCell<ServoUrl>,
351 #[no_trace]
353 about_base_url: DomRefCell<Option<ServoUrl>>,
354 #[ignore_malloc_size_of = "defined in selectors"]
355 #[no_trace]
356 quirks_mode: Cell<QuirksMode>,
357 event_handler: DocumentEventHandler,
359 embedder_controls: DocumentEmbedderControls,
361 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
364 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
365 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
366 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
367 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
368 images: MutNullableDom<HTMLCollection>,
369 embeds: MutNullableDom<HTMLCollection>,
370 links: MutNullableDom<HTMLCollection>,
371 forms: MutNullableDom<HTMLCollection>,
372 scripts: MutNullableDom<HTMLCollection>,
373 anchors: MutNullableDom<HTMLCollection>,
374 applets: MutNullableDom<HTMLCollection>,
375 iframes: RefCell<IFrameCollection>,
377 #[no_trace]
380 style_shared_lock: StyleSharedRwLock,
381 #[custom_trace]
383 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
384 stylesheet_list: MutNullableDom<StyleSheetList>,
385 ready_state: Cell<DocumentReadyState>,
386 domcontentloaded_dispatched: Cell<bool>,
388 focus_transaction: DomRefCell<Option<FocusTransaction>>,
390 focused: MutNullableDom<Element>,
392 #[no_trace]
394 focus_sequence: Cell<FocusSequenceNumber>,
395 has_focus: Cell<bool>,
399 current_script: MutNullableDom<HTMLScriptElement>,
401 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
403 script_blocking_stylesheets_count: Cell<u32>,
405 render_blocking_element_count: Cell<u32>,
408 deferred_scripts: PendingInOrderScriptVec,
410 asap_in_order_scripts_list: PendingInOrderScriptVec,
412 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
414 animation_frame_ident: Cell<u32>,
417 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
420 running_animation_callbacks: Cell<bool>,
425 loader: DomRefCell<DocumentLoader>,
427 current_parser: MutNullableDom<ServoParser>,
429 base_element: MutNullableDom<HTMLBaseElement>,
431 target_base_element: MutNullableDom<HTMLBaseElement>,
433 appropriate_template_contents_owner_document: MutNullableDom<Document>,
436 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
439 #[no_trace]
443 needs_restyle: Cell<RestyleReason>,
444 #[no_trace]
447 dom_interactive: Cell<Option<CrossProcessInstant>>,
448 #[no_trace]
450 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
451 #[no_trace]
453 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
454 #[no_trace]
455 dom_complete: Cell<Option<CrossProcessInstant>>,
456 #[no_trace]
457 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
458 #[no_trace]
459 load_event_start: Cell<Option<CrossProcessInstant>>,
460 #[no_trace]
461 load_event_end: Cell<Option<CrossProcessInstant>>,
462 #[no_trace]
463 unload_event_start: Cell<Option<CrossProcessInstant>>,
464 #[no_trace]
465 unload_event_end: Cell<Option<CrossProcessInstant>>,
466 #[no_trace]
468 https_state: Cell<HttpsState>,
469 #[no_trace]
471 origin: DomRefCell<MutableOrigin>,
472 referrer: Option<String>,
474 target_element: MutNullableDom<Element>,
476 #[no_trace]
478 policy_container: DomRefCell<PolicyContainer>,
479 #[no_trace]
481 preloaded_resources: DomRefCell<PreloadedResources>,
482 ignore_destructive_writes_counter: Cell<u32>,
484 ignore_opens_during_unload_counter: Cell<u32>,
486 spurious_animation_frames: Cell<u8>,
490
491 dom_count: Cell<u32>,
497 fullscreen_element: MutNullableDom<Element>,
499 form_id_listener_map:
506 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
507 #[no_trace]
508 interactive_time: DomRefCell<ProgressiveWebMetrics>,
509 #[no_trace]
510 tti_window: DomRefCell<InteractiveWindow>,
511 canceller: FetchCanceller,
513 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
515 page_showing: Cell<bool>,
517 salvageable: Cell<bool>,
519 active_parser_was_aborted: Cell<bool>,
521 fired_unload: Cell<bool>,
523 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
525 redirect_count: Cell<u16>,
527 script_and_layout_blockers: Cell<u32>,
529 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
531 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
532 completely_loaded: Cell<bool>,
534 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
536 shadow_roots_styles_changed: Cell<bool>,
538 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
544 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
547 has_pending_animated_image_update: Cell<bool>,
549 selection: MutNullableDom<Selection>,
551 timeline: Dom<DocumentTimeline>,
554 animations: Animations,
556 image_animation_manager: DomRefCell<ImageAnimationManager>,
558 dirty_root: MutNullableDom<Element>,
560 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
562 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
571 fonts: MutNullableDom<FontFaceSet>,
574 visibility_state: Cell<DocumentVisibilityState>,
576 status_code: Option<u16>,
578 is_initial_about_blank: Cell<bool>,
580 allow_declarative_shadow_roots: Cell<bool>,
582 #[no_trace]
584 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
585 has_trustworthy_ancestor_origin: Cell<bool>,
587 intersection_observer_task_queued: Cell<bool>,
589 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
601 highlighted_dom_node: MutNullableDom<Node>,
603 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
606 #[ignore_malloc_size_of = "mozjs"]
608 adopted_stylesheets_frozen_types: CachedFrozenArray,
609 pending_scroll_events: DomRefCell<Vec<PendingScrollEvent>>,
613 rendering_update_reasons: Cell<RenderingUpdateReason>,
615 waiting_on_canvas_image_updates: Cell<bool>,
619 #[no_trace]
627 current_rendering_epoch: Cell<Epoch>,
628 #[conditional_malloc_size_of]
630 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
631 #[no_trace]
632 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
634 #[no_trace]
635 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
642 #[no_trace]
644 favicon: RefCell<Option<Image>>,
645
646 websockets: DOMTracker<WebSocket>,
648
649 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
651
652 #[no_trace]
654 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
655
656 layout_animations_test_enabled: bool,
658
659 #[no_trace]
661 state_override: DomRefCell<FxHashMap<CommandName, bool>>,
662
663 #[no_trace]
665 value_override: DomRefCell<FxHashMap<CommandName, DOMString>>,
666
667 #[no_trace]
669 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
670
671 css_styling_flag: Cell<bool>,
673}
674
675impl Document {
676 fn unloading_cleanup_steps(&self) {
678 if self.close_outstanding_websockets() {
681 self.salvageable.set(false);
683 }
684
685 if !self.salvageable.get() {
690 let global_scope = self.window.as_global_scope();
691
692 global_scope.close_event_sources();
694
695 let msg = ScriptToConstellationMessage::DiscardDocument;
700 let _ = global_scope.script_to_constellation_chan().send(msg);
701 }
702 }
703
704 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
705 self.websockets.track(websocket);
706 }
707
708 fn close_outstanding_websockets(&self) -> bool {
709 let mut closed_any_websocket = false;
710 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
711 if websocket.make_disappear() {
712 closed_any_websocket = true;
713 }
714 });
715 closed_any_websocket
716 }
717
718 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
719 debug_assert!(*node.owner_doc() == *self);
720 if !node.is_connected() {
721 return;
722 }
723
724 let parent = match node.parent_in_flat_tree() {
725 Some(parent) => parent,
726 None => {
727 let document_element = match self.GetDocumentElement() {
730 Some(element) => element,
731 None => return,
732 };
733 if let Some(dirty_root) = self.dirty_root.get() {
734 for ancestor in dirty_root
737 .upcast::<Node>()
738 .inclusive_ancestors_in_flat_tree()
739 {
740 if ancestor.is::<Element>() {
741 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
742 }
743 }
744 }
745 self.dirty_root.set(Some(&document_element));
746 return;
747 },
748 };
749
750 if parent.is::<Element>() {
751 if !parent.is_styled() {
752 return;
753 }
754
755 if parent.is_display_none() {
756 return;
757 }
758 }
759
760 let element_parent: DomRoot<Element>;
761 let element = match node.downcast::<Element>() {
762 Some(element) => element,
763 None => {
764 match DomRoot::downcast::<Element>(parent) {
767 Some(parent) => {
768 element_parent = parent;
769 &element_parent
770 },
771 None => {
772 return;
776 },
777 }
778 },
779 };
780
781 let dirty_root = match self.dirty_root.get() {
782 Some(root) if root.is_connected() => root,
783 _ => {
784 element
785 .upcast::<Node>()
786 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
787 self.dirty_root.set(Some(element));
788 return;
789 },
790 };
791
792 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
793 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
794 return;
795 }
796
797 if ancestor.is::<Element>() {
798 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
799 }
800 }
801
802 let new_dirty_root = element
803 .upcast::<Node>()
804 .common_ancestor_in_flat_tree(dirty_root.upcast())
805 .expect("Couldn't find common ancestor");
806
807 let mut has_dirty_descendants = true;
808 for ancestor in dirty_root
809 .upcast::<Node>()
810 .inclusive_ancestors_in_flat_tree()
811 {
812 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
813 has_dirty_descendants &= *ancestor != *new_dirty_root;
814 }
815
816 self.dirty_root
817 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
818 }
819
820 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
821 self.dirty_root.take()
822 }
823
824 #[inline]
825 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
826 self.loader.borrow()
827 }
828
829 #[inline]
830 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
831 self.loader.borrow_mut()
832 }
833
834 #[inline]
835 pub(crate) fn has_browsing_context(&self) -> bool {
836 self.has_browsing_context
837 }
838
839 #[inline]
841 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
842 if self.has_browsing_context {
843 self.window.undiscarded_window_proxy()
844 } else {
845 None
846 }
847 }
848
849 pub(crate) fn webview_id(&self) -> WebViewId {
850 self.window.webview_id()
851 }
852
853 #[inline]
854 pub(crate) fn window(&self) -> &Window {
855 &self.window
856 }
857
858 #[inline]
859 pub(crate) fn is_html_document(&self) -> bool {
860 self.is_html_document
861 }
862
863 pub(crate) fn is_xhtml_document(&self) -> bool {
864 self.content_type.matches(APPLICATION, "xhtml+xml")
865 }
866
867 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
868 self.https_state.set(https_state);
869 }
870
871 pub(crate) fn is_fully_active(&self) -> bool {
872 self.activity.get() == DocumentActivity::FullyActive
873 }
874
875 pub(crate) fn is_active(&self) -> bool {
876 self.activity.get() != DocumentActivity::Inactive
877 }
878
879 #[inline]
880 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
881 self.current_rendering_epoch.get()
882 }
883
884 pub(crate) fn set_activity(&self, cx: &mut js::context::JSContext, activity: DocumentActivity) {
885 assert!(self.has_browsing_context);
887 if activity == self.activity.get() {
888 return;
889 }
890
891 self.activity.set(activity);
893 let media = ServoMedia::get();
894 let pipeline_id = self.window().pipeline_id();
895 let client_context_id =
896 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
897
898 if activity != DocumentActivity::FullyActive {
899 self.window().suspend(cx);
900 media.suspend(&client_context_id);
901 return;
902 }
903
904 self.title_changed();
905 self.notify_embedder_favicon();
906 self.dirty_all_nodes();
907 self.window().resume(CanGc::from_cx(cx));
908 media.resume(&client_context_id);
909
910 if self.ready_state.get() != DocumentReadyState::Complete {
911 return;
912 }
913
914 let document = Trusted::new(self);
918 self.owner_global()
919 .task_manager()
920 .dom_manipulation_task_source()
921 .queue(task!(fire_pageshow_event: move || {
922 let document = document.root();
923 let window = document.window();
924 if document.page_showing.get() {
926 return;
927 }
928 document.page_showing.set(true);
930 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
932 let event = PageTransitionEvent::new(
935 window,
936 atom!("pageshow"),
937 false, false, true, CanGc::note(),
941 );
942 let event = event.upcast::<Event>();
943 event.set_trusted(true);
944 window.dispatch_event_with_target_override(event, CanGc::note());
945 }))
946 }
947
948 pub(crate) fn origin(&self) -> Ref<'_, MutableOrigin> {
949 self.origin.borrow()
950 }
951
952 pub(crate) fn mark_as_internal(&self) {
955 *self.origin.borrow_mut() = MutableOrigin::new(ImmutableOrigin::new_opaque());
956 }
957
958 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
959 *self.protocol_handler_automation_mode.borrow_mut() = mode;
960 }
961
962 pub(crate) fn url(&self) -> ServoUrl {
964 self.url.borrow().clone()
965 }
966
967 pub(crate) fn set_url(&self, url: ServoUrl) {
968 *self.url.borrow_mut() = url;
969 }
970
971 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
972 self.about_base_url.borrow().clone()
973 }
974
975 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
976 *self.about_base_url.borrow_mut() = about_base_url;
977 }
978
979 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
981 let document_url = self.url();
982 if document_url.as_str() == "about:srcdoc" {
984 return self
987 .about_base_url()
988 .expect("about:srcdoc page should always have an about base URL");
989 }
990
991 if document_url.matches_about_blank() {
994 if let Some(about_base_url) = self.about_base_url() {
995 return about_base_url;
996 }
997 }
998
999 document_url
1001 }
1002
1003 pub(crate) fn base_url(&self) -> ServoUrl {
1005 match self.base_element() {
1006 None => self.fallback_base_url(),
1008 Some(base) => base.frozen_base_url(),
1010 }
1011 }
1012
1013 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
1014 self.needs_restyle.set(self.needs_restyle.get() | reason)
1015 }
1016
1017 pub(crate) fn clear_restyle_reasons(&self) {
1018 self.needs_restyle.set(RestyleReason::empty());
1019 }
1020
1021 pub(crate) fn restyle_reason(&self) -> RestyleReason {
1022 let mut condition = self.needs_restyle.get();
1023 if self.stylesheets.borrow().has_changed() {
1024 condition.insert(RestyleReason::StylesheetsChanged);
1025 }
1026
1027 if let Some(root) = self.GetDocumentElement() {
1031 if root.upcast::<Node>().has_dirty_descendants() {
1032 condition.insert(RestyleReason::DOMChanged);
1033 }
1034 }
1035
1036 if !self.pending_restyles.borrow().is_empty() {
1037 condition.insert(RestyleReason::PendingRestyles);
1038 }
1039
1040 condition
1041 }
1042
1043 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1045 self.base_element.get()
1046 }
1047
1048 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1050 self.target_base_element.get()
1051 }
1052
1053 pub(crate) fn refresh_base_element(&self) {
1055 if let Some(base_element) = self.base_element.get() {
1056 base_element.clear_frozen_base_url();
1057 }
1058 let new_base_element = self
1059 .upcast::<Node>()
1060 .traverse_preorder(ShadowIncluding::No)
1061 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1062 .find(|element| {
1063 element
1064 .upcast::<Element>()
1065 .has_attribute(&local_name!("href"))
1066 });
1067 if let Some(ref new_base_element) = new_base_element {
1068 new_base_element.set_frozen_base_url();
1069 }
1070 self.base_element.set(new_base_element.as_deref());
1071
1072 let new_target_base_element = self
1073 .upcast::<Node>()
1074 .traverse_preorder(ShadowIncluding::No)
1075 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1076 .next();
1077 self.target_base_element
1078 .set(new_target_base_element.as_deref());
1079 }
1080
1081 pub(crate) fn dom_count(&self) -> u32 {
1082 self.dom_count.get()
1083 }
1084
1085 pub(crate) fn increment_dom_count(&self) {
1089 self.dom_count.set(self.dom_count.get() + 1);
1090 }
1091
1092 pub(crate) fn decrement_dom_count(&self) {
1094 self.dom_count.set(self.dom_count.get() - 1);
1095 }
1096
1097 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1098 self.quirks_mode.get()
1099 }
1100
1101 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1102 let old_mode = self.quirks_mode.replace(new_mode);
1103
1104 if old_mode != new_mode {
1105 self.window.layout_mut().set_quirks_mode(new_mode);
1106 }
1107 }
1108
1109 pub(crate) fn encoding(&self) -> &'static Encoding {
1110 self.encoding.get()
1111 }
1112
1113 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1114 self.encoding.set(encoding);
1115 }
1116
1117 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1118 if node.is_connected() {
1119 node.note_dirty_descendants();
1120 }
1121
1122 node.dirty(NodeDamage::ContentOrHeritage);
1125 }
1126
1127 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1129 self.document_or_shadow_root
1130 .unregister_named_element(&self.id_map, to_unregister, &id);
1131 self.reset_form_owner_for_listeners(&id, can_gc);
1132 }
1133
1134 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1136 let root = self.GetDocumentElement().expect(
1137 "The element is in the document, so there must be a document \
1138 element.",
1139 );
1140 self.document_or_shadow_root.register_named_element(
1141 &self.id_map,
1142 element,
1143 &id,
1144 DomRoot::from_ref(root.upcast::<Node>()),
1145 );
1146 self.reset_form_owner_for_listeners(&id, can_gc);
1147 }
1148
1149 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1151 self.document_or_shadow_root
1152 .unregister_named_element(&self.name_map, to_unregister, &name);
1153 }
1154
1155 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1157 let root = self.GetDocumentElement().expect(
1158 "The element is in the document, so there must be a document \
1159 element.",
1160 );
1161 self.document_or_shadow_root.register_named_element(
1162 &self.name_map,
1163 element,
1164 &name,
1165 DomRoot::from_ref(root.upcast::<Node>()),
1166 );
1167 }
1168
1169 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1170 &self,
1171 id: DOMString,
1172 listener: &T,
1173 ) {
1174 let mut map = self.form_id_listener_map.borrow_mut();
1175 let listener = listener.to_element();
1176 let set = map.entry(Atom::from(id)).or_default();
1177 set.insert(Dom::from_ref(listener));
1178 }
1179
1180 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1181 &self,
1182 id: DOMString,
1183 listener: &T,
1184 ) {
1185 let mut map = self.form_id_listener_map.borrow_mut();
1186 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1187 entry
1188 .get_mut()
1189 .remove(&Dom::from_ref(listener.to_element()));
1190 if entry.get().is_empty() {
1191 entry.remove();
1192 }
1193 }
1194 }
1195
1196 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1198 self.get_element_by_id(&Atom::from(fragment))
1202 .or_else(|| self.get_anchor_by_name(fragment))
1206 }
1207
1208 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1211 if fragment.is_empty() {
1221 return Some(DomRoot::from_ref(self.upcast()));
1222 }
1223 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1225 {
1226 return Some(DomRoot::upcast(potential_indicated_element));
1228 }
1229 let fragment_bytes = percent_decode(fragment.as_bytes());
1231 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1233 return None;
1234 };
1235 if let Some(potential_indicated_element) =
1237 self.find_a_potential_indicated_element(&decoded_fragment)
1238 {
1239 return Some(DomRoot::upcast(potential_indicated_element));
1241 }
1242 if decoded_fragment.eq_ignore_ascii_case("top") {
1244 return Some(DomRoot::from_ref(self.upcast()));
1245 }
1246 None
1248 }
1249
1250 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str) {
1252 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1257 self.set_target_element(None);
1258 return;
1259 };
1260 if *indicated_part == *self.upcast() {
1262 self.set_target_element(None);
1264 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1269 return;
1271 }
1272 let Some(target) = indicated_part.downcast::<Element>() else {
1275 unreachable!("Indicated part should always be an element");
1277 };
1278 self.set_target_element(Some(target));
1280 target.scroll_into_view_with_options(
1284 ScrollBehavior::Auto,
1285 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1286 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1287 None,
1288 None,
1289 );
1290 self.event_handler()
1295 .set_sequential_focus_navigation_starting_point(target.upcast());
1296 }
1297
1298 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1299 let name = Atom::from(name);
1300 self.name_map.borrow().get(&name).and_then(|elements| {
1301 elements
1302 .iter()
1303 .find(|e| e.is::<HTMLAnchorElement>())
1304 .map(|e| DomRoot::from_ref(&**e))
1305 })
1306 }
1307
1308 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1310 match state {
1311 DocumentReadyState::Loading => {
1312 if self.window().is_top_level() {
1313 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1314 self.webview_id(),
1315 LoadStatus::Started,
1316 ));
1317 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1318 }
1319 },
1320 DocumentReadyState::Complete => {
1321 if self.window().is_top_level() {
1322 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1323 self.webview_id(),
1324 LoadStatus::Complete,
1325 ));
1326 }
1327 update_with_current_instant(&self.dom_complete);
1328 },
1329 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1330 };
1331
1332 self.ready_state.set(state);
1333
1334 self.upcast::<EventTarget>()
1335 .fire_event(atom!("readystatechange"), can_gc);
1336 }
1337
1338 pub(crate) fn scripting_enabled(&self) -> bool {
1341 self.has_browsing_context() &&
1344 !self.has_active_sandboxing_flag(
1348 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1349 )
1350 }
1351
1352 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1355 self.focused.get()
1356 }
1357
1358 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1363 self.focus_sequence.get()
1364 }
1365
1366 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1368 self.focus_sequence.set(FocusSequenceNumber(
1369 self.focus_sequence
1370 .get()
1371 .0
1372 .checked_add(1)
1373 .expect("too many focus messages have been sent"),
1374 ));
1375 self.focus_sequence.get()
1376 }
1377
1378 pub(crate) fn has_focus_transaction(&self) -> bool {
1379 self.focus_transaction.borrow().is_some()
1380 }
1381
1382 pub(crate) fn begin_focus_transaction(&self) {
1385 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1387 element: self.focused.get().as_deref().map(Dom::from_ref),
1388 has_focus: self.has_focus.get(),
1389 focus_options: FocusOptions {
1390 preventScroll: true,
1391 },
1392 });
1393 }
1394
1395 pub(crate) fn perform_focus_fixup_rule(&self, can_gc: CanGc) {
1402 if self
1403 .focused
1404 .get()
1405 .as_deref()
1406 .is_none_or(|focused| focused.is_focusable_area())
1407 {
1408 return;
1409 }
1410 self.request_focus(None, FocusInitiator::Script, can_gc);
1411 }
1412
1413 pub(crate) fn request_focus(
1416 &self,
1417 elem: Option<&Element>,
1418 focus_initiator: FocusInitiator,
1419 can_gc: CanGc,
1420 ) {
1421 self.request_focus_with_options(
1422 elem,
1423 focus_initiator,
1424 FocusOptions {
1425 preventScroll: true,
1426 },
1427 can_gc,
1428 );
1429 }
1430
1431 pub(crate) fn request_focus_with_options(
1437 &self,
1438 target: Option<&Element>,
1439 focus_initiator: FocusInitiator,
1440 focus_options: FocusOptions,
1441 can_gc: CanGc,
1442 ) {
1443 if target.is_some_and(|target| match focus_initiator {
1445 FocusInitiator::Keyboard => !target.is_sequentially_focusable(),
1446 FocusInitiator::Click => !target.is_click_focusable(),
1447 FocusInitiator::Script | FocusInitiator::Remote => !target.is_focusable_area(),
1448 }) {
1449 return;
1450 }
1451
1452 let implicit_transaction = self.focus_transaction.borrow().is_none();
1453
1454 if implicit_transaction {
1455 self.begin_focus_transaction();
1456 }
1457
1458 {
1459 let mut focus_transaction = self.focus_transaction.borrow_mut();
1460 let focus_transaction = focus_transaction.as_mut().unwrap();
1461 focus_transaction.element = target.map(Dom::from_ref);
1462 focus_transaction.has_focus = true;
1463 focus_transaction.focus_options = focus_options;
1464 }
1465
1466 if implicit_transaction {
1467 self.commit_focus_transaction(focus_initiator, can_gc);
1468 }
1469 }
1470
1471 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1475 if self.window().parent_info().is_none() {
1476 warn!("Top-level document cannot be unfocused");
1477 return;
1478 }
1479
1480 assert!(
1483 self.focus_transaction.borrow().is_none(),
1484 "there mustn't be an in-progress focus transaction at this point"
1485 );
1486
1487 self.begin_focus_transaction();
1489
1490 {
1492 let mut focus_transaction = self.focus_transaction.borrow_mut();
1493 focus_transaction.as_mut().unwrap().has_focus = false;
1494 }
1495
1496 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1498 }
1499
1500 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1503 let (mut new_focused, new_focus_state, prevent_scroll) = {
1504 let focus_transaction = self.focus_transaction.borrow();
1505 let focus_transaction = focus_transaction
1506 .as_ref()
1507 .expect("no focus transaction in progress");
1508 (
1509 focus_transaction
1510 .element
1511 .as_ref()
1512 .map(|e| DomRoot::from_ref(&**e)),
1513 focus_transaction.has_focus,
1514 focus_transaction.focus_options.preventScroll,
1515 )
1516 };
1517 *self.focus_transaction.borrow_mut() = None;
1518
1519 if !new_focus_state {
1520 if new_focused.take().is_some() {
1523 trace!(
1524 "Forgetting the document's focused area because the \
1525 document's container was removed from the top-level BC's \
1526 focus chain"
1527 );
1528 }
1529 }
1530
1531 let old_focused = self.focused.get();
1532 let old_focus_state = self.has_focus.get();
1533
1534 debug!(
1535 "Committing focus transaction: {:?} → {:?}",
1536 (&old_focused, old_focus_state),
1537 (&new_focused, new_focus_state),
1538 );
1539
1540 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1543 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1544
1545 let trace_focus_chain = |name, element, doc| {
1546 trace!(
1547 "{} local focus chain: {}",
1548 name,
1549 match (element, doc) {
1550 (Some(e), _) => format!("[{:?}, document]", e),
1551 (None, true) => "[document]".to_owned(),
1552 (None, false) => "[]".to_owned(),
1553 }
1554 );
1555 };
1556
1557 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1558 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1559
1560 if old_focused_filtered != new_focused_filtered {
1561 if let Some(elem) = &old_focused_filtered {
1562 let node = elem.upcast::<Node>();
1563 elem.set_focus_state(false);
1564 if node.is_connected() {
1566 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1567 }
1568 }
1569 }
1570
1571 if old_focus_state != new_focus_state && !new_focus_state {
1572 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1573 }
1574
1575 self.focused.set(new_focused.as_deref());
1576 self.has_focus.set(new_focus_state);
1577
1578 if old_focus_state != new_focus_state && new_focus_state {
1579 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1580 }
1581
1582 if old_focused_filtered != new_focused_filtered {
1583 if let Some(elem) = &new_focused_filtered {
1584 elem.set_focus_state(true);
1585 let node = elem.upcast::<Node>();
1586 if let Some(html_element) = elem.downcast::<HTMLElement>() {
1587 html_element.handle_focus_state_for_contenteditable(can_gc);
1588 }
1589 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1591
1592 if !prevent_scroll {
1595 let scroll_axis = ScrollAxisState {
1598 position: ScrollLogicalPosition::Center,
1599 requirement: ScrollRequirement::IfNotVisible,
1600 };
1601
1602 elem.scroll_into_view_with_options(
1606 ScrollBehavior::Smooth,
1607 scroll_axis,
1608 scroll_axis,
1609 None,
1610 None,
1611 );
1612 }
1613 }
1614 }
1615
1616 if focus_initiator == FocusInitiator::Remote {
1617 return;
1618 }
1619
1620 match (old_focus_state, new_focus_state) {
1623 (_, true) => {
1624 let child_browsing_context_id = new_focused
1645 .as_ref()
1646 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1647 .and_then(|iframe| iframe.browsing_context_id());
1648
1649 let sequence = self.increment_fetch_focus_sequence();
1650
1651 debug!(
1652 "Advertising the focus request to the constellation \
1653 with sequence number {} and child BC ID {}",
1654 sequence,
1655 child_browsing_context_id
1656 .as_ref()
1657 .map(|id| id as &dyn std::fmt::Display)
1658 .unwrap_or(&"(none)"),
1659 );
1660
1661 self.window()
1662 .send_to_constellation(ScriptToConstellationMessage::Focus(
1663 child_browsing_context_id,
1664 sequence,
1665 ));
1666 },
1667 (false, false) => {
1668 },
1671 (true, false) => {
1672 unreachable!(
1673 "Can't lose the document's focus without specifying \
1674 another one to focus"
1675 );
1676 },
1677 }
1678 }
1679
1680 pub(crate) fn title_changed(&self) {
1682 if self.browsing_context().is_some() {
1683 self.send_title_to_embedder();
1684 let title = String::from(self.Title());
1685 self.window
1686 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1687 self.window.pipeline_id(),
1688 title.clone(),
1689 ));
1690 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1691 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1692 self.window.pipeline_id(),
1693 title,
1694 ));
1695 }
1696 }
1697 }
1698
1699 fn title(&self) -> Option<DOMString> {
1703 let title = self.GetDocumentElement().and_then(|root| {
1704 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1705 root.upcast::<Node>()
1707 .child_elements()
1708 .find(|node| {
1709 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1710 })
1711 .map(DomRoot::upcast::<Node>)
1712 } else {
1713 root.upcast::<Node>()
1715 .traverse_preorder(ShadowIncluding::No)
1716 .find(|node| node.is::<HTMLTitleElement>())
1717 }
1718 });
1719
1720 title.map(|title| {
1721 let value = title.child_text_content();
1723 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1724 })
1725 }
1726
1727 pub(crate) fn send_title_to_embedder(&self) {
1729 let window = self.window();
1730 if window.is_top_level() {
1731 let title = self.title().map(String::from);
1732 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1733 }
1734 }
1735
1736 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1737 let window = self.window();
1738 window.send_to_embedder(msg);
1739 }
1740
1741 pub(crate) fn dirty_all_nodes(&self) {
1742 let root = match self.GetDocumentElement() {
1743 Some(root) => root,
1744 None => return,
1745 };
1746 for node in root
1747 .upcast::<Node>()
1748 .traverse_preorder(ShadowIncluding::Yes)
1749 {
1750 node.dirty(NodeDamage::Other)
1751 }
1752 }
1753
1754 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1756 let boxes_that_were_scrolled: Vec<_> = self
1764 .pending_scroll_events
1765 .borrow()
1766 .iter()
1767 .filter_map(|pending_event| {
1768 if &*pending_event.event == "scroll" {
1769 Some(pending_event.target.as_rooted())
1770 } else {
1771 None
1772 }
1773 })
1774 .collect();
1775
1776 for target in boxes_that_were_scrolled.into_iter() {
1777 let Some(element) = target.downcast::<Element>() else {
1783 continue;
1784 };
1785 let document = element.owner_document();
1786
1787 let mut pending_scroll_events = document.pending_scroll_events.borrow_mut();
1794 let event = "scrollend".into();
1795 if pending_scroll_events
1796 .iter()
1797 .any(|existing| existing.equivalent(&target, &event))
1798 {
1799 continue;
1800 }
1801
1802 pending_scroll_events.push(PendingScrollEvent {
1804 target: target.as_traced(),
1805 event: "scrollend".into(),
1806 });
1807 }
1808
1809 rooted_vec!(let pending_scroll_events <- self.pending_scroll_events.take().into_iter());
1812 for pending_event in pending_scroll_events.iter() {
1813 let event = pending_event.event.clone();
1816 if pending_event.target.is::<Document>() {
1817 pending_event.target.fire_bubbling_event(event, can_gc);
1818 }
1819 else {
1828 pending_event.target.fire_event(event, can_gc);
1829 }
1830 }
1831
1832 }
1835
1836 pub(crate) fn handle_viewport_scroll_event(&self) {
1841 self.finish_handle_scroll_event(self.upcast());
1853 }
1854
1855 pub(crate) fn finish_handle_scroll_event(&self, event_target: &EventTarget) {
1860 let event = "scroll".into();
1863 if self
1864 .pending_scroll_events
1865 .borrow()
1866 .iter()
1867 .any(|existing| existing.equivalent(event_target, &event))
1868 {
1869 return;
1870 }
1871
1872 self.pending_scroll_events
1875 .borrow_mut()
1876 .push(PendingScrollEvent {
1877 target: Dom::from_ref(event_target),
1878 event: "scroll".into(),
1879 });
1880 }
1881
1882 pub(crate) fn node_from_nodes_and_strings(
1884 &self,
1885 cx: &mut js::context::JSContext,
1886 mut nodes: Vec<NodeOrString>,
1887 ) -> Fallible<DomRoot<Node>> {
1888 if nodes.len() == 1 {
1889 Ok(match nodes.pop().unwrap() {
1890 NodeOrString::Node(node) => node,
1891 NodeOrString::String(string) => {
1892 DomRoot::upcast(self.CreateTextNode(string, CanGc::from_cx(cx)))
1893 },
1894 })
1895 } else {
1896 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(CanGc::from_cx(cx)));
1897 for node in nodes {
1898 match node {
1899 NodeOrString::Node(node) => {
1900 fragment.AppendChild(cx, &node)?;
1901 },
1902 NodeOrString::String(string) => {
1903 let node = DomRoot::upcast::<Node>(
1904 self.CreateTextNode(string, CanGc::from_cx(cx)),
1905 );
1906 fragment.AppendChild(cx, &node).unwrap();
1909 },
1910 }
1911 }
1912 Ok(fragment)
1913 }
1914 }
1915
1916 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1917 match self.GetBody() {
1918 Some(ref body) if body.is_body_element() => {
1919 body.upcast::<Element>().get_string_attribute(local_name)
1920 },
1921 _ => DOMString::new(),
1922 }
1923 }
1924
1925 pub(crate) fn set_body_attribute(
1926 &self,
1927 local_name: &LocalName,
1928 value: DOMString,
1929 can_gc: CanGc,
1930 ) {
1931 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1932 let body = body.upcast::<Element>();
1933 let value = body.parse_attribute(&ns!(), local_name, value);
1934 body.set_attribute(local_name, value, can_gc);
1935 }
1936 }
1937
1938 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1939 self.current_script.set(script);
1940 }
1941
1942 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1943 self.script_blocking_stylesheets_count.get()
1944 }
1945
1946 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1947 let count_cell = &self.script_blocking_stylesheets_count;
1948 count_cell.set(count_cell.get() + 1);
1949 }
1950
1951 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1952 let count_cell = &self.script_blocking_stylesheets_count;
1953 assert!(count_cell.get() > 0);
1954 count_cell.set(count_cell.get() - 1);
1955 }
1956
1957 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1958 self.render_blocking_element_count.get()
1959 }
1960
1961 pub(crate) fn increment_render_blocking_element_count(&self) {
1963 assert!(self.allows_adding_render_blocking_elements());
1970 let count_cell = &self.render_blocking_element_count;
1971 count_cell.set(count_cell.get() + 1);
1972 }
1973
1974 pub(crate) fn decrement_render_blocking_element_count(&self) {
1976 let count_cell = &self.render_blocking_element_count;
1982 assert!(count_cell.get() > 0);
1983 count_cell.set(count_cell.get() - 1);
1984 }
1985
1986 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1988 self.is_html_document && self.GetBody().is_none()
1991 }
1992
1993 pub(crate) fn is_render_blocked(&self) -> bool {
1995 self.render_blocking_element_count() > 0
1999 }
2004
2005 pub(crate) fn invalidate_stylesheets(&self) {
2006 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
2007
2008 if let Some(element) = self.GetDocumentElement() {
2012 element.upcast::<Node>().dirty(NodeDamage::Style);
2013 }
2014 }
2015
2016 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
2019 !self.animation_frame_list.borrow().is_empty()
2020 }
2021
2022 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
2024 let ident = self.animation_frame_ident.get() + 1;
2025 self.animation_frame_ident.set(ident);
2026
2027 let had_animation_frame_callbacks;
2028 {
2029 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
2030 had_animation_frame_callbacks = !animation_frame_list.is_empty();
2031 animation_frame_list.push_back((ident, Some(callback)));
2032 }
2033
2034 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
2040 self.window().send_to_constellation(
2041 ScriptToConstellationMessage::ChangeRunningAnimationsState(
2042 AnimationState::AnimationCallbacksPresent,
2043 ),
2044 );
2045 }
2046
2047 ident
2048 }
2049
2050 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
2052 let mut list = self.animation_frame_list.borrow_mut();
2053 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
2054 pair.1 = None;
2055 }
2056 }
2057
2058 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
2060 let _realm = enter_realm(self);
2061
2062 self.running_animation_callbacks.set(true);
2063 let timing = self.global().performance().Now();
2064
2065 let num_callbacks = self.animation_frame_list.borrow().len();
2066 for _ in 0..num_callbacks {
2067 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
2068 if let Some(callback) = maybe_callback {
2069 callback.call(self, *timing, can_gc);
2070 }
2071 }
2072 self.running_animation_callbacks.set(false);
2073
2074 if self.animation_frame_list.borrow().is_empty() {
2075 self.window().send_to_constellation(
2076 ScriptToConstellationMessage::ChangeRunningAnimationsState(
2077 AnimationState::NoAnimationCallbacksPresent,
2078 ),
2079 );
2080 }
2081 }
2082
2083 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
2084 self.policy_container.borrow()
2085 }
2086
2087 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
2088 *self.policy_container.borrow_mut() = policy_container;
2089 }
2090
2091 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
2092 self.policy_container.borrow_mut().set_csp_list(csp_list);
2093 }
2094
2095 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
2097 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
2099 csp_list.push(policy);
2100 self.policy_container
2101 .borrow_mut()
2102 .set_csp_list(Some(csp_list));
2103 }
2104
2105 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
2106 Ref::map(self.policy_container.borrow(), |policy_container| {
2107 &policy_container.csp_list
2108 })
2109 }
2110
2111 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
2112 self.preloaded_resources.borrow()
2113 }
2114
2115 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
2116 self.preloaded_resources
2117 .borrow_mut()
2118 .insert(key, preload_id);
2119 }
2120
2121 pub(crate) fn fetch<Listener: FetchResponseListener>(
2122 &self,
2123 load: LoadType,
2124 mut request: RequestBuilder,
2125 listener: Listener,
2126 ) {
2127 request = request
2128 .insecure_requests_policy(self.insecure_requests_policy())
2129 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2130 let callback = NetworkListener {
2131 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2132 task_source: self
2133 .owner_global()
2134 .task_manager()
2135 .networking_task_source()
2136 .into(),
2137 }
2138 .into_callback();
2139 self.loader_mut()
2140 .fetch_async_with_callback(load, request, callback);
2141 }
2142
2143 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
2144 &self,
2145 mut request: RequestBuilder,
2146 listener: Listener,
2147 ) {
2148 request = request
2149 .insecure_requests_policy(self.insecure_requests_policy())
2150 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2151 let callback = NetworkListener {
2152 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2153 task_source: self
2154 .owner_global()
2155 .task_manager()
2156 .networking_task_source()
2157 .into(),
2158 }
2159 .into_callback();
2160 self.loader_mut().fetch_async_background(request, callback);
2161 }
2162
2163 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
2165 match self.window().window_proxy().frame_element() {
2166 None => DomRoot::from_ref(self),
2169 Some(container) => container.owner_document().deferred_fetch_control_document(),
2171 }
2172 }
2173
2174 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
2176 let control_document = self.deferred_fetch_control_document();
2178 let navigable = control_document.window();
2180 let is_top_level = navigable.is_top_level();
2183 let deferred_fetch_allowed = true;
2187 let deferred_fetch_minimal_allowed = true;
2191 let mut quota = match is_top_level {
2193 true if !deferred_fetch_allowed => 0,
2195 true if !deferred_fetch_minimal_allowed => 640 * 1024,
2197 true => 512 * 1024,
2199 _ if deferred_fetch_allowed => 0,
2203 _ if deferred_fetch_minimal_allowed => 8 * 1024,
2207 _ => 0,
2209 } as isize;
2210 let mut quota_for_request_origin = 64 * 1024_isize;
2212 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
2221 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
2223 continue;
2224 }
2225 let request_length = deferred_fetch.request.total_request_length();
2227 quota -= request_length as isize;
2229 if deferred_fetch.request.url().origin() == origin {
2232 quota_for_request_origin -= request_length as isize;
2233 }
2234 }
2235 if quota <= 0 {
2237 return 0;
2238 }
2239 if quota < quota_for_request_origin {
2241 return quota;
2242 }
2243 quota_for_request_origin
2245 }
2246
2247 pub(crate) fn update_document_for_history_step_application(
2249 &self,
2250 old_url: &ServoUrl,
2251 new_url: &ServoUrl,
2252 ) {
2253 if old_url.as_url()[Position::BeforeFragment..] !=
2283 new_url.as_url()[Position::BeforeFragment..]
2284 {
2285 let window = Trusted::new(self.owner_window().deref());
2286 let old_url = old_url.to_string();
2287 let new_url = new_url.to_string();
2288 self.owner_global()
2289 .task_manager()
2290 .dom_manipulation_task_source()
2291 .queue(task!(hashchange_event: move || {
2292 let window = window.root();
2293 HashChangeEvent::new(
2294 &window,
2295 atom!("hashchange"),
2296 false,
2297 false,
2298 old_url,
2299 new_url,
2300 CanGc::note(),
2301 )
2302 .upcast::<Event>()
2303 .fire(window.upcast(), CanGc::note());
2304 }));
2305 }
2306 }
2307
2308 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut js::context::JSContext) {
2311 debug!("Document got finish_load: {:?}", load);
2313 self.loader.borrow_mut().finish_load(&load);
2314
2315 match load {
2316 LoadType::Stylesheet(_) => {
2317 self.process_pending_parsing_blocking_script(cx);
2320
2321 self.process_deferred_scripts(cx);
2323 },
2324 LoadType::PageSource(_) => {
2325 if self.has_browsing_context && self.is_fully_active() {
2328 self.window().allow_layout_if_necessary();
2329 }
2330
2331 self.process_deferred_scripts(cx);
2336 },
2337 _ => {},
2338 }
2339
2340 let loader = self.loader.borrow();
2347
2348 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
2350 update_with_current_instant(&self.top_level_dom_complete);
2351 }
2352
2353 if loader.is_blocked() || loader.events_inhibited() {
2354 return;
2356 }
2357
2358 ScriptThread::mark_document_with_no_blocked_loads(self);
2359 }
2360
2361 pub(crate) fn check_if_unloading_is_cancelled(
2363 &self,
2364 recursive_flag: bool,
2365 can_gc: CanGc,
2366 ) -> bool {
2367 self.incr_ignore_opens_during_unload_counter();
2370 let beforeunload_event = BeforeUnloadEvent::new(
2372 &self.window,
2373 atom!("beforeunload"),
2374 EventBubbles::Bubbles,
2375 EventCancelable::Cancelable,
2376 can_gc,
2377 );
2378 let event = beforeunload_event.upcast::<Event>();
2379 event.set_trusted(true);
2380 let event_target = self.window.upcast::<EventTarget>();
2381 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2382 self.window
2383 .dispatch_event_with_target_override(event, can_gc);
2384 if has_listeners {
2387 self.salvageable.set(false);
2388 }
2389 let mut can_unload = true;
2390 let default_prevented = event.DefaultPrevented();
2392 let return_value_not_empty = !event
2393 .downcast::<BeforeUnloadEvent>()
2394 .unwrap()
2395 .ReturnValue()
2396 .is_empty();
2397 if default_prevented || return_value_not_empty {
2398 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2399 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2400 self.send_to_embedder(msg);
2401 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2402 }
2403 if !recursive_flag {
2405 let iframes: Vec<_> = self.iframes().iter().collect();
2408 for iframe in &iframes {
2409 let document = iframe.owner_document();
2411 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2412 if !document.salvageable() {
2413 self.salvageable.set(false);
2414 }
2415 if !can_unload {
2416 break;
2417 }
2418 }
2419 }
2420 self.decr_ignore_opens_during_unload_counter();
2422 can_unload
2423 }
2424
2425 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2427 self.incr_ignore_opens_during_unload_counter();
2430 if self.page_showing.get() {
2432 self.page_showing.set(false);
2434 let event = PageTransitionEvent::new(
2437 &self.window,
2438 atom!("pagehide"),
2439 false, false, self.salvageable.get(), can_gc,
2443 );
2444 let event = event.upcast::<Event>();
2445 event.set_trusted(true);
2446 self.window
2447 .dispatch_event_with_target_override(event, can_gc);
2448 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2450 }
2451 if !self.fired_unload.get() {
2453 let event = Event::new(
2454 self.window.upcast(),
2455 atom!("unload"),
2456 EventBubbles::Bubbles,
2457 EventCancelable::Cancelable,
2458 can_gc,
2459 );
2460 event.set_trusted(true);
2461 let event_target = self.window.upcast::<EventTarget>();
2462 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2463 self.window
2464 .dispatch_event_with_target_override(&event, can_gc);
2465 self.fired_unload.set(true);
2466 if has_listeners {
2468 self.salvageable.set(false);
2469 }
2470 }
2471 if !recursive_flag {
2475 let iframes: Vec<_> = self.iframes().iter().collect();
2478 for iframe in &iframes {
2479 let document = iframe.owner_document();
2481 document.unload(true, can_gc);
2482 if !document.salvageable() {
2483 self.salvageable.set(false);
2484 }
2485 }
2486 }
2487
2488 self.unloading_cleanup_steps();
2490
2491 self.window.as_global_scope().clean_up_all_file_resources();
2493
2494 self.decr_ignore_opens_during_unload_counter();
2496
2497 }
2500
2501 fn completely_finish_loading(&self) {
2503 self.completely_loaded.set(true);
2508 self.notify_constellation_load();
2517
2518 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2527 &*self.declarative_refresh.borrow()
2528 {
2529 self.window.as_global_scope().schedule_callback(
2530 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2531 window: DomRoot::from_ref(self.window()),
2532 url: url.clone(),
2533 }),
2534 Duration::from_secs(*time),
2535 );
2536 }
2537 }
2538
2539 pub(crate) fn maybe_queue_document_completion(&self) {
2541 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2543 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2544 None => false,
2545 };
2546
2547 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2552 !self.is_fully_active() ||
2553 is_in_delaying_load_events_mode ||
2554 self.loader.borrow().events_inhibited();
2557
2558 if not_ready_for_load {
2559 return;
2561 }
2562
2563 self.loader.borrow_mut().inhibit_events();
2564
2565 debug!("Document loads are complete.");
2570 let document = Trusted::new(self);
2571 self.owner_global()
2572 .task_manager()
2573 .dom_manipulation_task_source()
2574 .queue(task!(fire_load_event: move || {
2575 let document = document.root();
2576 let window = document.window();
2578 if !window.is_alive() {
2579 return;
2580 }
2581
2582 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2584
2585 if document.browsing_context().is_none() {
2587 return;
2588 }
2589
2590 update_with_current_instant(&document.load_event_start);
2592
2593 let load_event = Event::new(
2595 window.upcast(),
2596 atom!("load"),
2597 EventBubbles::DoesNotBubble,
2598 EventCancelable::NotCancelable,
2599 CanGc::note(),
2600 );
2601 load_event.set_trusted(true);
2602 debug!("About to dispatch load for {:?}", document.url());
2603 window.dispatch_event_with_target_override(&load_event, CanGc::note());
2604
2605 update_with_current_instant(&document.load_event_end);
2615
2616 document.page_showing.set(true);
2621
2622 let page_show_event = PageTransitionEvent::new(
2624 window,
2625 atom!("pageshow"),
2626 false, false, false, CanGc::note(),
2630 );
2631 let page_show_event = page_show_event.upcast::<Event>();
2632 page_show_event.set_trusted(true);
2633 page_show_event.fire(window.upcast(), CanGc::note());
2634
2635 document.completely_finish_loading();
2637
2638 if let Some(fragment) = document.url().fragment() {
2642 document.scroll_to_the_fragment(fragment);
2643 }
2644 }));
2645
2646 #[cfg(feature = "webxr")]
2661 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2662 self.window.Navigator().Xr().dispatch_sessionavailable();
2663 }
2664 }
2665
2666 pub(crate) fn completely_loaded(&self) -> bool {
2667 self.completely_loaded.get()
2668 }
2669
2670 pub(crate) fn set_pending_parsing_blocking_script(
2672 &self,
2673 script: &HTMLScriptElement,
2674 load: Option<ScriptResult>,
2675 ) {
2676 assert!(!self.has_pending_parsing_blocking_script());
2677 *self.pending_parsing_blocking_script.borrow_mut() =
2678 Some(PendingScript::new_with_load(script, load));
2679 }
2680
2681 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2683 self.pending_parsing_blocking_script.borrow().is_some()
2684 }
2685
2686 pub(crate) fn pending_parsing_blocking_script_loaded(
2688 &self,
2689 element: &HTMLScriptElement,
2690 result: ScriptResult,
2691 cx: &mut js::context::JSContext,
2692 ) {
2693 {
2694 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2695 let entry = blocking_script.as_mut().unwrap();
2696 assert!(&*entry.element == element);
2697 entry.loaded(result);
2698 }
2699 self.process_pending_parsing_blocking_script(cx);
2700 }
2701
2702 fn process_pending_parsing_blocking_script(&self, cx: &mut js::context::JSContext) {
2703 if self.script_blocking_stylesheets_count.get() > 0 {
2704 return;
2705 }
2706 let pair = self
2707 .pending_parsing_blocking_script
2708 .borrow_mut()
2709 .as_mut()
2710 .and_then(PendingScript::take_result);
2711 if let Some((element, result)) = pair {
2712 *self.pending_parsing_blocking_script.borrow_mut() = None;
2713 self.get_current_parser()
2714 .unwrap()
2715 .resume_with_pending_parsing_blocking_script(&element, result, cx);
2716 }
2717 }
2718
2719 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2721 self.asap_scripts_set
2722 .borrow_mut()
2723 .push(Dom::from_ref(script));
2724 }
2725
2726 pub(crate) fn asap_script_loaded(
2729 &self,
2730 cx: &mut js::context::JSContext,
2731 element: &HTMLScriptElement,
2732 result: ScriptResult,
2733 ) {
2734 {
2735 let mut scripts = self.asap_scripts_set.borrow_mut();
2736 let idx = scripts
2737 .iter()
2738 .position(|entry| &**entry == element)
2739 .unwrap();
2740 scripts.swap_remove(idx);
2741 }
2742 element.execute(cx, result);
2743 }
2744
2745 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2747 self.asap_in_order_scripts_list.push(script);
2748 }
2749
2750 pub(crate) fn asap_in_order_script_loaded(
2753 &self,
2754 cx: &mut js::context::JSContext,
2755 element: &HTMLScriptElement,
2756 result: ScriptResult,
2757 ) {
2758 self.asap_in_order_scripts_list.loaded(element, result);
2759 while let Some((element, result)) = self
2760 .asap_in_order_scripts_list
2761 .take_next_ready_to_be_executed()
2762 {
2763 element.execute(cx, result);
2764 }
2765 }
2766
2767 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2769 self.deferred_scripts.push(script);
2770 }
2771
2772 pub(crate) fn deferred_script_loaded(
2775 &self,
2776 cx: &mut js::context::JSContext,
2777 element: &HTMLScriptElement,
2778 result: ScriptResult,
2779 ) {
2780 self.deferred_scripts.loaded(element, result);
2781 self.process_deferred_scripts(cx);
2782 }
2783
2784 fn process_deferred_scripts(&self, cx: &mut js::context::JSContext) {
2786 if self.ready_state.get() != DocumentReadyState::Interactive {
2787 return;
2788 }
2789 loop {
2791 if self.script_blocking_stylesheets_count.get() > 0 {
2792 return;
2793 }
2794 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2795 {
2796 element.execute(cx, result);
2797 } else {
2798 break;
2799 }
2800 }
2801 if self.deferred_scripts.is_empty() {
2802 self.maybe_dispatch_dom_content_loaded();
2804 }
2805 }
2806
2807 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2809 if self.domcontentloaded_dispatched.get() {
2810 return;
2811 }
2812 self.domcontentloaded_dispatched.set(true);
2813 assert_ne!(
2814 self.ReadyState(),
2815 DocumentReadyState::Complete,
2816 "Complete before DOMContentLoaded?"
2817 );
2818
2819 let document = Trusted::new(self);
2822 self.owner_global()
2823 .task_manager()
2824 .dom_manipulation_task_source()
2825 .queue(
2826 task!(fire_dom_content_loaded_event: move || {
2827 let document = document.root();
2828
2829 update_with_current_instant(&document.dom_content_loaded_event_start);
2832
2833 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2836
2837 update_with_current_instant(&document.dom_content_loaded_event_end);
2840
2841 })
2848 );
2849
2850 self.interactive_time
2852 .borrow()
2853 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2854
2855 }
2858
2859 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut js::context::JSContext) {
2861 if !self.is_fully_active() {
2863 self.salvageable.set(false);
2868 }
2872 for exited_iframe in self.iframes().iter() {
2885 debug!("Destroying nested iframe document");
2886 exited_iframe.destroy_document_and_its_descendants(cx);
2887 }
2888 self.destroy(cx);
2893 }
2896
2897 pub(crate) fn destroy(&self, cx: &mut js::context::JSContext) {
2899 let exited_window = self.window();
2900 self.abort(cx);
2902 self.salvageable.set(false);
2904 self.unloading_cleanup_steps();
2914
2915 exited_window
2918 .as_global_scope()
2919 .task_manager()
2920 .cancel_all_tasks_and_ignore_future_tasks();
2921
2922 exited_window.discard_browsing_context();
2924
2925 }
2937
2938 fn terminate_fetch_group(&self) -> bool {
2940 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2941
2942 for canceller in &mut load_cancellers {
2946 if !canceller.keep_alive() {
2947 canceller.terminate();
2948 }
2949 }
2950 self.owner_global().process_deferred_fetches();
2952
2953 !load_cancellers.is_empty()
2954 }
2955
2956 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
2958 self.loader.borrow_mut().inhibit_events();
2960
2961 for iframe in self.iframes().iter() {
2963 if let Some(document) = iframe.GetContentDocument() {
2964 document.abort(cx);
2965 }
2966 }
2967
2968 self.script_blocking_stylesheets_count.set(0);
2974 *self.pending_parsing_blocking_script.borrow_mut() = None;
2975 *self.asap_scripts_set.borrow_mut() = vec![];
2976 self.asap_in_order_scripts_list.clear();
2977 self.deferred_scripts.clear();
2978 let loads_cancelled = self.terminate_fetch_group();
2979 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2980 if loads_cancelled || event_sources_canceled {
2981 self.salvageable.set(false);
2983 };
2984
2985 self.owner_global()
2990 .task_manager()
2991 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2992
2993 if let Some(parser) = self.get_current_parser() {
2998 self.active_parser_was_aborted.set(true);
3000 parser.abort(cx);
3002 self.salvageable.set(false);
3004 }
3005 }
3006
3007 pub(crate) fn notify_constellation_load(&self) {
3008 self.window()
3009 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
3010 }
3011
3012 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
3013 self.current_parser.set(script);
3014 }
3015
3016 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
3017 self.current_parser.get()
3018 }
3019
3020 pub(crate) fn get_current_parser_line(&self) -> u32 {
3021 self.get_current_parser()
3022 .map(|parser| parser.get_current_line())
3023 .unwrap_or(0)
3024 }
3025
3026 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
3029 self.iframes.borrow_mut().validate(self);
3030 self.iframes.borrow()
3031 }
3032
3033 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
3036 self.iframes.borrow_mut().validate(self);
3037 self.iframes.borrow_mut()
3038 }
3039
3040 pub(crate) fn invalidate_iframes_collection(&self) {
3041 self.iframes.borrow_mut().invalidate();
3042 }
3043
3044 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
3045 self.dom_interactive.get()
3046 }
3047
3048 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
3049 self.interactive_time
3050 .borrow_mut()
3051 .set_navigation_start(navigation_start);
3052 }
3053
3054 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
3055 self.interactive_time.borrow()
3056 }
3057
3058 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
3059 self.get_interactive_metrics().get_tti().is_some()
3060 }
3061
3062 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
3063 self.dom_content_loaded_event_start.get()
3064 }
3065
3066 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
3067 self.dom_content_loaded_event_end.get()
3068 }
3069
3070 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
3071 self.dom_complete.get()
3072 }
3073
3074 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
3075 self.top_level_dom_complete.get()
3076 }
3077
3078 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
3079 self.load_event_start.get()
3080 }
3081
3082 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
3083 self.load_event_end.get()
3084 }
3085
3086 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
3087 self.unload_event_start.get()
3088 }
3089
3090 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
3091 self.unload_event_end.get()
3092 }
3093
3094 pub(crate) fn start_tti(&self) {
3095 if self.get_interactive_metrics().needs_tti() {
3096 self.tti_window.borrow_mut().start_window();
3097 }
3098 }
3099
3100 pub(crate) fn record_tti_if_necessary(&self) {
3104 if self.has_recorded_tti_metric() {
3105 return;
3106 }
3107 if self.tti_window.borrow().needs_check() {
3108 self.get_interactive_metrics()
3109 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
3110 self.tti_window.borrow().get_start(),
3111 ));
3112 }
3113 }
3114
3115 fn fire_focus_event(
3117 &self,
3118 focus_event_type: FocusEventType,
3119 event_target: &EventTarget,
3120 related_target: Option<&EventTarget>,
3121 can_gc: CanGc,
3122 ) {
3123 let (event_name, does_bubble) = match focus_event_type {
3124 FocusEventType::Focus => ("focus".into(), EventBubbles::DoesNotBubble),
3125 FocusEventType::Blur => ("blur".into(), EventBubbles::DoesNotBubble),
3126 };
3127 let event = FocusEvent::new(
3128 &self.window,
3129 event_name,
3130 does_bubble,
3131 EventCancelable::NotCancelable,
3132 Some(&self.window),
3133 0i32,
3134 related_target,
3135 can_gc,
3136 );
3137 let event = event.upcast::<Event>();
3138 event.set_trusted(true);
3139 event.fire(event_target, can_gc);
3140 }
3141
3142 pub(crate) fn is_cookie_averse(&self) -> bool {
3144 !self.has_browsing_context || !url_has_network_scheme(&self.url())
3145 }
3146
3147 pub(crate) fn lookup_custom_element_definition(
3149 &self,
3150 namespace: &Namespace,
3151 local_name: &LocalName,
3152 is: Option<&LocalName>,
3153 ) -> Option<Rc<CustomElementDefinition>> {
3154 if *namespace != ns!(html) {
3156 return None;
3157 }
3158
3159 if !self.has_browsing_context {
3161 return None;
3162 }
3163
3164 let registry = self.window.CustomElements();
3166
3167 registry.lookup_definition(local_name, is)
3168 }
3169
3170 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
3172 self.window.CustomElements()
3173 }
3174
3175 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
3176 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3177 self.throw_on_dynamic_markup_insertion_counter
3178 .set(counter + 1);
3179 }
3180
3181 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
3182 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3183 self.throw_on_dynamic_markup_insertion_counter
3184 .set(counter - 1);
3185 }
3186
3187 pub(crate) fn react_to_environment_changes(&self) {
3188 for image in self.responsive_images.borrow().iter() {
3189 image.react_to_environment_changes();
3190 }
3191 }
3192
3193 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3194 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3195 }
3196
3197 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3198 let index = self
3199 .responsive_images
3200 .borrow()
3201 .iter()
3202 .position(|x| **x == *img);
3203 if let Some(i) = index {
3204 self.responsive_images.borrow_mut().remove(i);
3205 }
3206 }
3207
3208 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3209 let did_have_these_media_controls = self
3210 .media_controls
3211 .borrow_mut()
3212 .insert(id.to_string(), Dom::from_ref(controls))
3213 .is_some();
3214 debug_assert!(
3215 !did_have_these_media_controls,
3216 "Trying to register known media controls"
3217 );
3218 }
3219
3220 pub(crate) fn unregister_media_controls(&self, id: &str) {
3221 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3222 debug_assert!(
3223 did_have_these_media_controls,
3224 "Trying to unregister unknown media controls"
3225 );
3226 }
3227
3228 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3229 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3230 if dirty_canvases
3231 .iter()
3232 .any(|dirty_canvas| dirty_canvas == canvas)
3233 {
3234 return;
3235 }
3236 dirty_canvases.push(canvas.clone());
3237 }
3238
3239 pub(crate) fn needs_rendering_update(&self) -> bool {
3243 if !self.is_fully_active() {
3244 return false;
3245 }
3246 if !self.window().layout_blocked() &&
3247 (!self.restyle_reason().is_empty() ||
3248 self.window().layout().needs_new_display_list())
3249 {
3250 return true;
3251 }
3252 if !self.rendering_update_reasons.get().is_empty() {
3253 return true;
3254 }
3255 if self.event_handler.has_pending_input_events() {
3256 return true;
3257 }
3258 if self.has_pending_scroll_events() {
3259 return true;
3260 }
3261 if self.window().has_unhandled_resize_event() {
3262 return true;
3263 }
3264 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3265 {
3266 return true;
3267 }
3268
3269 false
3270 }
3271
3272 pub(crate) fn update_the_rendering(&self) -> (ReflowPhasesRun, ReflowStatistics) {
3280 assert!(!self.is_render_blocked());
3281
3282 let mut phases = ReflowPhasesRun::empty();
3283 if self.has_pending_animated_image_update.get() {
3284 self.image_animation_manager
3285 .borrow()
3286 .update_active_frames(&self.window, self.current_animation_timeline_value());
3287 self.has_pending_animated_image_update.set(false);
3288 phases.insert(ReflowPhasesRun::UpdatedImageData);
3289 }
3290
3291 self.current_rendering_epoch
3292 .set(self.current_rendering_epoch.get().next());
3293 let current_rendering_epoch = self.current_rendering_epoch.get();
3294
3295 let image_keys: Vec<_> = self
3297 .dirty_canvases
3298 .borrow_mut()
3299 .drain(..)
3300 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3301 .collect();
3302
3303 let pipeline_id = self.window().pipeline_id();
3306 if !image_keys.is_empty() {
3307 phases.insert(ReflowPhasesRun::UpdatedImageData);
3308 self.waiting_on_canvas_image_updates.set(true);
3309 self.window().paint_api().delay_new_frame_for_canvas(
3310 self.webview_id(),
3311 self.window().pipeline_id(),
3312 current_rendering_epoch,
3313 image_keys,
3314 );
3315 }
3316
3317 let (reflow_phases, statistics) = self.window().reflow(ReflowGoal::UpdateTheRendering);
3318 let phases = phases.union(reflow_phases);
3319
3320 self.window().paint_api().update_epoch(
3321 self.webview_id(),
3322 pipeline_id,
3323 current_rendering_epoch,
3324 );
3325
3326 (phases, statistics)
3327 }
3328
3329 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3330 self.waiting_on_canvas_image_updates.set(false);
3331 }
3332
3333 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3334 self.waiting_on_canvas_image_updates.get()
3335 }
3336
3337 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
3347 if !self.is_fully_active() {
3348 return false;
3349 }
3350
3351 let fonts = self.Fonts(can_gc);
3352 if !fonts.waiting_to_fullfill_promise() {
3353 return false;
3354 }
3355 if self.window().font_context().web_fonts_still_loading() != 0 {
3356 return false;
3357 }
3358 if self.ReadyState() != DocumentReadyState::Complete {
3359 return false;
3360 }
3361 if !self.restyle_reason().is_empty() {
3362 return false;
3363 }
3364 if !self.rendering_update_reasons.get().is_empty() {
3365 return false;
3366 }
3367
3368 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
3369
3370 if result {
3374 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3375 }
3376
3377 result
3378 }
3379
3380 pub(crate) fn id_map(
3381 &self,
3382 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3383 self.id_map.borrow()
3384 }
3385
3386 pub(crate) fn name_map(
3387 &self,
3388 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3389 self.name_map.borrow()
3390 }
3391
3392 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3394 self.resize_observers
3395 .borrow_mut()
3396 .push(Dom::from_ref(resize_observer));
3397 }
3398
3399 pub(crate) fn has_resize_observers(&self) -> bool {
3401 !self.resize_observers.borrow().is_empty()
3402 }
3403
3404 pub(crate) fn gather_active_resize_observations_at_depth(
3407 &self,
3408 depth: &ResizeObservationDepth,
3409 ) -> bool {
3410 let mut has_active_resize_observations = false;
3411 for observer in self.resize_observers.borrow_mut().iter_mut() {
3412 observer.gather_active_resize_observations_at_depth(
3413 depth,
3414 &mut has_active_resize_observations,
3415 );
3416 }
3417 has_active_resize_observations
3418 }
3419
3420 #[expect(clippy::redundant_iter_cloned)]
3422 pub(crate) fn broadcast_active_resize_observations(
3423 &self,
3424 can_gc: CanGc,
3425 ) -> ResizeObservationDepth {
3426 let mut shallowest = ResizeObservationDepth::max();
3427 let iterator: Vec<DomRoot<ResizeObserver>> = self
3431 .resize_observers
3432 .borrow()
3433 .iter()
3434 .cloned()
3435 .map(|obs| DomRoot::from_ref(&*obs))
3436 .collect();
3437 for observer in iterator {
3438 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3439 }
3440 shallowest
3441 }
3442
3443 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3445 self.resize_observers
3446 .borrow()
3447 .iter()
3448 .any(|observer| observer.has_skipped_resize_observations())
3449 }
3450
3451 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3453 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3454 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3455 ..Default::default()
3456 };
3457 self.window
3458 .as_global_scope()
3459 .report_an_error(error_info, HandleValue::null(), can_gc);
3460 }
3461
3462 pub(crate) fn status_code(&self) -> Option<u16> {
3463 self.status_code
3464 }
3465
3466 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3468 let encoding = self.encoding.get();
3474
3475 let base_url = self.base_url();
3481
3482 url::Url::options()
3484 .base_url(Some(base_url.as_url()))
3485 .encoding_override(Some(&|input| {
3486 servo_url::encoding::encode_as_url_query_string(input, encoding)
3487 }))
3488 .parse(url)
3489 .map(ServoUrl::from)
3490 }
3491
3492 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3494 if !self.has_browsing_context {
3496 return false;
3497 }
3498
3499 if !self.is_fully_active() {
3501 return false;
3502 }
3503
3504 true
3510 }
3511
3512 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3515 self.intersection_observers
3516 .borrow_mut()
3517 .push(Dom::from_ref(intersection_observer));
3518 }
3519
3520 pub(crate) fn remove_intersection_observer(
3524 &self,
3525 intersection_observer: &IntersectionObserver,
3526 ) {
3527 self.intersection_observers
3528 .borrow_mut()
3529 .retain(|observer| *observer != intersection_observer)
3530 }
3531
3532 pub(crate) fn update_intersection_observer_steps(
3534 &self,
3535 time: CrossProcessInstant,
3536 can_gc: CanGc,
3537 ) {
3538 for intersection_observer in &*self.intersection_observers.borrow() {
3540 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3541 }
3542 }
3543
3544 fn update_single_intersection_observer_steps(
3546 &self,
3547 intersection_observer: &IntersectionObserver,
3548 time: CrossProcessInstant,
3549 can_gc: CanGc,
3550 ) {
3551 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3554
3555 intersection_observer.update_intersection_observations_steps(
3559 self,
3560 time,
3561 root_bounds,
3562 can_gc,
3563 );
3564 }
3565
3566 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3568 self.intersection_observer_task_queued.set(false);
3571
3572 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3577
3578 for intersection_observer in notify_list.iter() {
3581 intersection_observer.invoke_callback_if_necessary(can_gc);
3583 }
3584 }
3585
3586 pub(crate) fn queue_an_intersection_observer_task(&self) {
3588 if self.intersection_observer_task_queued.get() {
3591 return;
3592 }
3593
3594 self.intersection_observer_task_queued.set(true);
3597
3598 let document = Trusted::new(self);
3602 self.owner_global()
3603 .task_manager()
3604 .intersection_observer_task_source()
3605 .queue(task!(notify_intersection_observers: move || {
3606 document.root().notify_intersection_observers(CanGc::note());
3607 }));
3608 }
3609
3610 pub(crate) fn handle_paint_metric(
3611 &self,
3612 metric_type: ProgressiveWebMetricType,
3613 metric_value: CrossProcessInstant,
3614 first_reflow: bool,
3615 can_gc: CanGc,
3616 ) {
3617 let metrics = self.interactive_time.borrow();
3618 match metric_type {
3619 ProgressiveWebMetricType::FirstPaint |
3620 ProgressiveWebMetricType::FirstContentfulPaint => {
3621 let binding = PerformancePaintTiming::new(
3622 self.window.as_global_scope(),
3623 metric_type.clone(),
3624 metric_value,
3625 can_gc,
3626 );
3627 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3628 let entry = binding.upcast::<PerformanceEntry>();
3629 self.window.Performance().queue_entry(entry);
3630 },
3631 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3632 let binding = LargestContentfulPaint::new(
3633 self.window.as_global_scope(),
3634 metric_value,
3635 area,
3636 url,
3637 can_gc,
3638 );
3639 metrics.set_largest_contentful_paint(metric_value, area);
3640 let entry = binding.upcast::<PerformanceEntry>();
3641 self.window.Performance().queue_entry(entry);
3642 },
3643 ProgressiveWebMetricType::TimeToInteractive => {
3644 unreachable!("Unexpected non-paint metric.")
3645 },
3646 }
3647 }
3648
3649 fn write(
3651 &self,
3652 cx: &mut js::context::JSContext,
3653 text: Vec<TrustedHTMLOrString>,
3654 line_feed: bool,
3655 containing_class: &str,
3656 field: &str,
3657 ) -> ErrorResult {
3658 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3660 let mut is_trusted = true;
3662 for value in text {
3664 match value {
3665 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3667 strings.push(trusted_html.to_string());
3668 },
3669 TrustedHTMLOrString::String(str_) => {
3670 is_trusted = false;
3672 strings.push(str_.into());
3674 },
3675 };
3676 }
3677 let mut string = itertools::join(strings, "");
3678 if !is_trusted {
3682 string = TrustedHTML::get_trusted_type_compliant_string(
3683 cx,
3684 &self.global(),
3685 TrustedHTMLOrString::String(string.into()),
3686 &format!("{} {}", containing_class, field),
3687 )?
3688 .str()
3689 .to_owned();
3690 }
3691 if line_feed {
3693 string.push('\n');
3694 }
3695 if !self.is_html_document() {
3697 return Err(Error::InvalidState(None));
3698 }
3699
3700 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3703 return Err(Error::InvalidState(None));
3704 }
3705
3706 if !self.is_active() || self.active_parser_was_aborted.get() {
3708 return Ok(());
3709 }
3710
3711 let parser = match self.get_current_parser() {
3712 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3713 _ => {
3715 if self.is_prompting_or_unloading() ||
3718 self.ignore_destructive_writes_counter.get() > 0
3719 {
3720 return Ok(());
3721 }
3722 self.Open(cx, None, None)?;
3724 self.get_current_parser().unwrap()
3725 },
3726 };
3727
3728 parser.write(string.into(), cx);
3730
3731 Ok(())
3732 }
3733
3734 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3735 RefMut::map(
3736 self.details_name_groups.borrow_mut(),
3737 |details_name_groups| details_name_groups.get_or_insert_default(),
3738 )
3739 }
3740}
3741
3742#[derive(MallocSizeOf, PartialEq)]
3743pub(crate) enum DocumentSource {
3744 FromParser,
3745 NotFromParser,
3746}
3747
3748pub(crate) trait LayoutDocumentHelpers<'dom> {
3749 fn is_html_document_for_layout(&self) -> bool;
3750 fn quirks_mode(self) -> QuirksMode;
3751 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3752 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3753 fn shadow_roots_styles_changed(self) -> bool;
3754 fn flush_shadow_roots_stylesheets(self);
3755 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>];
3756}
3757
3758#[expect(unsafe_code)]
3759impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3760 #[inline]
3761 fn is_html_document_for_layout(&self) -> bool {
3762 self.unsafe_get().is_html_document
3763 }
3764
3765 #[inline]
3766 fn quirks_mode(self) -> QuirksMode {
3767 self.unsafe_get().quirks_mode.get()
3768 }
3769
3770 #[inline]
3771 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3772 self.unsafe_get().style_shared_lock()
3773 }
3774
3775 #[inline]
3776 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3777 unsafe {
3782 self.unsafe_get()
3783 .shadow_roots
3784 .borrow_for_layout()
3785 .iter()
3786 .map(|sr| sr.to_layout())
3787 .collect()
3788 }
3789 }
3790
3791 #[inline]
3792 fn shadow_roots_styles_changed(self) -> bool {
3793 self.unsafe_get().shadow_roots_styles_changed.get()
3794 }
3795
3796 #[inline]
3797 fn flush_shadow_roots_stylesheets(self) {
3798 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3799 }
3800
3801 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3802 let id_map = unsafe { self.unsafe_get().id_map.borrow_for_layout() };
3803 let matching_elements = id_map.get(id).map(Vec::as_slice).unwrap_or_default();
3804 unsafe { LayoutDom::to_layout_slice(matching_elements) }
3805 }
3806}
3807
3808pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3812 host_suffix_string: &str,
3813 original_host: Host,
3814) -> Option<Host> {
3815 if host_suffix_string.is_empty() {
3817 return None;
3818 }
3819
3820 let host = match Host::parse(host_suffix_string) {
3822 Ok(host) => host,
3823 Err(_) => return None,
3824 };
3825
3826 if host != original_host {
3828 let host = match host {
3830 Host::Domain(ref host) => host,
3831 _ => return None,
3832 };
3833 let original_host = match original_host {
3834 Host::Domain(ref original_host) => original_host,
3835 _ => return None,
3836 };
3837
3838 let index = original_host.len().checked_sub(host.len())?;
3840 let (prefix, suffix) = original_host.split_at(index);
3841
3842 if !prefix.ends_with('.') {
3843 return None;
3844 }
3845 if suffix != host {
3846 return None;
3847 }
3848
3849 if is_pub_domain(host) {
3851 return None;
3852 }
3853 }
3854
3855 Some(host)
3857}
3858
3859fn url_has_network_scheme(url: &ServoUrl) -> bool {
3861 matches!(url.scheme(), "ftp" | "http" | "https")
3862}
3863
3864#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3865pub(crate) enum HasBrowsingContext {
3866 No,
3867 Yes,
3868}
3869
3870impl Document {
3871 #[allow(clippy::too_many_arguments)]
3872 pub(crate) fn new_inherited(
3873 window: &Window,
3874 has_browsing_context: HasBrowsingContext,
3875 url: Option<ServoUrl>,
3876 about_base_url: Option<ServoUrl>,
3877 origin: MutableOrigin,
3878 is_html_document: IsHTMLDocument,
3879 content_type: Option<Mime>,
3880 last_modified: Option<String>,
3881 activity: DocumentActivity,
3882 source: DocumentSource,
3883 doc_loader: DocumentLoader,
3884 referrer: Option<String>,
3885 status_code: Option<u16>,
3886 canceller: FetchCanceller,
3887 is_initial_about_blank: bool,
3888 allow_declarative_shadow_roots: bool,
3889 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3890 has_trustworthy_ancestor_origin: bool,
3891 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3892 creation_sandboxing_flag_set: SandboxingFlagSet,
3893 can_gc: CanGc,
3894 ) -> Document {
3895 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3896
3897 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3898 (DocumentReadyState::Loading, false)
3899 } else {
3900 (DocumentReadyState::Complete, true)
3901 };
3902
3903 let frame_type = match window.is_top_level() {
3904 true => TimerMetadataFrameType::RootWindow,
3905 false => TimerMetadataFrameType::IFrame,
3906 };
3907 let interactive_time = ProgressiveWebMetrics::new(
3908 window.time_profiler_chan().clone(),
3909 url.clone(),
3910 frame_type,
3911 );
3912
3913 let content_type = content_type.unwrap_or_else(|| {
3914 match is_html_document {
3915 IsHTMLDocument::HTMLDocument => "text/html",
3917 IsHTMLDocument::NonHTMLDocument => "application/xml",
3919 }
3920 .parse()
3921 .unwrap()
3922 });
3923
3924 let encoding = content_type
3925 .get_parameter(CHARSET)
3926 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3927 .unwrap_or(UTF_8);
3928
3929 let has_focus = window.parent_info().is_none();
3930
3931 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3932
3933 Document {
3934 node: Node::new_document_node(),
3935 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3936 window: Dom::from_ref(window),
3937 has_browsing_context,
3938 implementation: Default::default(),
3939 content_type,
3940 last_modified,
3941 url: DomRefCell::new(url),
3942 about_base_url: DomRefCell::new(about_base_url),
3943 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3945 event_handler: DocumentEventHandler::new(window),
3946 embedder_controls: DocumentEmbedderControls::new(window),
3947 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3948 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3949 encoding: Cell::new(encoding),
3951 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3952 activity: Cell::new(activity),
3953 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3954 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3955 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3956 images: Default::default(),
3957 embeds: Default::default(),
3958 links: Default::default(),
3959 forms: Default::default(),
3960 scripts: Default::default(),
3961 anchors: Default::default(),
3962 applets: Default::default(),
3963 iframes: RefCell::new(IFrameCollection::new()),
3964 style_shared_lock: {
3965 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3972 LazyLock::new(StyleSharedRwLock::new);
3973
3974 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3975 },
3977 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3978 stylesheet_list: MutNullableDom::new(None),
3979 ready_state: Cell::new(ready_state),
3980 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3981 focus_transaction: DomRefCell::new(None),
3982 focused: Default::default(),
3983 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3984 has_focus: Cell::new(has_focus),
3985 current_script: Default::default(),
3986 pending_parsing_blocking_script: Default::default(),
3987 script_blocking_stylesheets_count: Default::default(),
3988 render_blocking_element_count: Default::default(),
3989 deferred_scripts: Default::default(),
3990 asap_in_order_scripts_list: Default::default(),
3991 asap_scripts_set: Default::default(),
3992 animation_frame_ident: Cell::new(0),
3993 animation_frame_list: DomRefCell::new(VecDeque::new()),
3994 running_animation_callbacks: Cell::new(false),
3995 loader: DomRefCell::new(doc_loader),
3996 current_parser: Default::default(),
3997 base_element: Default::default(),
3998 target_base_element: Default::default(),
3999 appropriate_template_contents_owner_document: Default::default(),
4000 pending_restyles: DomRefCell::new(FxHashMap::default()),
4001 needs_restyle: Cell::new(RestyleReason::DOMChanged),
4002 dom_interactive: Cell::new(Default::default()),
4003 dom_content_loaded_event_start: Cell::new(Default::default()),
4004 dom_content_loaded_event_end: Cell::new(Default::default()),
4005 dom_complete: Cell::new(Default::default()),
4006 top_level_dom_complete: Cell::new(Default::default()),
4007 load_event_start: Cell::new(Default::default()),
4008 load_event_end: Cell::new(Default::default()),
4009 unload_event_start: Cell::new(Default::default()),
4010 unload_event_end: Cell::new(Default::default()),
4011 https_state: Cell::new(HttpsState::None),
4012 origin: DomRefCell::new(origin),
4013 referrer,
4014 target_element: MutNullableDom::new(None),
4015 policy_container: DomRefCell::new(PolicyContainer::default()),
4016 preloaded_resources: Default::default(),
4017 ignore_destructive_writes_counter: Default::default(),
4018 ignore_opens_during_unload_counter: Default::default(),
4019 spurious_animation_frames: Cell::new(0),
4020 dom_count: Cell::new(1),
4021 fullscreen_element: MutNullableDom::new(None),
4022 form_id_listener_map: Default::default(),
4023 interactive_time: DomRefCell::new(interactive_time),
4024 tti_window: DomRefCell::new(InteractiveWindow::default()),
4025 canceller,
4026 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
4027 page_showing: Cell::new(false),
4028 salvageable: Cell::new(true),
4029 active_parser_was_aborted: Cell::new(false),
4030 fired_unload: Cell::new(false),
4031 responsive_images: Default::default(),
4032 redirect_count: Cell::new(0),
4033 completely_loaded: Cell::new(false),
4034 script_and_layout_blockers: Cell::new(0),
4035 delayed_tasks: Default::default(),
4036 shadow_roots: DomRefCell::new(HashSet::new()),
4037 shadow_roots_styles_changed: Cell::new(false),
4038 media_controls: DomRefCell::new(HashMap::new()),
4039 dirty_canvases: DomRefCell::new(Default::default()),
4040 has_pending_animated_image_update: Cell::new(false),
4041 selection: MutNullableDom::new(None),
4042 timeline: DocumentTimeline::new(window, can_gc).as_traced(),
4043 animations: Animations::new(),
4044 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
4045 dirty_root: Default::default(),
4046 declarative_refresh: Default::default(),
4047 resize_observers: Default::default(),
4048 fonts: Default::default(),
4049 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
4050 status_code,
4051 is_initial_about_blank: Cell::new(is_initial_about_blank),
4052 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
4053 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
4054 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
4055 intersection_observer_task_queued: Cell::new(false),
4056 intersection_observers: Default::default(),
4057 highlighted_dom_node: Default::default(),
4058 adopted_stylesheets: Default::default(),
4059 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
4060 pending_scroll_events: Default::default(),
4061 rendering_update_reasons: Default::default(),
4062 waiting_on_canvas_image_updates: Cell::new(false),
4063 current_rendering_epoch: Default::default(),
4064 custom_element_reaction_stack,
4065 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
4066 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
4067 favicon: RefCell::new(None),
4068 websockets: DOMTracker::new(),
4069 details_name_groups: Default::default(),
4070 protocol_handler_automation_mode: Default::default(),
4071 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
4072 state_override: Default::default(),
4073 value_override: Default::default(),
4074 default_single_line_container_name: Default::default(),
4075 css_styling_flag: Default::default(),
4076 }
4077 }
4078
4079 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
4081 if let Some(csp_list) = self.get_csp_list().as_ref() {
4082 for policy in &csp_list.0 {
4083 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
4084 policy.disposition == PolicyDisposition::Enforce
4085 {
4086 return InsecureRequestsPolicy::Upgrade;
4087 }
4088 }
4089 }
4090
4091 self.inherited_insecure_requests_policy
4092 .get()
4093 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
4094 }
4095
4096 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
4098 &self.event_handler
4099 }
4100
4101 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
4103 &self.embedder_controls
4104 }
4105
4106 fn has_pending_scroll_events(&self) -> bool {
4109 !self.pending_scroll_events.borrow().is_empty()
4110 }
4111
4112 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
4115 self.rendering_update_reasons
4116 .set(self.rendering_update_reasons.get().union(reason));
4117 }
4118
4119 pub(crate) fn clear_rendering_update_reasons(&self) {
4121 self.rendering_update_reasons
4122 .set(RenderingUpdateReason::empty())
4123 }
4124
4125 pub(crate) fn add_script_and_layout_blocker(&self) {
4132 self.script_and_layout_blockers
4133 .set(self.script_and_layout_blockers.get() + 1);
4134 }
4135
4136 #[expect(unsafe_code)]
4137 pub(crate) fn remove_script_and_layout_blocker(&self) {
4141 assert!(self.script_and_layout_blockers.get() > 0);
4142 self.script_and_layout_blockers
4143 .set(self.script_and_layout_blockers.get() - 1);
4144 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
4145 {
4146 let task = self.delayed_tasks.borrow_mut().remove(0);
4147 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
4148 task.run_box(&mut cx);
4149 }
4150 }
4151
4152 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
4154 self.delayed_tasks.borrow_mut().push(Box::new(task));
4155 }
4156
4157 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
4160 assert_eq!(
4161 self.script_and_layout_blockers.get(),
4162 0,
4163 "Attempt to use script or layout while DOM not in a stable state"
4164 );
4165 }
4166
4167 #[allow(clippy::too_many_arguments)]
4168 pub(crate) fn new(
4169 window: &Window,
4170 has_browsing_context: HasBrowsingContext,
4171 url: Option<ServoUrl>,
4172 about_base_url: Option<ServoUrl>,
4173 origin: MutableOrigin,
4174 doctype: IsHTMLDocument,
4175 content_type: Option<Mime>,
4176 last_modified: Option<String>,
4177 activity: DocumentActivity,
4178 source: DocumentSource,
4179 doc_loader: DocumentLoader,
4180 referrer: Option<String>,
4181 status_code: Option<u16>,
4182 canceller: FetchCanceller,
4183 is_initial_about_blank: bool,
4184 allow_declarative_shadow_roots: bool,
4185 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4186 has_trustworthy_ancestor_origin: bool,
4187 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4188 creation_sandboxing_flag_set: SandboxingFlagSet,
4189 can_gc: CanGc,
4190 ) -> DomRoot<Document> {
4191 Self::new_with_proto(
4192 window,
4193 None,
4194 has_browsing_context,
4195 url,
4196 about_base_url,
4197 origin,
4198 doctype,
4199 content_type,
4200 last_modified,
4201 activity,
4202 source,
4203 doc_loader,
4204 referrer,
4205 status_code,
4206 canceller,
4207 is_initial_about_blank,
4208 allow_declarative_shadow_roots,
4209 inherited_insecure_requests_policy,
4210 has_trustworthy_ancestor_origin,
4211 custom_element_reaction_stack,
4212 creation_sandboxing_flag_set,
4213 can_gc,
4214 )
4215 }
4216
4217 #[allow(clippy::too_many_arguments)]
4218 fn new_with_proto(
4219 window: &Window,
4220 proto: Option<HandleObject>,
4221 has_browsing_context: HasBrowsingContext,
4222 url: Option<ServoUrl>,
4223 about_base_url: Option<ServoUrl>,
4224 origin: MutableOrigin,
4225 doctype: IsHTMLDocument,
4226 content_type: Option<Mime>,
4227 last_modified: Option<String>,
4228 activity: DocumentActivity,
4229 source: DocumentSource,
4230 doc_loader: DocumentLoader,
4231 referrer: Option<String>,
4232 status_code: Option<u16>,
4233 canceller: FetchCanceller,
4234 is_initial_about_blank: bool,
4235 allow_declarative_shadow_roots: bool,
4236 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4237 has_trustworthy_ancestor_origin: bool,
4238 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4239 creation_sandboxing_flag_set: SandboxingFlagSet,
4240 can_gc: CanGc,
4241 ) -> DomRoot<Document> {
4242 let document = reflect_dom_object_with_proto(
4243 Box::new(Document::new_inherited(
4244 window,
4245 has_browsing_context,
4246 url,
4247 about_base_url,
4248 origin,
4249 doctype,
4250 content_type,
4251 last_modified,
4252 activity,
4253 source,
4254 doc_loader,
4255 referrer,
4256 status_code,
4257 canceller,
4258 is_initial_about_blank,
4259 allow_declarative_shadow_roots,
4260 inherited_insecure_requests_policy,
4261 has_trustworthy_ancestor_origin,
4262 custom_element_reaction_stack,
4263 creation_sandboxing_flag_set,
4264 can_gc,
4265 )),
4266 window,
4267 proto,
4268 can_gc,
4269 );
4270 {
4271 let node = document.upcast::<Node>();
4272 node.set_owner_doc(&document);
4273 }
4274 document
4275 }
4276
4277 pub(crate) fn get_redirect_count(&self) -> u16 {
4278 self.redirect_count.get()
4279 }
4280
4281 pub(crate) fn set_redirect_count(&self, count: u16) {
4282 self.redirect_count.set(count)
4283 }
4284
4285 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4286 if name.is_empty() {
4287 return 0;
4288 }
4289 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4290 }
4291
4292 pub(crate) fn nth_element_by_name(
4293 &self,
4294 index: u32,
4295 name: &DOMString,
4296 ) -> Option<DomRoot<Node>> {
4297 if name.is_empty() {
4298 return None;
4299 }
4300 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4301 }
4302
4303 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4306 let element = match node.downcast::<Element>() {
4307 Some(element) => element,
4308 None => return false,
4309 };
4310 if element.namespace() != &ns!(html) {
4311 return false;
4312 }
4313 element.get_name().is_some_and(|n| &*n == name)
4314 }
4315
4316 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4317 let doc = self.GetDocumentElement();
4318 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4319 maybe_node
4320 .iter()
4321 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4322 .filter(|node| callback(node))
4323 .count() as u32
4324 }
4325
4326 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4327 &self,
4328 index: u32,
4329 callback: F,
4330 ) -> Option<DomRoot<Node>> {
4331 let doc = self.GetDocumentElement();
4332 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4333 maybe_node
4334 .iter()
4335 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4336 .filter(|node| callback(node))
4337 .nth(index as usize)
4338 .map(|n| DomRoot::from_ref(&*n))
4339 }
4340
4341 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4342 self.GetDocumentElement().and_then(DomRoot::downcast)
4343 }
4344
4345 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
4347 &self.style_shared_lock
4348 }
4349
4350 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4352 let mut stylesheets = self.stylesheets.borrow_mut();
4359 let have_changed = stylesheets.has_changed();
4360 stylesheets.flush_without_invalidation();
4361 have_changed
4362 }
4363
4364 pub(crate) fn salvageable(&self) -> bool {
4365 self.salvageable.get()
4366 }
4367
4368 pub(crate) fn make_document_unsalvageable(&self) {
4370 self.salvageable.set(false);
4376 }
4377
4378 pub(crate) fn appropriate_template_contents_owner_document(
4380 &self,
4381 can_gc: CanGc,
4382 ) -> DomRoot<Document> {
4383 self.appropriate_template_contents_owner_document
4384 .or_init(|| {
4385 let doctype = if self.is_html_document {
4386 IsHTMLDocument::HTMLDocument
4387 } else {
4388 IsHTMLDocument::NonHTMLDocument
4389 };
4390 let new_doc = Document::new(
4391 self.window(),
4392 HasBrowsingContext::No,
4393 None,
4394 None,
4395 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4397 doctype,
4398 None,
4399 None,
4400 DocumentActivity::Inactive,
4401 DocumentSource::NotFromParser,
4402 DocumentLoader::new(&self.loader()),
4403 None,
4404 None,
4405 Default::default(),
4406 false,
4407 self.allow_declarative_shadow_roots(),
4408 Some(self.insecure_requests_policy()),
4409 self.has_trustworthy_ancestor_or_current_origin(),
4410 self.custom_element_reaction_stack.clone(),
4411 self.creation_sandboxing_flag_set(),
4412 can_gc,
4413 );
4414 new_doc
4415 .appropriate_template_contents_owner_document
4416 .set(Some(&new_doc));
4417 new_doc
4418 })
4419 }
4420
4421 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4422 self.id_map
4423 .borrow()
4424 .get(id)
4425 .map(|elements| DomRoot::from_ref(&*elements[0]))
4426 }
4427
4428 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4429 let map = self.pending_restyles.borrow_mut();
4430 RefMut::map(map, |m| {
4431 &mut m
4432 .entry(Dom::from_ref(el))
4433 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4434 .0
4435 })
4436 }
4437
4438 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4439 let mut entry = self.ensure_pending_restyle(el);
4445 if entry.snapshot.is_none() {
4446 entry.snapshot = Some(Snapshot::new());
4447 }
4448 if attr.local_name() == &local_name!("style") {
4449 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4450 }
4451
4452 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4453 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4454 }
4455
4456 let snapshot = entry.snapshot.as_mut().unwrap();
4457 if attr.local_name() == &local_name!("id") {
4458 if snapshot.id_changed {
4459 return;
4460 }
4461 snapshot.id_changed = true;
4462 } else if attr.local_name() == &local_name!("class") {
4463 if snapshot.class_changed {
4464 return;
4465 }
4466 snapshot.class_changed = true;
4467 } else {
4468 snapshot.other_attributes_changed = true;
4469 }
4470 let local_name = style::LocalName::cast(attr.local_name());
4471 if !snapshot.changed_attrs.contains(local_name) {
4472 snapshot.changed_attrs.push(local_name.clone());
4473 }
4474 if snapshot.attrs.is_none() {
4475 let attrs = el
4476 .attrs()
4477 .iter()
4478 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4479 .collect();
4480 snapshot.attrs = Some(attrs);
4481 }
4482 }
4483
4484 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4485 self.policy_container
4486 .borrow_mut()
4487 .set_referrer_policy(policy);
4488 }
4489
4490 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4491 self.policy_container.borrow().get_referrer_policy()
4492 }
4493
4494 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4495 if let Some(ref element) = self.target_element.get() {
4496 element.set_target_state(false);
4497 }
4498
4499 self.target_element.set(node);
4500
4501 if let Some(ref element) = self.target_element.get() {
4502 element.set_target_state(true);
4503 }
4504 }
4505
4506 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4507 self.ignore_destructive_writes_counter
4508 .set(self.ignore_destructive_writes_counter.get() + 1);
4509 }
4510
4511 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4512 self.ignore_destructive_writes_counter
4513 .set(self.ignore_destructive_writes_counter.get() - 1);
4514 }
4515
4516 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4517 self.ignore_opens_during_unload_counter.get() > 0
4518 }
4519
4520 fn incr_ignore_opens_during_unload_counter(&self) {
4521 self.ignore_opens_during_unload_counter
4522 .set(self.ignore_opens_during_unload_counter.get() + 1);
4523 }
4524
4525 fn decr_ignore_opens_during_unload_counter(&self) {
4526 self.ignore_opens_during_unload_counter
4527 .set(self.ignore_opens_during_unload_counter.get() - 1);
4528 }
4529
4530 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4532 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4539 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4540
4541 if !self.is_fully_active() {
4544 promise.reject_error(
4545 Error::Type(c"Document is not fully active".to_owned()),
4546 can_gc,
4547 );
4548 return promise;
4549 }
4550
4551 let mut error = false;
4554
4555 {
4558 match *pending.namespace() {
4560 ns!(mathml) => {
4561 if pending.local_name().as_ref() != "math" {
4562 error = true;
4563 }
4564 },
4565 ns!(svg) => {
4566 if pending.local_name().as_ref() != "svg" {
4567 error = true;
4568 }
4569 },
4570 ns!(html) => (),
4571 _ => error = true,
4572 }
4573
4574 if pending.is::<HTMLDialogElement>() {
4576 error = true;
4577 }
4578
4579 if !pending.fullscreen_element_ready_check() {
4581 error = true;
4582 }
4583
4584 if !pending.owner_window().has_transient_activation() {
4592 error = true;
4593 }
4594 }
4595
4596 if pref!(dom_fullscreen_test) {
4597 info!("Tests don't really enter fullscreen.");
4600 } else {
4601 warn!("Fullscreen not supported yet");
4604 }
4605
4606 if !error {
4609 pending.owner_window().consume_user_activation();
4610 }
4611
4612 if !error {
4618 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4619 self.send_to_embedder(event);
4620 }
4621
4622 let pipeline_id = self.window().pipeline_id();
4625
4626 let trusted_pending = Trusted::new(pending);
4627 let trusted_pending_doc = Trusted::new(self);
4628 let trusted_promise = TrustedPromise::new(promise.clone());
4629 let handler = ElementPerformFullscreenEnter::new(
4630 trusted_pending,
4631 trusted_pending_doc,
4632 trusted_promise,
4633 error,
4634 );
4635 let script_msg = CommonScriptMsg::Task(
4636 ScriptThreadEventCategory::EnterFullscreen,
4637 handler,
4638 Some(pipeline_id),
4639 TaskSourceName::DOMManipulation,
4640 );
4641 let msg = MainThreadScriptMsg::Common(script_msg);
4642 self.window().main_thread_script_chan().send(msg).unwrap();
4643
4644 promise
4645 }
4646
4647 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4649 let global = self.global();
4650
4651 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4654 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4655
4656 if !self.is_fully_active() || self.fullscreen_element.get().is_none() {
4659 promise.reject_error(
4660 Error::Type(
4661 c"No fullscreen element to exit or document is not fully active".to_owned(),
4662 ),
4663 can_gc,
4664 );
4665 return promise;
4666 }
4667
4668 let element = self.fullscreen_element.get().unwrap();
4671 let window = self.window();
4672
4673 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4677 self.send_to_embedder(event);
4678
4679 let trusted_element = Trusted::new(&*element);
4682 let trusted_promise = TrustedPromise::new(promise.clone());
4683 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4684 let pipeline_id = Some(global.pipeline_id());
4685 let script_msg = CommonScriptMsg::Task(
4686 ScriptThreadEventCategory::ExitFullscreen,
4687 handler,
4688 pipeline_id,
4689 TaskSourceName::DOMManipulation,
4690 );
4691 let msg = MainThreadScriptMsg::Common(script_msg);
4692 window.main_thread_script_chan().send(msg).unwrap();
4693
4694 promise
4695 }
4696
4697 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4698 self.fullscreen_element.set(element);
4699 }
4700
4701 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4702 match self.browsing_context() {
4704 None => false,
4706 Some(_) => {
4707 let window = self.window();
4709 if window.is_top_level() {
4710 true
4711 } else {
4712 window
4714 .GetFrameElement()
4715 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4716 }
4717 },
4718 }
4719 }
4720
4721 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4722 let map = self.form_id_listener_map.borrow();
4723 if let Some(listeners) = map.get(id) {
4724 for listener in listeners {
4725 listener
4726 .as_maybe_form_control()
4727 .expect("Element must be a form control")
4728 .reset_form_owner(can_gc);
4729 }
4730 }
4731 }
4732
4733 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4734 self.shadow_roots
4735 .borrow_mut()
4736 .insert(Dom::from_ref(shadow_root));
4737 self.invalidate_shadow_roots_stylesheets();
4738 }
4739
4740 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4741 let mut shadow_roots = self.shadow_roots.borrow_mut();
4742 shadow_roots.remove(&Dom::from_ref(shadow_root));
4743 }
4744
4745 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4746 self.shadow_roots_styles_changed.set(true);
4747 }
4748
4749 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4750 self.shadow_roots_styles_changed.get()
4751 }
4752
4753 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4754 if !self.shadow_roots_styles_changed.get() {
4755 return;
4756 }
4757 self.shadow_roots_styles_changed.set(false);
4758 }
4759
4760 pub(crate) fn stylesheet_count(&self) -> usize {
4761 self.stylesheets.borrow().len()
4762 }
4763
4764 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4765 let stylesheets = self.stylesheets.borrow();
4766
4767 stylesheets
4768 .get(Origin::Author, index)
4769 .and_then(|s| s.owner.get_cssom_object())
4770 }
4771
4772 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4779 let stylesheets = &mut *self.stylesheets.borrow_mut();
4780
4781 let insertion_point = stylesheets
4783 .iter()
4784 .map(|(sheet, _origin)| sheet)
4785 .find(|sheet_in_doc| {
4786 match &sheet_in_doc.owner {
4787 StylesheetSource::Element(other_node) => {
4788 owner_node.upcast::<Node>().is_before(other_node.upcast())
4789 },
4790 StylesheetSource::Constructed(_) => true,
4793 }
4794 })
4795 .cloned();
4796
4797 if self.has_browsing_context() {
4798 let document_context = self.window.web_font_context();
4799
4800 self.window.layout_mut().add_stylesheet(
4801 sheet.clone(),
4802 insertion_point.as_ref().map(|s| s.sheet.clone()),
4803 &document_context,
4804 );
4805 }
4806
4807 DocumentOrShadowRoot::add_stylesheet(
4808 StylesheetSource::Element(Dom::from_ref(owner_node)),
4809 StylesheetSetRef::Document(stylesheets),
4810 sheet,
4811 insertion_point,
4812 self.style_shared_lock(),
4813 );
4814 }
4815
4816 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4821 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4822 debug_assert!(cssom_stylesheet.is_constructed());
4823
4824 let stylesheets = &mut *self.stylesheets.borrow_mut();
4825 let sheet = cssom_stylesheet.style_stylesheet().clone();
4826
4827 let insertion_point = stylesheets
4828 .iter()
4829 .last()
4830 .map(|(sheet, _origin)| sheet)
4831 .cloned();
4832
4833 if self.has_browsing_context() {
4834 self.window.layout_mut().add_stylesheet(
4835 sheet.clone(),
4836 insertion_point.as_ref().map(|s| s.sheet.clone()),
4837 &self.window.web_font_context(),
4838 );
4839 }
4840
4841 DocumentOrShadowRoot::add_stylesheet(
4842 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4843 StylesheetSetRef::Document(stylesheets),
4844 sheet,
4845 insertion_point,
4846 self.style_shared_lock(),
4847 );
4848 }
4849
4850 pub(crate) fn load_web_fonts_from_stylesheet(
4852 &self,
4853 stylesheet: &Arc<Stylesheet>,
4854 document_context: &WebFontDocumentContext,
4855 ) {
4856 self.window
4857 .layout()
4858 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4859 }
4860
4861 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4864 if self.has_browsing_context() {
4865 self.window
4866 .layout_mut()
4867 .remove_stylesheet(stylesheet.clone());
4868 }
4869
4870 DocumentOrShadowRoot::remove_stylesheet(
4871 owner,
4872 stylesheet,
4873 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4874 )
4875 }
4876
4877 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4878 Ref::map(self.id_map.borrow(), |map| {
4879 map.get(id).map(|vec| &**vec).unwrap_or_default()
4880 })
4881 }
4882
4883 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4884 Ref::map(self.name_map.borrow(), |map| {
4885 map.get(name).map(|vec| &**vec).unwrap_or_default()
4886 })
4887 }
4888
4889 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4890 self.pending_restyles
4891 .borrow_mut()
4892 .drain()
4893 .filter_map(|(elem, restyle)| {
4894 let node = elem.upcast::<Node>();
4895 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4896 return None;
4897 }
4898 node.note_dirty_descendants();
4899 Some((node.to_trusted_node_address(), restyle.0))
4900 })
4901 .collect()
4902 }
4903
4904 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: TimeDuration) {
4905 self.timeline.advance_specific(delta);
4906 let current_timeline_value = self.current_animation_timeline_value();
4907 self.animations
4908 .update_for_new_timeline_value(&self.window, current_timeline_value);
4909 }
4910
4911 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4912 let current_timeline_value = self.current_animation_timeline_value();
4913 self.animations
4914 .mark_animating_nodes_as_dirty(current_timeline_value);
4915 }
4916
4917 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4918 self.timeline
4919 .upcast::<AnimationTimeline>()
4920 .current_time_in_seconds()
4921 }
4922
4923 pub(crate) fn animations(&self) -> &Animations {
4924 &self.animations
4925 }
4926
4927 pub(crate) fn update_animations_post_reflow(&self) {
4928 self.animations
4929 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4930 self.image_animation_manager
4931 .borrow()
4932 .maybe_schedule_update_after_layout(
4933 &self.window,
4934 self.current_animation_timeline_value(),
4935 );
4936 }
4937
4938 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4939 self.animations.cancel_animations_for_node(node);
4940 self.image_animation_manager
4941 .borrow()
4942 .cancel_animations_for_node(node);
4943 }
4944
4945 pub(crate) fn update_animations_and_send_events(&self, cx: &mut js::context::JSContext) {
4947 if !self.layout_animations_test_enabled {
4949 self.timeline.update(self.window());
4950 }
4951
4952 let current_timeline_value = self.current_animation_timeline_value();
4959 self.animations
4960 .update_for_new_timeline_value(&self.window, current_timeline_value);
4961 self.maybe_mark_animating_nodes_as_dirty();
4962
4963 self.window().perform_a_microtask_checkpoint(cx);
4965
4966 let _realm = enter_realm(self);
4968 self.animations()
4969 .send_pending_events(self.window(), CanGc::from_cx(cx));
4970 }
4971
4972 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4973 self.image_animation_manager.borrow()
4974 }
4975
4976 pub(crate) fn set_has_pending_animated_image_update(&self) {
4977 self.has_pending_animated_image_update.set(true);
4978 }
4979
4980 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4982 if self.will_declaratively_refresh() {
4984 return;
4985 }
4986
4987 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4989 Regex::new(
4993 r#"(?xs)
4994 ^
4995 \s* # 3
4996 ((?<time>[0-9]+)|\.) # 5-6
4997 [0-9.]* # 8
4998 (
4999 (
5000 (\s*;|\s*,|\s) # 10.3
5001 \s* # 10.4
5002 )
5003 (
5004 (
5005 (U|u)(R|r)(L|l) # 11.2-11.4
5006 \s*=\s* # 11.5-11.7
5007 )?
5008 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
5009 |
5010 (?<url4>(?s-u:.)*)
5011 )
5012 )?
5013 $
5014 "#,
5015 )
5016 .unwrap()
5017 });
5018
5019 let mut url_record = self.url();
5021 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
5022 captures
5023 } else {
5024 return;
5025 };
5026 let time = if let Some(time_string) = captures.name("time") {
5027 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
5028 } else {
5029 0
5030 };
5031 let captured_url = captures.name("url1").or(captures
5032 .name("url2")
5033 .or(captures.name("url3").or(captures.name("url4"))));
5034
5035 if let Some(url_match) = captured_url {
5037 url_record = if let Ok(url) = ServoUrl::parse_with_base(
5038 Some(&url_record),
5039 &String::from_utf8_lossy(url_match.as_bytes()),
5040 ) {
5041 info!("Refresh to {}", url.debug_compact());
5042 url
5043 } else {
5044 return;
5046 }
5047 }
5048 if self.completely_loaded() {
5050 self.window.as_global_scope().schedule_callback(
5052 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
5053 window: DomRoot::from_ref(self.window()),
5054 url: url_record,
5055 }),
5056 Duration::from_secs(time),
5057 );
5058 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
5059 } else {
5060 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
5061 url: url_record,
5062 time,
5063 });
5064 }
5065 }
5066
5067 pub(crate) fn will_declaratively_refresh(&self) -> bool {
5068 self.declarative_refresh.borrow().is_some()
5069 }
5070 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
5071 *self.declarative_refresh.borrow_mut() = Some(refresh);
5072 }
5073
5074 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
5076 if self.visibility_state.get() == visibility_state {
5078 return;
5079 }
5080 self.visibility_state.set(visibility_state);
5082 let entry = VisibilityStateEntry::new(
5085 &self.global(),
5086 visibility_state,
5087 CrossProcessInstant::now(),
5088 can_gc,
5089 );
5090 self.window
5091 .Performance()
5092 .queue_entry(entry.upcast::<PerformanceEntry>());
5093
5094 #[cfg(feature = "gamepad")]
5105 if visibility_state == DocumentVisibilityState::Hidden {
5106 self.window
5107 .Navigator()
5108 .GetGamepads()
5109 .iter_mut()
5110 .for_each(|gamepad| {
5111 if let Some(g) = gamepad {
5112 g.vibration_actuator().handle_visibility_change();
5113 }
5114 });
5115 }
5116
5117 self.upcast::<EventTarget>()
5119 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
5120 }
5121
5122 pub(crate) fn is_initial_about_blank(&self) -> bool {
5124 self.is_initial_about_blank.get()
5125 }
5126
5127 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
5129 self.allow_declarative_shadow_roots.get()
5130 }
5131
5132 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
5133 self.has_trustworthy_ancestor_origin.get()
5134 }
5135
5136 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
5137 self.has_trustworthy_ancestor_origin.get() ||
5138 self.origin().immutable().is_potentially_trustworthy()
5139 }
5140
5141 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
5142 self.highlighted_dom_node.set(node);
5143 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
5144 }
5145
5146 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
5147 self.highlighted_dom_node.get()
5148 }
5149
5150 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
5151 self.custom_element_reaction_stack.clone()
5152 }
5153
5154 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
5155 self.active_sandboxing_flag_set.get().contains(flag)
5156 }
5157
5158 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
5159 self.active_sandboxing_flag_set.set(flags)
5160 }
5161
5162 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
5163 self.creation_sandboxing_flag_set.get()
5164 }
5165
5166 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
5167 &self,
5168 ) -> SandboxingFlagSet {
5169 self.window()
5170 .window_proxy()
5171 .frame_element()
5172 .and_then(|element| element.downcast::<HTMLIFrameElement>())
5173 .map(HTMLIFrameElement::sandboxing_flag_set)
5174 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
5175 }
5176
5177 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
5178 self.window()
5179 .scrolling_box_query(None, flags)
5180 .expect("We should always have a ScrollingBox for the Viewport")
5181 }
5182
5183 pub(crate) fn notify_embedder_favicon(&self) {
5184 if let Some(ref image) = *self.favicon.borrow() {
5185 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
5186 }
5187 }
5188
5189 pub(crate) fn set_favicon(&self, favicon: Image) {
5190 *self.favicon.borrow_mut() = Some(favicon);
5191 self.notify_embedder_favicon();
5192 }
5193
5194 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
5195 self.fullscreen_element.get()
5196 }
5197
5198 pub(crate) fn state_override(&self, command_name: &CommandName) -> Option<bool> {
5200 self.state_override.borrow().get(command_name).copied()
5201 }
5202
5203 pub(crate) fn set_state_override(&self, command_name: CommandName, state: bool) {
5205 self.state_override.borrow_mut().insert(command_name, state);
5206 }
5207
5208 pub(crate) fn value_override(&self, command_name: &CommandName) -> Option<DOMString> {
5210 self.value_override.borrow().get(command_name).cloned()
5211 }
5212
5213 pub(crate) fn set_value_override(&self, command_name: CommandName, value: Option<DOMString>) {
5215 if let Some(value) = value {
5216 self.value_override.borrow_mut().insert(command_name, value);
5217 } else {
5218 self.value_override.borrow_mut().remove(&command_name);
5219 }
5220 }
5221
5222 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
5224 self.default_single_line_container_name.get()
5225 }
5226
5227 pub(crate) fn set_default_single_line_container_name(
5229 &self,
5230 value: DefaultSingleLineContainerName,
5231 ) {
5232 self.default_single_line_container_name.set(value)
5233 }
5234
5235 pub(crate) fn css_styling_flag(&self) -> bool {
5237 self.css_styling_flag.get()
5238 }
5239
5240 pub(crate) fn set_css_styling_flag(&self, value: bool) {
5242 self.css_styling_flag.set(value)
5243 }
5244}
5245
5246impl DocumentMethods<crate::DomTypeHolder> for Document {
5247 fn Constructor(
5249 window: &Window,
5250 proto: Option<HandleObject>,
5251 can_gc: CanGc,
5252 ) -> Fallible<DomRoot<Document>> {
5253 let doc = window.Document();
5255 let docloader = DocumentLoader::new(&doc.loader());
5256 Ok(Document::new_with_proto(
5257 window,
5258 proto,
5259 HasBrowsingContext::No,
5260 None,
5261 None,
5262 doc.origin().clone(),
5263 IsHTMLDocument::NonHTMLDocument,
5264 None,
5265 None,
5266 DocumentActivity::Inactive,
5267 DocumentSource::NotFromParser,
5268 docloader,
5269 None,
5270 None,
5271 Default::default(),
5272 false,
5273 doc.allow_declarative_shadow_roots(),
5274 Some(doc.insecure_requests_policy()),
5275 doc.has_trustworthy_ancestor_or_current_origin(),
5276 doc.custom_element_reaction_stack(),
5277 doc.active_sandboxing_flag_set.get(),
5278 can_gc,
5279 ))
5280 }
5281
5282 fn ParseHTMLUnsafe(
5284 cx: &mut js::context::JSContext,
5285 window: &Window,
5286 s: TrustedHTMLOrString,
5287 ) -> Fallible<DomRoot<Self>> {
5288 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
5292 cx,
5293 window.as_global_scope(),
5294 s,
5295 "Document parseHTMLUnsafe",
5296 )?;
5297
5298 let url = window.get_url();
5299 let doc = window.Document();
5300 let loader = DocumentLoader::new(&doc.loader());
5301
5302 let content_type = "text/html"
5303 .parse()
5304 .expect("Supported type is not a MIME type");
5305 let document = Document::new(
5308 window,
5309 HasBrowsingContext::No,
5310 Some(ServoUrl::parse("about:blank").unwrap()),
5311 None,
5312 doc.origin().clone(),
5313 IsHTMLDocument::HTMLDocument,
5314 Some(content_type),
5315 None,
5316 DocumentActivity::Inactive,
5317 DocumentSource::FromParser,
5318 loader,
5319 None,
5320 None,
5321 Default::default(),
5322 false,
5323 true,
5324 Some(doc.insecure_requests_policy()),
5325 doc.has_trustworthy_ancestor_or_current_origin(),
5326 doc.custom_element_reaction_stack(),
5327 doc.creation_sandboxing_flag_set(),
5328 CanGc::from_cx(cx),
5329 );
5330 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, cx);
5332 document.set_ready_state(DocumentReadyState::Complete, CanGc::from_cx(cx));
5334 Ok(document)
5335 }
5336
5337 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
5339 self.stylesheet_list.or_init(|| {
5340 StyleSheetList::new(
5341 &self.window,
5342 StyleSheetListOwner::Document(Dom::from_ref(self)),
5343 can_gc,
5344 )
5345 })
5346 }
5347
5348 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
5350 self.implementation
5351 .or_init(|| DOMImplementation::new(self, can_gc))
5352 }
5353
5354 fn URL(&self) -> USVString {
5356 USVString(String::from(self.url().as_str()))
5357 }
5358
5359 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5361 self.document_or_shadow_root.get_active_element(
5362 self.get_focused_element(),
5363 self.GetBody(),
5364 self.GetDocumentElement(),
5365 )
5366 }
5367
5368 fn HasFocus(&self) -> bool {
5370 if self.window().parent_info().is_none() {
5392 self.is_fully_active()
5394 } else {
5395 self.is_fully_active() && self.has_focus.get()
5397 }
5398 }
5399
5400 fn Domain(&self) -> DOMString {
5402 match self.origin().effective_domain() {
5404 None => DOMString::new(),
5406 Some(Host::Domain(domain)) => DOMString::from(domain),
5408 Some(host) => DOMString::from(host.to_string()),
5409 }
5410 }
5411
5412 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5414 if !self.has_browsing_context {
5416 return Err(Error::Security(None));
5417 }
5418
5419 if self.has_active_sandboxing_flag(
5422 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5423 ) {
5424 return Err(Error::Security(None));
5425 }
5426
5427 let effective_domain = match self.origin().effective_domain() {
5429 Some(effective_domain) => effective_domain,
5430 None => return Err(Error::Security(None)),
5432 };
5433
5434 let host =
5436 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5437 None => return Err(Error::Security(None)),
5438 Some(host) => host,
5439 };
5440
5441 self.origin().set_domain(host);
5446
5447 Ok(())
5448 }
5449
5450 fn Referrer(&self) -> DOMString {
5452 match self.referrer {
5453 Some(ref referrer) => DOMString::from(referrer.to_string()),
5454 None => DOMString::new(),
5455 }
5456 }
5457
5458 fn DocumentURI(&self) -> USVString {
5460 self.URL()
5461 }
5462
5463 fn CompatMode(&self) -> DOMString {
5465 DOMString::from(match self.quirks_mode.get() {
5466 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5467 QuirksMode::Quirks => "BackCompat",
5468 })
5469 }
5470
5471 fn CharacterSet(&self) -> DOMString {
5473 DOMString::from(self.encoding.get().name())
5474 }
5475
5476 fn Charset(&self) -> DOMString {
5478 self.CharacterSet()
5479 }
5480
5481 fn InputEncoding(&self) -> DOMString {
5483 self.CharacterSet()
5484 }
5485
5486 fn ContentType(&self) -> DOMString {
5488 DOMString::from(self.content_type.to_string())
5489 }
5490
5491 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5493 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5494 }
5495
5496 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5498 self.upcast::<Node>().child_elements().next()
5499 }
5500
5501 fn GetElementsByTagName(
5503 &self,
5504 qualified_name: DOMString,
5505 can_gc: CanGc,
5506 ) -> DomRoot<HTMLCollection> {
5507 let qualified_name = LocalName::from(qualified_name);
5508 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5509 return DomRoot::from_ref(entry);
5510 }
5511 let result = HTMLCollection::by_qualified_name(
5512 &self.window,
5513 self.upcast(),
5514 qualified_name.clone(),
5515 can_gc,
5516 );
5517 self.tag_map
5518 .borrow_mut()
5519 .insert(qualified_name, Dom::from_ref(&*result));
5520 result
5521 }
5522
5523 fn GetElementsByTagNameNS(
5525 &self,
5526 maybe_ns: Option<DOMString>,
5527 tag_name: DOMString,
5528 can_gc: CanGc,
5529 ) -> DomRoot<HTMLCollection> {
5530 let ns = namespace_from_domstring(maybe_ns);
5531 let local = LocalName::from(tag_name);
5532 let qname = QualName::new(None, ns, local);
5533 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5534 return DomRoot::from_ref(collection);
5535 }
5536 let result =
5537 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
5538 self.tagns_map
5539 .borrow_mut()
5540 .insert(qname, Dom::from_ref(&*result));
5541 result
5542 }
5543
5544 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5546 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5547 .map(Atom::from)
5548 .collect();
5549 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5550 return DomRoot::from_ref(collection);
5551 }
5552 let result = HTMLCollection::by_atomic_class_name(
5553 &self.window,
5554 self.upcast(),
5555 class_atoms.clone(),
5556 can_gc,
5557 );
5558 self.classes_map
5559 .borrow_mut()
5560 .insert(class_atoms, Dom::from_ref(&*result));
5561 result
5562 }
5563
5564 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5566 self.get_element_by_id(&Atom::from(id))
5567 }
5568
5569 fn CreateElement(
5571 &self,
5572 cx: &mut js::context::JSContext,
5573 mut local_name: DOMString,
5574 options: StringOrElementCreationOptions,
5575 ) -> Fallible<DomRoot<Element>> {
5576 if !is_valid_element_local_name(&local_name.str()) {
5579 debug!("Not a valid element name");
5580 return Err(Error::InvalidCharacter(None));
5581 }
5582
5583 if self.is_html_document {
5584 local_name.make_ascii_lowercase();
5585 }
5586
5587 let ns = if self.is_html_document || self.is_xhtml_document() {
5588 ns!(html)
5589 } else {
5590 ns!()
5591 };
5592
5593 let name = QualName::new(None, ns, LocalName::from(local_name));
5594 let is = match options {
5595 StringOrElementCreationOptions::String(_) => None,
5596 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5597 options.is.as_ref().map(LocalName::from)
5598 },
5599 };
5600 Ok(Element::create(
5601 cx,
5602 name,
5603 is,
5604 self,
5605 ElementCreator::ScriptCreated,
5606 CustomElementCreationMode::Synchronous,
5607 None,
5608 ))
5609 }
5610
5611 fn CreateElementNS(
5613 &self,
5614 cx: &mut js::context::JSContext,
5615 namespace: Option<DOMString>,
5616 qualified_name: DOMString,
5617 options: StringOrElementCreationOptions,
5618 ) -> Fallible<DomRoot<Element>> {
5619 let context = domname::Context::Element;
5622 let (namespace, prefix, local_name) =
5623 domname::validate_and_extract(namespace, &qualified_name, context)?;
5624
5625 let name = QualName::new(prefix, namespace, local_name);
5628 let is = match options {
5629 StringOrElementCreationOptions::String(_) => None,
5630 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5631 options.is.as_ref().map(LocalName::from)
5632 },
5633 };
5634
5635 Ok(Element::create(
5637 cx,
5638 name,
5639 is,
5640 self,
5641 ElementCreator::ScriptCreated,
5642 CustomElementCreationMode::Synchronous,
5643 None,
5644 ))
5645 }
5646
5647 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5649 if !is_valid_attribute_local_name(&local_name.str()) {
5652 debug!("Not a valid attribute name");
5653 return Err(Error::InvalidCharacter(None));
5654 }
5655 if self.is_html_document {
5656 local_name.make_ascii_lowercase();
5657 }
5658 let name = LocalName::from(local_name);
5659 let value = AttrValue::String("".to_owned());
5660
5661 Ok(Attr::new(
5662 self,
5663 name.clone(),
5664 value,
5665 name,
5666 ns!(),
5667 None,
5668 None,
5669 can_gc,
5670 ))
5671 }
5672
5673 fn CreateAttributeNS(
5675 &self,
5676 namespace: Option<DOMString>,
5677 qualified_name: DOMString,
5678 can_gc: CanGc,
5679 ) -> Fallible<DomRoot<Attr>> {
5680 let context = domname::Context::Attribute;
5683 let (namespace, prefix, local_name) =
5684 domname::validate_and_extract(namespace, &qualified_name, context)?;
5685 let value = AttrValue::String("".to_owned());
5686 let qualified_name = LocalName::from(qualified_name);
5687 Ok(Attr::new(
5688 self,
5689 local_name,
5690 value,
5691 qualified_name,
5692 namespace,
5693 prefix,
5694 None,
5695 can_gc,
5696 ))
5697 }
5698
5699 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5701 DocumentFragment::new(self, can_gc)
5702 }
5703
5704 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5706 Text::new(data, self, can_gc)
5707 }
5708
5709 fn CreateCDATASection(
5711 &self,
5712 data: DOMString,
5713 can_gc: CanGc,
5714 ) -> Fallible<DomRoot<CDATASection>> {
5715 if self.is_html_document {
5717 return Err(Error::NotSupported(None));
5718 }
5719
5720 if data.contains("]]>") {
5722 return Err(Error::InvalidCharacter(None));
5723 }
5724
5725 Ok(CDATASection::new(data, self, can_gc))
5727 }
5728
5729 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5731 Comment::new(data, self, None, can_gc)
5732 }
5733
5734 fn CreateProcessingInstruction(
5736 &self,
5737 target: DOMString,
5738 data: DOMString,
5739 can_gc: CanGc,
5740 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5741 if !matches_name_production(&target.str()) {
5743 return Err(Error::InvalidCharacter(None));
5744 }
5745
5746 if data.contains("?>") {
5748 return Err(Error::InvalidCharacter(None));
5749 }
5750
5751 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5753 }
5754
5755 fn ImportNode(
5757 &self,
5758 cx: &mut js::context::JSContext,
5759 node: &Node,
5760 options: BooleanOrImportNodeOptions,
5761 ) -> Fallible<DomRoot<Node>> {
5762 if node.is::<Document>() || node.is::<ShadowRoot>() {
5764 return Err(Error::NotSupported(None));
5765 }
5766 let (subtree, registry) = match options {
5768 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5771 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5773 let subtree = (!options.selfOnly).into();
5775 let registry = options.customElementRegistry;
5777 (subtree, registry)
5781 },
5782 };
5783 let registry = registry
5786 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5787
5788 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5791 }
5792
5793 fn AdoptNode(&self, cx: &mut js::context::JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5795 if node.is::<Document>() {
5797 return Err(Error::NotSupported(None));
5798 }
5799
5800 if node.is::<ShadowRoot>() {
5802 return Err(Error::HierarchyRequest(None));
5803 }
5804
5805 Node::adopt(cx, node, self);
5807
5808 Ok(DomRoot::from_ref(node))
5810 }
5811
5812 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5814 interface.make_ascii_lowercase();
5815 match &*interface.str() {
5816 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5817 &self.window,
5818 can_gc,
5819 ))),
5820 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5821 CompositionEvent::new_uninitialized(&self.window, can_gc),
5822 )),
5823 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5824 self.window.upcast(),
5825 can_gc,
5826 ))),
5827 "events" | "event" | "htmlevents" | "svgevents" => {
5830 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5831 },
5832 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5833 &self.window,
5834 can_gc,
5835 ))),
5836 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5837 &self.window,
5838 can_gc,
5839 ))),
5840 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5841 &self.window,
5842 can_gc,
5843 ))),
5844 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5845 self.window.upcast(),
5846 can_gc,
5847 ))),
5848 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5849 &self.window,
5850 can_gc,
5851 ))),
5852 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5853 &self.window,
5854 "".into(),
5855 can_gc,
5856 ))),
5857 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5858 &self.window,
5859 &TouchList::new(&self.window, &[], can_gc),
5860 &TouchList::new(&self.window, &[], can_gc),
5861 &TouchList::new(&self.window, &[], can_gc),
5862 can_gc,
5863 ))),
5864 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5865 &self.window,
5866 can_gc,
5867 ))),
5868 _ => Err(Error::NotSupported(None)),
5869 }
5870 }
5871
5872 fn LastModified(&self) -> DOMString {
5874 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5875 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5881 }))
5882 }
5883
5884 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5886 Range::new_with_doc(self, None, can_gc)
5887 }
5888
5889 fn CreateNodeIterator(
5891 &self,
5892 root: &Node,
5893 what_to_show: u32,
5894 filter: Option<Rc<NodeFilter>>,
5895 can_gc: CanGc,
5896 ) -> DomRoot<NodeIterator> {
5897 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5898 }
5899
5900 fn CreateTreeWalker(
5902 &self,
5903 root: &Node,
5904 what_to_show: u32,
5905 filter: Option<Rc<NodeFilter>>,
5906 ) -> DomRoot<TreeWalker> {
5907 TreeWalker::new(self, root, what_to_show, filter)
5908 }
5909
5910 fn Title(&self) -> DOMString {
5912 self.title().unwrap_or_else(|| DOMString::from(""))
5913 }
5914
5915 fn SetTitle(&self, cx: &mut js::context::JSContext, title: DOMString) {
5917 let root = match self.GetDocumentElement() {
5918 Some(root) => root,
5919 None => return,
5920 };
5921
5922 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5923 let elem = root.upcast::<Node>().child_elements().find(|node| {
5924 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5925 });
5926 match elem {
5927 Some(elem) => DomRoot::upcast::<Node>(elem),
5928 None => {
5929 let name = QualName::new(None, ns!(svg), local_name!("title"));
5930 let elem = Element::create(
5931 cx,
5932 name,
5933 None,
5934 self,
5935 ElementCreator::ScriptCreated,
5936 CustomElementCreationMode::Synchronous,
5937 None,
5938 );
5939 let parent = root.upcast::<Node>();
5940 let child = elem.upcast::<Node>();
5941 parent
5942 .InsertBefore(cx, child, parent.GetFirstChild().as_deref())
5943 .unwrap()
5944 },
5945 }
5946 } else if root.namespace() == &ns!(html) {
5947 let elem = root
5948 .upcast::<Node>()
5949 .traverse_preorder(ShadowIncluding::No)
5950 .find(|node| node.is::<HTMLTitleElement>());
5951 match elem {
5952 Some(elem) => elem,
5953 None => match self.GetHead() {
5954 Some(head) => {
5955 let name = QualName::new(None, ns!(html), local_name!("title"));
5956 let elem = Element::create(
5957 cx,
5958 name,
5959 None,
5960 self,
5961 ElementCreator::ScriptCreated,
5962 CustomElementCreationMode::Synchronous,
5963 None,
5964 );
5965 head.upcast::<Node>()
5966 .AppendChild(cx, elem.upcast())
5967 .unwrap()
5968 },
5969 None => return,
5970 },
5971 }
5972 } else {
5973 return;
5974 };
5975
5976 node.set_text_content_for_element(cx, Some(title));
5977 }
5978
5979 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5981 self.get_html_element()
5982 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5983 }
5984
5985 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5987 self.current_script.get()
5988 }
5989
5990 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5992 self.get_html_element().and_then(|root| {
5995 let node = root.upcast::<Node>();
5996 node.children()
5997 .find(|child| {
5998 matches!(
5999 child.type_id(),
6000 NodeTypeId::Element(ElementTypeId::HTMLElement(
6001 HTMLElementTypeId::HTMLBodyElement,
6002 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
6003 HTMLElementTypeId::HTMLFrameSetElement,
6004 ))
6005 )
6006 })
6007 .map(|node| DomRoot::downcast(node).unwrap())
6008 })
6009 }
6010
6011 fn SetBody(
6013 &self,
6014 cx: &mut js::context::JSContext,
6015 new_body: Option<&HTMLElement>,
6016 ) -> ErrorResult {
6017 let new_body = match new_body {
6019 Some(new_body) => new_body,
6020 None => return Err(Error::HierarchyRequest(None)),
6021 };
6022
6023 let node = new_body.upcast::<Node>();
6024 match node.type_id() {
6025 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
6026 NodeTypeId::Element(ElementTypeId::HTMLElement(
6027 HTMLElementTypeId::HTMLFrameSetElement,
6028 )) => {},
6029 _ => return Err(Error::HierarchyRequest(None)),
6030 }
6031
6032 let old_body = self.GetBody();
6034 if old_body.as_deref() == Some(new_body) {
6035 return Ok(());
6036 }
6037
6038 match (self.GetDocumentElement(), &old_body) {
6039 (Some(ref root), Some(child)) => {
6042 let root = root.upcast::<Node>();
6043 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
6044 .map(|_| ())
6045 },
6046
6047 (None, _) => Err(Error::HierarchyRequest(None)),
6049
6050 (Some(ref root), &None) => {
6053 let root = root.upcast::<Node>();
6054 root.AppendChild(cx, new_body.upcast()).map(|_| ())
6055 },
6056 }
6057 }
6058
6059 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
6061 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
6062 }
6063
6064 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6066 self.images.or_init(|| {
6067 HTMLCollection::new_with_filter_fn(
6068 &self.window,
6069 self.upcast(),
6070 |element, _| element.is::<HTMLImageElement>(),
6071 can_gc,
6072 )
6073 })
6074 }
6075
6076 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6078 self.embeds.or_init(|| {
6079 HTMLCollection::new_with_filter_fn(
6080 &self.window,
6081 self.upcast(),
6082 |element, _| element.is::<HTMLEmbedElement>(),
6083 can_gc,
6084 )
6085 })
6086 }
6087
6088 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6090 self.Embeds(can_gc)
6091 }
6092
6093 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6095 self.links.or_init(|| {
6096 HTMLCollection::new_with_filter_fn(
6097 &self.window,
6098 self.upcast(),
6099 |element, _| {
6100 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
6101 element.has_attribute(&local_name!("href"))
6102 },
6103 can_gc,
6104 )
6105 })
6106 }
6107
6108 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6110 self.forms.or_init(|| {
6111 HTMLCollection::new_with_filter_fn(
6112 &self.window,
6113 self.upcast(),
6114 |element, _| element.is::<HTMLFormElement>(),
6115 can_gc,
6116 )
6117 })
6118 }
6119
6120 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6122 self.scripts.or_init(|| {
6123 HTMLCollection::new_with_filter_fn(
6124 &self.window,
6125 self.upcast(),
6126 |element, _| element.is::<HTMLScriptElement>(),
6127 can_gc,
6128 )
6129 })
6130 }
6131
6132 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6134 self.anchors.or_init(|| {
6135 HTMLCollection::new_with_filter_fn(
6136 &self.window,
6137 self.upcast(),
6138 |element, _| {
6139 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
6140 },
6141 can_gc,
6142 )
6143 })
6144 }
6145
6146 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6148 self.applets
6149 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
6150 }
6151
6152 fn GetLocation(&self, cx: &mut js::context::JSContext) -> Option<DomRoot<Location>> {
6154 if self.is_fully_active() {
6155 Some(self.window.Location(cx))
6156 } else {
6157 None
6158 }
6159 }
6160
6161 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
6163 HTMLCollection::children(&self.window, self.upcast(), can_gc)
6164 }
6165
6166 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
6168 self.upcast::<Node>().child_elements().next()
6169 }
6170
6171 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
6173 self.upcast::<Node>()
6174 .rev_children()
6175 .find_map(DomRoot::downcast)
6176 }
6177
6178 fn ChildElementCount(&self) -> u32 {
6180 self.upcast::<Node>().child_elements().count() as u32
6181 }
6182
6183 fn Prepend(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
6185 self.upcast::<Node>().prepend(cx, nodes)
6186 }
6187
6188 fn Append(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
6190 self.upcast::<Node>().append(cx, nodes)
6191 }
6192
6193 fn ReplaceChildren(
6195 &self,
6196 cx: &mut js::context::JSContext,
6197 nodes: Vec<NodeOrString>,
6198 ) -> ErrorResult {
6199 self.upcast::<Node>().replace_children(cx, nodes)
6200 }
6201
6202 fn MoveBefore(
6204 &self,
6205 cx: &mut js::context::JSContext,
6206 node: &Node,
6207 child: Option<&Node>,
6208 ) -> ErrorResult {
6209 self.upcast::<Node>().move_before(cx, node, child)
6210 }
6211
6212 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
6214 self.upcast::<Node>().query_selector(selectors)
6215 }
6216
6217 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
6219 self.upcast::<Node>().query_selector_all(selectors)
6220 }
6221
6222 fn ReadyState(&self) -> DocumentReadyState {
6224 self.ready_state.get()
6225 }
6226
6227 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
6229 if self.has_browsing_context {
6230 Some(DomRoot::from_ref(&*self.window))
6231 } else {
6232 None
6233 }
6234 }
6235
6236 fn GetCookie(&self) -> Fallible<DOMString> {
6238 if self.is_cookie_averse() {
6239 return Ok(DOMString::new());
6240 }
6241
6242 if !self.origin().is_tuple() {
6243 return Err(Error::Security(None));
6244 }
6245
6246 let url = self.url();
6247 let (tx, rx) =
6248 profile_generic_channel::channel(self.global().time_profiler_chan().clone()).unwrap();
6249 let _ = self
6250 .window
6251 .as_global_scope()
6252 .resource_threads()
6253 .send(GetCookiesForUrl(url, tx, NonHTTP));
6254 let cookies = rx.recv().unwrap();
6255 Ok(cookies.map_or(DOMString::new(), DOMString::from))
6256 }
6257
6258 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
6260 if self.is_cookie_averse() {
6261 return Ok(());
6262 }
6263
6264 if !self.origin().is_tuple() {
6265 return Err(Error::Security(None));
6266 }
6267
6268 if !cookie.is_valid_for_cookie() {
6269 return Ok(());
6270 }
6271
6272 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6273 vec![cookie]
6274 } else {
6275 vec![]
6276 };
6277
6278 let _ = self
6279 .window
6280 .as_global_scope()
6281 .resource_threads()
6282 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6283 Ok(())
6284 }
6285
6286 fn BgColor(&self) -> DOMString {
6288 self.get_body_attribute(&local_name!("bgcolor"))
6289 }
6290
6291 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
6293 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
6294 }
6295
6296 fn FgColor(&self) -> DOMString {
6298 self.get_body_attribute(&local_name!("text"))
6299 }
6300
6301 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
6303 self.set_body_attribute(&local_name!("text"), value, can_gc)
6304 }
6305
6306 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
6308 if name.is_empty() {
6309 return None;
6310 }
6311 let name = Atom::from(name);
6312
6313 let elements_with_name = self.get_elements_with_name(&name);
6316 let name_iter = elements_with_name
6317 .iter()
6318 .filter(|elem| is_named_element_with_name_attribute(elem));
6319 let elements_with_id = self.get_elements_with_id(&name);
6320 let id_iter = elements_with_id
6321 .iter()
6322 .filter(|elem| is_named_element_with_id_attribute(elem));
6323 let mut elements = name_iter.chain(id_iter);
6324
6325 let first = elements.next()?;
6332 if elements.all(|other| first == other) {
6333 if let Some(nested_window_proxy) = first
6334 .downcast::<HTMLIFrameElement>()
6335 .and_then(|iframe| iframe.GetContentWindow())
6336 {
6337 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6338 }
6339
6340 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6342 }
6343
6344 #[derive(JSTraceable, MallocSizeOf)]
6347 struct DocumentNamedGetter {
6348 #[no_trace]
6349 name: Atom,
6350 }
6351 impl CollectionFilter for DocumentNamedGetter {
6352 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6353 let type_ = match elem.upcast::<Node>().type_id() {
6354 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6355 _ => return false,
6356 };
6357 match type_ {
6358 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6359 elem.get_name().as_ref() == Some(&self.name)
6360 },
6361 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6362 name == *self.name ||
6363 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6364 }),
6365 _ => false,
6369 }
6370 }
6371 }
6372 let collection = HTMLCollection::create(
6373 self.window(),
6374 self.upcast(),
6375 Box::new(DocumentNamedGetter { name }),
6376 can_gc,
6377 );
6378 Some(NamedPropertyValue::HTMLCollection(collection))
6379 }
6380
6381 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
6383 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
6384
6385 let name_map = self.name_map.borrow();
6386 for (name, elements) in &(name_map).0 {
6387 if name.is_empty() {
6388 continue;
6389 }
6390 let mut name_iter = elements
6391 .iter()
6392 .filter(|elem| is_named_element_with_name_attribute(elem));
6393 if let Some(first) = name_iter.next() {
6394 names_with_first_named_element_map.insert(name, first);
6395 }
6396 }
6397 let id_map = self.id_map.borrow();
6398 for (id, elements) in &(id_map).0 {
6399 if id.is_empty() {
6400 continue;
6401 }
6402 let mut id_iter = elements
6403 .iter()
6404 .filter(|elem| is_named_element_with_id_attribute(elem));
6405 if let Some(first) = id_iter.next() {
6406 match names_with_first_named_element_map.entry(id) {
6407 Vacant(entry) => drop(entry.insert(first)),
6408 Occupied(mut entry) => {
6409 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6410 *entry.get_mut() = first;
6411 }
6412 },
6413 }
6414 }
6415 }
6416
6417 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
6418 names_with_first_named_element_map
6419 .iter()
6420 .map(|(k, v)| (*k, *v))
6421 .collect();
6422 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6423 if a.1 == b.1 {
6424 a.0.cmp(b.0)
6427 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6428 Ordering::Less
6429 } else {
6430 Ordering::Greater
6431 }
6432 });
6433
6434 names_with_first_named_element_vec
6435 .iter()
6436 .map(|(k, _v)| DOMString::from(&***k))
6437 .collect()
6438 }
6439
6440 fn Clear(&self) {
6442 }
6444
6445 fn CaptureEvents(&self) {
6447 }
6449
6450 fn ReleaseEvents(&self) {
6452 }
6454
6455 global_event_handlers!();
6457
6458 event_handler!(
6460 readystatechange,
6461 GetOnreadystatechange,
6462 SetOnreadystatechange
6463 );
6464
6465 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6467 self.document_or_shadow_root.element_from_point(
6468 x,
6469 y,
6470 self.GetDocumentElement(),
6471 self.has_browsing_context,
6472 )
6473 }
6474
6475 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6477 self.document_or_shadow_root.elements_from_point(
6478 x,
6479 y,
6480 self.GetDocumentElement(),
6481 self.has_browsing_context,
6482 )
6483 }
6484
6485 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6487 if self.quirks_mode() == QuirksMode::Quirks {
6489 if let Some(ref body) = self.GetBody() {
6491 let e = body.upcast::<Element>();
6492 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6496 return Some(DomRoot::from_ref(e));
6497 }
6498 }
6499
6500 return None;
6502 }
6503
6504 self.GetDocumentElement()
6507 }
6508
6509 fn Open(
6511 &self,
6512 cx: &mut js::context::JSContext,
6513 _unused1: Option<DOMString>,
6514 _unused2: Option<DOMString>,
6515 ) -> Fallible<DomRoot<Document>> {
6516 if !self.is_html_document() {
6518 return Err(Error::InvalidState(None));
6519 }
6520
6521 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6523 return Err(Error::InvalidState(None));
6524 }
6525
6526 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6528
6529 if !self
6531 .origin()
6532 .same_origin(&entry_responsible_document.origin())
6533 {
6534 return Err(Error::Security(None));
6535 }
6536
6537 if self
6539 .get_current_parser()
6540 .is_some_and(|parser| parser.is_active())
6541 {
6542 return Ok(DomRoot::from_ref(self));
6543 }
6544
6545 if self.is_prompting_or_unloading() {
6547 return Ok(DomRoot::from_ref(self));
6548 }
6549
6550 if self.active_parser_was_aborted.get() {
6552 return Ok(DomRoot::from_ref(self));
6553 }
6554
6555 self.window().set_navigation_start();
6559
6560 if self.has_browsing_context() {
6563 self.abort(cx);
6566 }
6567
6568 for node in self
6570 .upcast::<Node>()
6571 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6572 {
6573 node.upcast::<EventTarget>().remove_all_listeners();
6574 }
6575
6576 if self.window.Document() == DomRoot::from_ref(self) {
6578 self.window.upcast::<EventTarget>().remove_all_listeners();
6579 }
6580
6581 Node::replace_all(cx, None, self.upcast::<Node>());
6583
6584 if self.is_fully_active() {
6591 let mut new_url = entry_responsible_document.url();
6593
6594 if entry_responsible_document != DomRoot::from_ref(self) {
6596 new_url.set_fragment(None);
6597 }
6598
6599 self.set_url(new_url);
6602 }
6603
6604 self.is_initial_about_blank.set(false);
6606
6607 self.set_quirks_mode(QuirksMode::NoQuirks);
6613
6614 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6620 *self.loader.borrow_mut() =
6621 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6622 ServoParser::parse_html_script_input(self, self.url());
6623
6624 self.ready_state.set(DocumentReadyState::Loading);
6630
6631 Ok(DomRoot::from_ref(self))
6633 }
6634
6635 fn Open_(
6637 &self,
6638 cx: &mut js::context::JSContext,
6639 url: USVString,
6640 target: DOMString,
6641 features: DOMString,
6642 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6643 self.browsing_context()
6644 .ok_or(Error::InvalidAccess(None))?
6645 .open(cx, url, target, features)
6646 }
6647
6648 fn Write(
6650 &self,
6651 cx: &mut js::context::JSContext,
6652 text: Vec<TrustedHTMLOrString>,
6653 ) -> ErrorResult {
6654 self.write(cx, text, false, "Document", "write")
6657 }
6658
6659 fn Writeln(
6661 &self,
6662 cx: &mut js::context::JSContext,
6663 text: Vec<TrustedHTMLOrString>,
6664 ) -> ErrorResult {
6665 self.write(cx, text, true, "Document", "writeln")
6668 }
6669
6670 fn Close(&self, cx: &mut js::context::JSContext) -> ErrorResult {
6672 if !self.is_html_document() {
6673 return Err(Error::InvalidState(None));
6675 }
6676
6677 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6680 return Err(Error::InvalidState(None));
6681 }
6682
6683 let parser = match self.get_current_parser() {
6685 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6686 _ => {
6687 return Ok(());
6688 },
6689 };
6690
6691 parser.close(cx);
6693
6694 Ok(())
6695 }
6696
6697 fn ExecCommand(
6699 &self,
6700 cx: &mut js::context::JSContext,
6701 command_id: DOMString,
6702 _show_ui: bool,
6703 value: TrustedHTMLOrString,
6704 ) -> Fallible<bool> {
6705 let value = if command_id == "insertHTML" {
6706 TrustedHTML::get_trusted_type_compliant_string(
6707 cx,
6708 self.window.as_global_scope(),
6709 value,
6710 "Document execCommand",
6711 )?
6712 } else {
6713 match value {
6714 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6715 TrustedHTMLOrString::String(value) => value,
6716 }
6717 };
6718
6719 Ok(self.exec_command_for_command_id(cx, command_id, value))
6720 }
6721
6722 fn QueryCommandEnabled(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6724 self.check_support_and_enabled(cx, &command_id).is_some()
6726 }
6727
6728 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6730 self.is_command_supported(command_id)
6734 }
6735
6736 fn QueryCommandIndeterm(&self, command_id: DOMString) -> bool {
6738 self.is_command_indeterminate(command_id)
6739 }
6740
6741 fn QueryCommandState(&self, command_id: DOMString) -> bool {
6743 self.command_state_for_command(command_id)
6744 }
6745
6746 fn QueryCommandValue(&self, command_id: DOMString) -> DOMString {
6748 self.command_value_for_command(command_id)
6749 }
6750
6751 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6753
6754 event_handler!(
6756 fullscreenchange,
6757 GetOnfullscreenchange,
6758 SetOnfullscreenchange
6759 );
6760
6761 fn FullscreenEnabled(&self) -> bool {
6763 self.get_allow_fullscreen()
6764 }
6765
6766 fn Fullscreen(&self) -> bool {
6768 self.fullscreen_element.get().is_some()
6769 }
6770
6771 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6773 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6774 }
6775
6776 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6778 self.exit_fullscreen(can_gc)
6779 }
6780
6781 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6785 match self.media_controls.borrow().get(&*id.str()) {
6786 Some(m) => Ok(DomRoot::from_ref(m)),
6787 None => Err(Error::InvalidAccess(None)),
6788 }
6789 }
6790
6791 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6793 if self.has_browsing_context {
6794 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6795 } else {
6796 None
6797 }
6798 }
6799
6800 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6802 self.fonts
6803 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6804 }
6805
6806 fn Hidden(&self) -> bool {
6808 self.visibility_state.get() == DocumentVisibilityState::Hidden
6809 }
6810
6811 fn VisibilityState(&self) -> DocumentVisibilityState {
6813 self.visibility_state.get()
6814 }
6815
6816 fn CreateExpression(
6817 &self,
6818 expression: DOMString,
6819 resolver: Option<Rc<XPathNSResolver>>,
6820 can_gc: CanGc,
6821 ) -> Fallible<DomRoot<crate::dom::types::XPathExpression>> {
6822 let parsed_expression =
6823 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6824 Ok(XPathExpression::new(
6825 &self.window,
6826 None,
6827 can_gc,
6828 parsed_expression,
6829 ))
6830 }
6831
6832 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6833 let global = self.global();
6834 let window = global.as_window();
6835 let evaluator = XPathEvaluator::new(window, None, can_gc);
6836 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6837 }
6838
6839 fn Evaluate(
6840 &self,
6841 expression: DOMString,
6842 context_node: &Node,
6843 resolver: Option<Rc<XPathNSResolver>>,
6844 result_type: u16,
6845 result: Option<&crate::dom::types::XPathResult>,
6846 can_gc: CanGc,
6847 ) -> Fallible<DomRoot<crate::dom::types::XPathResult>> {
6848 let parsed_expression =
6849 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6850 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6851 context_node,
6852 result_type,
6853 result,
6854 can_gc,
6855 )
6856 }
6857
6858 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6860 self.adopted_stylesheets_frozen_types.get_or_init(
6861 || {
6862 self.adopted_stylesheets
6863 .borrow()
6864 .clone()
6865 .iter()
6866 .map(|sheet| sheet.as_rooted())
6867 .collect()
6868 },
6869 context,
6870 retval,
6871 can_gc,
6872 );
6873 }
6874
6875 fn SetAdoptedStyleSheets(
6877 &self,
6878 context: JSContext,
6879 val: HandleValue,
6880 can_gc: CanGc,
6881 ) -> ErrorResult {
6882 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6883 context,
6884 self.adopted_stylesheets.borrow_mut().as_mut(),
6885 val,
6886 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6887 can_gc,
6888 );
6889
6890 if result.is_ok() {
6892 self.adopted_stylesheets_frozen_types.clear()
6893 }
6894
6895 result
6896 }
6897
6898 fn Timeline(&self) -> DomRoot<DocumentTimeline> {
6899 self.timeline.as_rooted()
6900 }
6901}
6902
6903fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6904 if marker.get().is_none() {
6905 marker.set(Some(CrossProcessInstant::now()))
6906 }
6907}
6908
6909#[derive(Clone, Copy, PartialEq)]
6911pub(crate) enum FocusType {
6912 Element, Parent, }
6915
6916#[derive(Clone, Copy, PartialEq)]
6918pub enum FocusInitiator {
6919 Keyboard,
6922 Click,
6925 Script,
6928 Remote,
6931}
6932
6933pub(crate) enum FocusEventType {
6935 Focus, Blur, }
6938
6939#[derive(JSTraceable, MallocSizeOf)]
6940pub(crate) enum AnimationFrameCallback {
6941 DevtoolsFramerateTick {
6942 actor_name: String,
6943 },
6944 FrameRequestCallback {
6945 #[conditional_malloc_size_of]
6946 callback: Rc<FrameRequestCallback>,
6947 },
6948}
6949
6950impl AnimationFrameCallback {
6951 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6952 match *self {
6953 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6954 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6955 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6956 devtools_sender.send(msg).unwrap();
6957 },
6958 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6959 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6962 },
6963 }
6964 }
6965}
6966
6967#[derive(Default, JSTraceable, MallocSizeOf)]
6968#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6969struct PendingInOrderScriptVec {
6970 scripts: DomRefCell<VecDeque<PendingScript>>,
6971}
6972
6973impl PendingInOrderScriptVec {
6974 fn is_empty(&self) -> bool {
6975 self.scripts.borrow().is_empty()
6976 }
6977
6978 fn push(&self, element: &HTMLScriptElement) {
6979 self.scripts
6980 .borrow_mut()
6981 .push_back(PendingScript::new(element));
6982 }
6983
6984 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6985 let mut scripts = self.scripts.borrow_mut();
6986 let entry = scripts
6987 .iter_mut()
6988 .find(|entry| &*entry.element == element)
6989 .unwrap();
6990 entry.loaded(result);
6991 }
6992
6993 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6994 let mut scripts = self.scripts.borrow_mut();
6995 let pair = scripts.front_mut()?.take_result()?;
6996 scripts.pop_front();
6997 Some(pair)
6998 }
6999
7000 fn clear(&self) {
7001 *self.scripts.borrow_mut() = Default::default();
7002 }
7003}
7004
7005#[derive(JSTraceable, MallocSizeOf)]
7006#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
7007struct PendingScript {
7008 element: Dom<HTMLScriptElement>,
7009 load: Option<ScriptResult>,
7011}
7012
7013impl PendingScript {
7014 fn new(element: &HTMLScriptElement) -> Self {
7015 Self {
7016 element: Dom::from_ref(element),
7017 load: None,
7018 }
7019 }
7020
7021 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
7022 Self {
7023 element: Dom::from_ref(element),
7024 load,
7025 }
7026 }
7027
7028 fn loaded(&mut self, result: ScriptResult) {
7029 assert!(self.load.is_none());
7030 self.load = Some(result);
7031 }
7032
7033 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
7034 self.load
7035 .take()
7036 .map(|result| (DomRoot::from_ref(&*self.element), result))
7037 }
7038}
7039
7040fn is_named_element_with_name_attribute(elem: &Element) -> bool {
7041 let type_ = match elem.upcast::<Node>().type_id() {
7042 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
7043 _ => return false,
7044 };
7045 match type_ {
7046 HTMLElementTypeId::HTMLFormElement |
7047 HTMLElementTypeId::HTMLIFrameElement |
7048 HTMLElementTypeId::HTMLImageElement => true,
7049 _ => false,
7053 }
7054}
7055
7056fn is_named_element_with_id_attribute(elem: &Element) -> bool {
7057 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
7061}
7062
7063impl DocumentHelpers for Document {
7064 fn ensure_safe_to_run_script_or_layout(&self) {
7065 Document::ensure_safe_to_run_script_or_layout(self)
7066 }
7067}
7068
7069pub(crate) struct SameoriginAncestorNavigablesIterator {
7073 document: DomRoot<Document>,
7074}
7075
7076impl SameoriginAncestorNavigablesIterator {
7077 pub(crate) fn new(document: DomRoot<Document>) -> Self {
7078 Self { document }
7079 }
7080}
7081
7082impl Iterator for SameoriginAncestorNavigablesIterator {
7083 type Item = DomRoot<Document>;
7084
7085 fn next(&mut self) -> Option<Self::Item> {
7086 let window_proxy = self.document.browsing_context()?;
7087 self.document = window_proxy.parent()?.document()?;
7088 Some(self.document.clone())
7089 }
7090}
7091
7092pub(crate) struct SameOriginDescendantNavigablesIterator {
7097 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
7098}
7099
7100impl SameOriginDescendantNavigablesIterator {
7101 pub(crate) fn new(document: DomRoot<Document>) -> Self {
7102 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
7103 Self {
7104 stack: vec![Box::new(iframes.into_iter())],
7105 }
7106 }
7107
7108 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
7109 let mut cur_iframe = self.stack.last_mut()?.next();
7110 while cur_iframe.is_none() {
7111 self.stack.pop();
7112 cur_iframe = self.stack.last_mut()?.next();
7113 }
7114 cur_iframe
7115 }
7116}
7117
7118impl Iterator for SameOriginDescendantNavigablesIterator {
7119 type Item = DomRoot<Document>;
7120
7121 fn next(&mut self) -> Option<Self::Item> {
7122 while let Some(iframe) = self.get_next_iframe() {
7123 let Some(pipeline_id) = iframe.pipeline_id() else {
7124 continue;
7125 };
7126
7127 if let Some(document) = ScriptThread::find_document(pipeline_id) {
7128 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
7129 document.iframes().iter().collect();
7130 self.stack.push(Box::new(child_iframes.into_iter()));
7131 return Some(document);
7132 } else {
7133 continue;
7134 };
7135 }
7136 None
7137 }
7138}