1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use base::cross_process_instant::CrossProcessInstant;
17use base::generic_channel::GenericSend;
18use base::id::WebViewId;
19use base::{Epoch, generic_channel};
20use bitflags::bitflags;
21use chrono::Local;
22use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
23use content_security_policy::sandboxing_directive::SandboxingFlagSet;
24use content_security_policy::{CspList, PolicyDisposition};
25use cookie::Cookie;
26use data_url::mime::Mime;
27use devtools_traits::ScriptToDevtoolsControlMsg;
28use dom_struct::dom_struct;
29use embedder_traits::{
30 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
31 Image, LoadStatus,
32};
33use encoding_rs::{Encoding, UTF_8};
34use fonts::WebFontDocumentContext;
35use html5ever::{LocalName, Namespace, QualName, local_name, ns};
36use hyper_serde::Serde;
37use js::rust::{HandleObject, HandleValue, MutableHandleValue};
38use layout_api::{
39 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
40 ScrollContainerQueryFlags, TrustedNodeAddress,
41};
42use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
43use net_traits::CookieSource::NonHTTP;
44use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
45use net_traits::ReferrerPolicy;
46use net_traits::policy_container::PolicyContainer;
47use net_traits::pub_domains::is_pub_domain;
48use net_traits::request::{
49 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
50};
51use net_traits::response::HttpsState;
52use percent_encoding::percent_decode;
53use profile_traits::ipc as profile_ipc;
54use profile_traits::time::TimerMetadataFrameType;
55use regex::bytes::Regex;
56use rustc_hash::{FxBuildHasher, FxHashMap};
57use script_bindings::interfaces::DocumentHelpers;
58use script_bindings::script_runtime::JSContext;
59use script_traits::{DocumentActivity, ProgressiveWebMetricType};
60use servo_arc::Arc;
61use servo_config::pref;
62use servo_media::{ClientContextId, ServoMedia};
63use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
64use style::attr::AttrValue;
65use style::context::QuirksMode;
66use style::invalidation::element::restyle_hints::RestyleHint;
67use style::selector_parser::Snapshot;
68use style::shared_lock::SharedRwLock as StyleSharedRwLock;
69use style::str::{split_html_space_chars, str_join};
70use style::stylesheet_set::DocumentStylesheetSet;
71use style::stylesheets::{Origin, OriginSet, Stylesheet};
72use stylo_atoms::Atom;
73use url::{Host, Position};
74
75use crate::animation_timeline::AnimationTimeline;
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::attr::Attr;
79use crate::dom::beforeunloadevent::BeforeUnloadEvent;
80use crate::dom::bindings::callback::ExceptionHandling;
81use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
82use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
83use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
84 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
85};
86use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
87use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
88use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
90#[cfg(any(feature = "webxr", feature = "gamepad"))]
91use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
92use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
93use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
94use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
95use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
96use crate::dom::bindings::codegen::Bindings::WindowBinding::{
97 FrameRequestCallback, ScrollBehavior, WindowMethods,
98};
99use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
100use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
101use crate::dom::bindings::codegen::UnionTypes::{
102 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
103};
104use crate::dom::bindings::domname::{
105 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
106};
107use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
108use crate::dom::bindings::frozenarray::CachedFrozenArray;
109use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
110use crate::dom::bindings::num::Finite;
111use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
112use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
113use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
114use crate::dom::bindings::str::{DOMString, USVString};
115use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
116use crate::dom::bindings::weakref::DOMTracker;
117use crate::dom::bindings::xmlname::matches_name_production;
118use crate::dom::cdatasection::CDATASection;
119use crate::dom::comment::Comment;
120use crate::dom::compositionevent::CompositionEvent;
121use crate::dom::css::cssstylesheet::CSSStyleSheet;
122use crate::dom::css::fontfaceset::FontFaceSet;
123use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
124use crate::dom::customelementregistry::{
125 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
126};
127use crate::dom::customevent::CustomEvent;
128use crate::dom::document_embedder_controls::DocumentEmbedderControls;
129use crate::dom::document_event_handler::DocumentEventHandler;
130use crate::dom::documentfragment::DocumentFragment;
131use crate::dom::documentorshadowroot::{
132 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
133};
134use crate::dom::documenttype::DocumentType;
135use crate::dom::domimplementation::DOMImplementation;
136use crate::dom::element::{
137 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
138 ElementPerformFullscreenExit,
139};
140use crate::dom::event::{Event, EventBubbles, EventCancelable};
141use crate::dom::eventtarget::EventTarget;
142use crate::dom::execcommand::contenteditable::ContentEditableRange;
143use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
144use crate::dom::focusevent::FocusEvent;
145use crate::dom::globalscope::GlobalScope;
146use crate::dom::hashchangeevent::HashChangeEvent;
147use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
148use crate::dom::html::htmlareaelement::HTMLAreaElement;
149use crate::dom::html::htmlbaseelement::HTMLBaseElement;
150use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
151use crate::dom::html::htmlelement::HTMLElement;
152use crate::dom::html::htmlembedelement::HTMLEmbedElement;
153use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
154use crate::dom::html::htmlheadelement::HTMLHeadElement;
155use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
156use crate::dom::html::htmliframeelement::HTMLIFrameElement;
157use crate::dom::html::htmlimageelement::HTMLImageElement;
158use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
159use crate::dom::html::htmltitleelement::HTMLTitleElement;
160use crate::dom::htmldetailselement::DetailsNameGroups;
161use crate::dom::intersectionobserver::IntersectionObserver;
162use crate::dom::keyboardevent::KeyboardEvent;
163use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
164use crate::dom::location::Location;
165use crate::dom::messageevent::MessageEvent;
166use crate::dom::mouseevent::MouseEvent;
167use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
168use crate::dom::nodeiterator::NodeIterator;
169use crate::dom::nodelist::NodeList;
170use crate::dom::pagetransitionevent::PageTransitionEvent;
171use crate::dom::performance::performanceentry::PerformanceEntry;
172use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
173use crate::dom::processinginstruction::ProcessingInstruction;
174use crate::dom::promise::Promise;
175use crate::dom::range::Range;
176use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
177use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
178use crate::dom::selection::Selection;
179use crate::dom::servoparser::ServoParser;
180use crate::dom::shadowroot::ShadowRoot;
181use crate::dom::storageevent::StorageEvent;
182use crate::dom::text::Text;
183use crate::dom::touchevent::TouchEvent as DomTouchEvent;
184use crate::dom::touchlist::TouchList;
185use crate::dom::treewalker::TreeWalker;
186use crate::dom::trustedhtml::TrustedHTML;
187use crate::dom::types::{HTMLCanvasElement, HTMLDialogElement, VisibilityStateEntry};
188use crate::dom::uievent::UIEvent;
189use crate::dom::virtualmethods::vtable_for;
190use crate::dom::websocket::WebSocket;
191use crate::dom::window::Window;
192use crate::dom::windowproxy::WindowProxy;
193use crate::dom::xpathevaluator::XPathEvaluator;
194use crate::dom::xpathexpression::XPathExpression;
195use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
196use crate::iframe_collection::IFrameCollection;
197use crate::image_animation::ImageAnimationManager;
198use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
199use crate::mime::{APPLICATION, CHARSET};
200use crate::network_listener::{FetchResponseListener, NetworkListener};
201use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
202use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
203use crate::script_thread::ScriptThread;
204use crate::stylesheet_set::StylesheetSetRef;
205use crate::task::NonSendTaskBox;
206use crate::task_source::TaskSourceName;
207use crate::timers::OneshotTimerCallback;
208use crate::xpath::parse_expression;
209
210#[derive(Clone, Copy, PartialEq)]
211pub(crate) enum FireMouseEventType {
212 Move,
213 Over,
214 Out,
215 Enter,
216 Leave,
217}
218
219impl FireMouseEventType {
220 pub(crate) fn as_str(&self) -> &str {
221 match *self {
222 FireMouseEventType::Move => "mousemove",
223 FireMouseEventType::Over => "mouseover",
224 FireMouseEventType::Out => "mouseout",
225 FireMouseEventType::Enter => "mouseenter",
226 FireMouseEventType::Leave => "mouseleave",
227 }
228 }
229}
230
231#[derive(JSTraceable, MallocSizeOf)]
232pub(crate) struct RefreshRedirectDue {
233 #[no_trace]
234 pub(crate) url: ServoUrl,
235 #[ignore_malloc_size_of = "non-owning"]
236 pub(crate) window: DomRoot<Window>,
237}
238impl RefreshRedirectDue {
239 pub(crate) fn invoke(self, can_gc: CanGc) {
241 let load_data = self
251 .window
252 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
253 self.window
254 .load_url(NavigationHistoryBehavior::Replace, false, load_data, can_gc);
255 }
256}
257
258#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
259pub(crate) enum IsHTMLDocument {
260 HTMLDocument,
261 NonHTMLDocument,
262}
263
264#[derive(JSTraceable, MallocSizeOf)]
265#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
266struct FocusTransaction {
267 element: Option<Dom<Element>>,
269 has_focus: bool,
271 focus_options: FocusOptions,
273}
274
275#[derive(JSTraceable, MallocSizeOf)]
277pub(crate) enum DeclarativeRefresh {
278 PendingLoad {
279 #[no_trace]
280 url: ServoUrl,
281 time: u64,
282 },
283 CreatedAfterLoad,
284}
285
286#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
289pub(crate) struct RenderingUpdateReason(u8);
290
291bitflags! {
292 impl RenderingUpdateReason: u8 {
293 const ResizeObserverStartedObservingTarget = 1 << 0;
296 const IntersectionObserverStartedObservingTarget = 1 << 1;
299 const FontReadyPromiseFulfilled = 1 << 2;
303 }
304}
305
306#[dom_struct]
308pub(crate) struct Document {
309 node: Node,
310 document_or_shadow_root: DocumentOrShadowRoot,
311 window: Dom<Window>,
312 implementation: MutNullableDom<DOMImplementation>,
313 #[ignore_malloc_size_of = "type from external crate"]
314 #[no_trace]
315 content_type: Mime,
316 last_modified: Option<String>,
317 #[no_trace]
318 encoding: Cell<&'static Encoding>,
319 has_browsing_context: bool,
320 is_html_document: bool,
321 #[no_trace]
322 activity: Cell<DocumentActivity>,
323 #[no_trace]
325 url: DomRefCell<ServoUrl>,
326 #[no_trace]
328 about_base_url: DomRefCell<Option<ServoUrl>>,
329 #[ignore_malloc_size_of = "defined in selectors"]
330 #[no_trace]
331 quirks_mode: Cell<QuirksMode>,
332 event_handler: DocumentEventHandler,
334 embedder_controls: DocumentEmbedderControls,
336 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
339 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
340 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
341 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
342 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
343 images: MutNullableDom<HTMLCollection>,
344 embeds: MutNullableDom<HTMLCollection>,
345 links: MutNullableDom<HTMLCollection>,
346 forms: MutNullableDom<HTMLCollection>,
347 scripts: MutNullableDom<HTMLCollection>,
348 anchors: MutNullableDom<HTMLCollection>,
349 applets: MutNullableDom<HTMLCollection>,
350 iframes: RefCell<IFrameCollection>,
352 #[no_trace]
355 style_shared_lock: StyleSharedRwLock,
356 #[custom_trace]
358 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
359 stylesheet_list: MutNullableDom<StyleSheetList>,
360 ready_state: Cell<DocumentReadyState>,
361 domcontentloaded_dispatched: Cell<bool>,
363 focus_transaction: DomRefCell<Option<FocusTransaction>>,
365 focused: MutNullableDom<Element>,
367 #[no_trace]
369 focus_sequence: Cell<FocusSequenceNumber>,
370 has_focus: Cell<bool>,
374 current_script: MutNullableDom<HTMLScriptElement>,
376 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
378 script_blocking_stylesheets_count: Cell<u32>,
380 render_blocking_element_count: Cell<u32>,
383 deferred_scripts: PendingInOrderScriptVec,
385 asap_in_order_scripts_list: PendingInOrderScriptVec,
387 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
389 animation_frame_ident: Cell<u32>,
392 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
395 running_animation_callbacks: Cell<bool>,
400 loader: DomRefCell<DocumentLoader>,
402 current_parser: MutNullableDom<ServoParser>,
404 base_element: MutNullableDom<HTMLBaseElement>,
406 target_base_element: MutNullableDom<HTMLBaseElement>,
408 appropriate_template_contents_owner_document: MutNullableDom<Document>,
411 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
414 #[no_trace]
418 needs_restyle: Cell<RestyleReason>,
419 #[no_trace]
422 dom_interactive: Cell<Option<CrossProcessInstant>>,
423 #[no_trace]
424 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
425 #[no_trace]
426 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
427 #[no_trace]
428 dom_complete: Cell<Option<CrossProcessInstant>>,
429 #[no_trace]
430 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
431 #[no_trace]
432 load_event_start: Cell<Option<CrossProcessInstant>>,
433 #[no_trace]
434 load_event_end: Cell<Option<CrossProcessInstant>>,
435 #[no_trace]
436 unload_event_start: Cell<Option<CrossProcessInstant>>,
437 #[no_trace]
438 unload_event_end: Cell<Option<CrossProcessInstant>>,
439 #[no_trace]
441 https_state: Cell<HttpsState>,
442 #[no_trace]
444 origin: MutableOrigin,
445 referrer: Option<String>,
447 target_element: MutNullableDom<Element>,
449 #[no_trace]
451 policy_container: DomRefCell<PolicyContainer>,
452 #[no_trace]
454 preloaded_resources: DomRefCell<PreloadedResources>,
455 ignore_destructive_writes_counter: Cell<u32>,
457 ignore_opens_during_unload_counter: Cell<u32>,
459 spurious_animation_frames: Cell<u8>,
463
464 dom_count: Cell<u32>,
470 fullscreen_element: MutNullableDom<Element>,
472 form_id_listener_map:
479 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
480 #[no_trace]
481 interactive_time: DomRefCell<ProgressiveWebMetrics>,
482 #[no_trace]
483 tti_window: DomRefCell<InteractiveWindow>,
484 canceller: FetchCanceller,
486 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
488 page_showing: Cell<bool>,
490 salvageable: Cell<bool>,
492 active_parser_was_aborted: Cell<bool>,
494 fired_unload: Cell<bool>,
496 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
498 redirect_count: Cell<u16>,
500 script_and_layout_blockers: Cell<u32>,
502 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
504 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
505 completely_loaded: Cell<bool>,
507 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
509 shadow_roots_styles_changed: Cell<bool>,
511 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
517 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
520 has_pending_animated_image_update: Cell<bool>,
522 selection: MutNullableDom<Selection>,
524 animation_timeline: DomRefCell<AnimationTimeline>,
527 animations: Animations,
529 image_animation_manager: DomRefCell<ImageAnimationManager>,
531 dirty_root: MutNullableDom<Element>,
533 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
535 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
544 fonts: MutNullableDom<FontFaceSet>,
547 visibility_state: Cell<DocumentVisibilityState>,
549 status_code: Option<u16>,
551 is_initial_about_blank: Cell<bool>,
553 allow_declarative_shadow_roots: Cell<bool>,
555 #[no_trace]
557 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
558 has_trustworthy_ancestor_origin: Cell<bool>,
560 intersection_observer_task_queued: Cell<bool>,
562 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
574 highlighted_dom_node: MutNullableDom<Node>,
576 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
579 #[ignore_malloc_size_of = "mozjs"]
581 adopted_stylesheets_frozen_types: CachedFrozenArray,
582 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
584 rendering_update_reasons: Cell<RenderingUpdateReason>,
586 waiting_on_canvas_image_updates: Cell<bool>,
590 #[no_trace]
598 current_rendering_epoch: Cell<Epoch>,
599 #[conditional_malloc_size_of]
601 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
602 #[no_trace]
603 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
605 #[no_trace]
606 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
613 #[no_trace]
615 favicon: RefCell<Option<Image>>,
616
617 websockets: DOMTracker<WebSocket>,
619
620 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
622
623 #[no_trace]
625 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
626
627 layout_animations_test_enabled: bool,
629
630 state_override: Cell<bool>,
632
633 value_override: DomRefCell<Option<DOMString>>,
635}
636
637impl Document {
638 fn unloading_cleanup_steps(&self) {
640 if self.close_outstanding_websockets() {
643 self.salvageable.set(false);
645 }
646
647 if !self.salvageable.get() {
652 let global_scope = self.window.as_global_scope();
653
654 global_scope.close_event_sources();
656
657 let msg = ScriptToConstellationMessage::DiscardDocument;
662 let _ = global_scope.script_to_constellation_chan().send(msg);
663 }
664 }
665
666 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
667 self.websockets.track(websocket);
668 }
669
670 fn close_outstanding_websockets(&self) -> bool {
671 let mut closed_any_websocket = false;
672 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
673 if websocket.make_disappear() {
674 closed_any_websocket = true;
675 }
676 });
677 closed_any_websocket
678 }
679
680 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
681 debug_assert!(*node.owner_doc() == *self);
682 if !node.is_connected() {
683 return;
684 }
685
686 let parent = match node.parent_in_flat_tree() {
687 Some(parent) => parent,
688 None => {
689 let document_element = match self.GetDocumentElement() {
692 Some(element) => element,
693 None => return,
694 };
695 if let Some(dirty_root) = self.dirty_root.get() {
696 for ancestor in dirty_root
699 .upcast::<Node>()
700 .inclusive_ancestors_in_flat_tree()
701 {
702 if ancestor.is::<Element>() {
703 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
704 }
705 }
706 }
707 self.dirty_root.set(Some(&document_element));
708 return;
709 },
710 };
711
712 if parent.is::<Element>() {
713 if !parent.is_styled() {
714 return;
715 }
716
717 if parent.is_display_none() {
718 return;
719 }
720 }
721
722 let element_parent: DomRoot<Element>;
723 let element = match node.downcast::<Element>() {
724 Some(element) => element,
725 None => {
726 match DomRoot::downcast::<Element>(parent) {
729 Some(parent) => {
730 element_parent = parent;
731 &element_parent
732 },
733 None => {
734 return;
738 },
739 }
740 },
741 };
742
743 let dirty_root = match self.dirty_root.get() {
744 Some(root) if root.is_connected() => root,
745 _ => {
746 element
747 .upcast::<Node>()
748 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
749 self.dirty_root.set(Some(element));
750 return;
751 },
752 };
753
754 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
755 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
756 return;
757 }
758
759 if ancestor.is::<Element>() {
760 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
761 }
762 }
763
764 let new_dirty_root = element
765 .upcast::<Node>()
766 .common_ancestor_in_flat_tree(dirty_root.upcast())
767 .expect("Couldn't find common ancestor");
768
769 let mut has_dirty_descendants = true;
770 for ancestor in dirty_root
771 .upcast::<Node>()
772 .inclusive_ancestors_in_flat_tree()
773 {
774 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
775 has_dirty_descendants &= *ancestor != *new_dirty_root;
776 }
777
778 self.dirty_root
779 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
780 }
781
782 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
783 self.dirty_root.take()
784 }
785
786 #[inline]
787 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
788 self.loader.borrow()
789 }
790
791 #[inline]
792 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
793 self.loader.borrow_mut()
794 }
795
796 #[inline]
797 pub(crate) fn has_browsing_context(&self) -> bool {
798 self.has_browsing_context
799 }
800
801 #[inline]
803 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
804 if self.has_browsing_context {
805 self.window.undiscarded_window_proxy()
806 } else {
807 None
808 }
809 }
810
811 pub(crate) fn webview_id(&self) -> WebViewId {
812 self.window.webview_id()
813 }
814
815 #[inline]
816 pub(crate) fn window(&self) -> &Window {
817 &self.window
818 }
819
820 #[inline]
821 pub(crate) fn is_html_document(&self) -> bool {
822 self.is_html_document
823 }
824
825 pub(crate) fn is_xhtml_document(&self) -> bool {
826 self.content_type.matches(APPLICATION, "xhtml+xml")
827 }
828
829 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
830 self.https_state.set(https_state);
831 }
832
833 pub(crate) fn is_fully_active(&self) -> bool {
834 self.activity.get() == DocumentActivity::FullyActive
835 }
836
837 pub(crate) fn is_active(&self) -> bool {
838 self.activity.get() != DocumentActivity::Inactive
839 }
840
841 #[inline]
842 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
843 self.current_rendering_epoch.get()
844 }
845
846 pub(crate) fn set_activity(&self, cx: &mut js::context::JSContext, activity: DocumentActivity) {
847 assert!(self.has_browsing_context);
849 if activity == self.activity.get() {
850 return;
851 }
852
853 self.activity.set(activity);
855 let media = ServoMedia::get();
856 let pipeline_id = self.window().pipeline_id();
857 let client_context_id =
858 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
859
860 if activity != DocumentActivity::FullyActive {
861 self.window().suspend(cx);
862 media.suspend(&client_context_id);
863 return;
864 }
865
866 self.title_changed();
867 self.notify_embedder_favicon();
868 self.dirty_all_nodes();
869 self.window().resume(CanGc::from_cx(cx));
870 media.resume(&client_context_id);
871
872 if self.ready_state.get() != DocumentReadyState::Complete {
873 return;
874 }
875
876 let document = Trusted::new(self);
880 self.owner_global()
881 .task_manager()
882 .dom_manipulation_task_source()
883 .queue(task!(fire_pageshow_event: move || {
884 let document = document.root();
885 let window = document.window();
886 if document.page_showing.get() {
888 return;
889 }
890 document.page_showing.set(true);
892 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
894 let event = PageTransitionEvent::new(
897 window,
898 atom!("pageshow"),
899 false, false, true, CanGc::note(),
903 );
904 let event = event.upcast::<Event>();
905 event.set_trusted(true);
906 window.dispatch_event_with_target_override(event, CanGc::note());
907 }))
908 }
909
910 pub(crate) fn origin(&self) -> &MutableOrigin {
911 &self.origin
912 }
913
914 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
915 *self.protocol_handler_automation_mode.borrow_mut() = mode;
916 }
917
918 pub(crate) fn url(&self) -> ServoUrl {
920 self.url.borrow().clone()
921 }
922
923 pub(crate) fn set_url(&self, url: ServoUrl) {
924 *self.url.borrow_mut() = url;
925 }
926
927 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
928 self.about_base_url.borrow().clone()
929 }
930
931 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
932 *self.about_base_url.borrow_mut() = about_base_url;
933 }
934
935 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
937 let document_url = self.url();
938 if document_url.as_str() == "about:srcdoc" {
940 return self
943 .about_base_url()
944 .expect("about:srcdoc page should always have an about base URL");
945 }
946
947 if document_url.matches_about_blank() {
950 if let Some(about_base_url) = self.about_base_url() {
951 return about_base_url;
952 }
953 }
954
955 document_url
957 }
958
959 pub(crate) fn base_url(&self) -> ServoUrl {
961 match self.base_element() {
962 None => self.fallback_base_url(),
964 Some(base) => base.frozen_base_url(),
966 }
967 }
968
969 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
970 self.needs_restyle.set(self.needs_restyle.get() | reason)
971 }
972
973 pub(crate) fn clear_restyle_reasons(&self) {
974 self.needs_restyle.set(RestyleReason::empty());
975 }
976
977 pub(crate) fn restyle_reason(&self) -> RestyleReason {
978 let mut condition = self.needs_restyle.get();
979 if self.stylesheets.borrow().has_changed() {
980 condition.insert(RestyleReason::StylesheetsChanged);
981 }
982
983 if let Some(root) = self.GetDocumentElement() {
987 if root.upcast::<Node>().has_dirty_descendants() {
988 condition.insert(RestyleReason::DOMChanged);
989 }
990 }
991
992 if !self.pending_restyles.borrow().is_empty() {
993 condition.insert(RestyleReason::PendingRestyles);
994 }
995
996 condition
997 }
998
999 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1001 self.base_element.get()
1002 }
1003
1004 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1006 self.target_base_element.get()
1007 }
1008
1009 pub(crate) fn refresh_base_element(&self) {
1011 if let Some(base_element) = self.base_element.get() {
1012 base_element.clear_frozen_base_url();
1013 }
1014 let new_base_element = self
1015 .upcast::<Node>()
1016 .traverse_preorder(ShadowIncluding::No)
1017 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1018 .find(|element| {
1019 element
1020 .upcast::<Element>()
1021 .has_attribute(&local_name!("href"))
1022 });
1023 if let Some(ref new_base_element) = new_base_element {
1024 new_base_element.set_frozen_base_url();
1025 }
1026 self.base_element.set(new_base_element.as_deref());
1027
1028 let new_target_base_element = self
1029 .upcast::<Node>()
1030 .traverse_preorder(ShadowIncluding::No)
1031 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1032 .next();
1033 self.target_base_element
1034 .set(new_target_base_element.as_deref());
1035 }
1036
1037 pub(crate) fn dom_count(&self) -> u32 {
1038 self.dom_count.get()
1039 }
1040
1041 pub(crate) fn increment_dom_count(&self) {
1045 self.dom_count.set(self.dom_count.get() + 1);
1046 }
1047
1048 pub(crate) fn decrement_dom_count(&self) {
1050 self.dom_count.set(self.dom_count.get() - 1);
1051 }
1052
1053 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1054 self.quirks_mode.get()
1055 }
1056
1057 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1058 let old_mode = self.quirks_mode.replace(new_mode);
1059
1060 if old_mode != new_mode {
1061 self.window.layout_mut().set_quirks_mode(new_mode);
1062 }
1063 }
1064
1065 pub(crate) fn encoding(&self) -> &'static Encoding {
1066 self.encoding.get()
1067 }
1068
1069 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1070 self.encoding.set(encoding);
1071 }
1072
1073 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1074 if node.is_connected() {
1075 node.note_dirty_descendants();
1076 }
1077
1078 node.dirty(NodeDamage::ContentOrHeritage);
1081 }
1082
1083 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1085 self.document_or_shadow_root
1086 .unregister_named_element(&self.id_map, to_unregister, &id);
1087 self.reset_form_owner_for_listeners(&id, can_gc);
1088 }
1089
1090 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1092 let root = self.GetDocumentElement().expect(
1093 "The element is in the document, so there must be a document \
1094 element.",
1095 );
1096 self.document_or_shadow_root.register_named_element(
1097 &self.id_map,
1098 element,
1099 &id,
1100 DomRoot::from_ref(root.upcast::<Node>()),
1101 );
1102 self.reset_form_owner_for_listeners(&id, can_gc);
1103 }
1104
1105 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1107 self.document_or_shadow_root
1108 .unregister_named_element(&self.name_map, to_unregister, &name);
1109 }
1110
1111 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1113 let root = self.GetDocumentElement().expect(
1114 "The element is in the document, so there must be a document \
1115 element.",
1116 );
1117 self.document_or_shadow_root.register_named_element(
1118 &self.name_map,
1119 element,
1120 &name,
1121 DomRoot::from_ref(root.upcast::<Node>()),
1122 );
1123 }
1124
1125 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1126 &self,
1127 id: DOMString,
1128 listener: &T,
1129 ) {
1130 let mut map = self.form_id_listener_map.borrow_mut();
1131 let listener = listener.to_element();
1132 let set = map.entry(Atom::from(id)).or_default();
1133 set.insert(Dom::from_ref(listener));
1134 }
1135
1136 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1137 &self,
1138 id: DOMString,
1139 listener: &T,
1140 ) {
1141 let mut map = self.form_id_listener_map.borrow_mut();
1142 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1143 entry
1144 .get_mut()
1145 .remove(&Dom::from_ref(listener.to_element()));
1146 if entry.get().is_empty() {
1147 entry.remove();
1148 }
1149 }
1150 }
1151
1152 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1154 self.get_element_by_id(&Atom::from(fragment))
1158 .or_else(|| self.get_anchor_by_name(fragment))
1162 }
1163
1164 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1167 if fragment.is_empty() {
1177 return Some(DomRoot::from_ref(self.upcast()));
1178 }
1179 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1181 {
1182 return Some(DomRoot::upcast(potential_indicated_element));
1184 }
1185 let fragment_bytes = percent_decode(fragment.as_bytes());
1187 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1189 return None;
1190 };
1191 if let Some(potential_indicated_element) =
1193 self.find_a_potential_indicated_element(&decoded_fragment)
1194 {
1195 return Some(DomRoot::upcast(potential_indicated_element));
1197 }
1198 if decoded_fragment.eq_ignore_ascii_case("top") {
1200 return Some(DomRoot::from_ref(self.upcast()));
1201 }
1202 None
1204 }
1205
1206 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str) {
1208 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1213 self.set_target_element(None);
1214 return;
1215 };
1216 if *indicated_part == *self.upcast() {
1218 self.set_target_element(None);
1220 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1225 return;
1227 }
1228 let Some(target) = indicated_part.downcast::<Element>() else {
1231 unreachable!("Indicated part should always be an element");
1233 };
1234 self.set_target_element(Some(target));
1236 target.scroll_into_view_with_options(
1240 ScrollBehavior::Auto,
1241 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1242 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1243 None,
1244 None,
1245 );
1246 }
1251
1252 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1253 let name = Atom::from(name);
1254 self.name_map.borrow().get(&name).and_then(|elements| {
1255 elements
1256 .iter()
1257 .find(|e| e.is::<HTMLAnchorElement>())
1258 .map(|e| DomRoot::from_ref(&**e))
1259 })
1260 }
1261
1262 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1264 match state {
1265 DocumentReadyState::Loading => {
1266 if self.window().is_top_level() {
1267 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1268 self.webview_id(),
1269 LoadStatus::Started,
1270 ));
1271 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1272 }
1273 },
1274 DocumentReadyState::Complete => {
1275 if self.window().is_top_level() {
1276 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1277 self.webview_id(),
1278 LoadStatus::Complete,
1279 ));
1280 }
1281 update_with_current_instant(&self.dom_complete);
1282 },
1283 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1284 };
1285
1286 self.ready_state.set(state);
1287
1288 self.upcast::<EventTarget>()
1289 .fire_event(atom!("readystatechange"), can_gc);
1290 }
1291
1292 pub(crate) fn scripting_enabled(&self) -> bool {
1295 self.has_browsing_context() &&
1298 !self.has_active_sandboxing_flag(
1302 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1303 )
1304 }
1305
1306 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1309 self.focused.get()
1310 }
1311
1312 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1317 self.focus_sequence.get()
1318 }
1319
1320 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1322 self.focus_sequence.set(FocusSequenceNumber(
1323 self.focus_sequence
1324 .get()
1325 .0
1326 .checked_add(1)
1327 .expect("too many focus messages have been sent"),
1328 ));
1329 self.focus_sequence.get()
1330 }
1331
1332 pub(crate) fn has_focus_transaction(&self) -> bool {
1333 self.focus_transaction.borrow().is_some()
1334 }
1335
1336 pub(crate) fn begin_focus_transaction(&self) {
1339 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1341 element: self.focused.get().as_deref().map(Dom::from_ref),
1342 has_focus: self.has_focus.get(),
1343 focus_options: FocusOptions {
1344 preventScroll: true,
1345 },
1346 });
1347 }
1348
1349 pub(crate) fn perform_focus_fixup_rule(&self, can_gc: CanGc) {
1356 if self
1357 .focused
1358 .get()
1359 .as_deref()
1360 .is_none_or(|focused| focused.is_focusable_area())
1361 {
1362 return;
1363 }
1364 self.request_focus(None, FocusInitiator::Script, can_gc);
1365 }
1366
1367 pub(crate) fn request_focus(
1370 &self,
1371 elem: Option<&Element>,
1372 focus_initiator: FocusInitiator,
1373 can_gc: CanGc,
1374 ) {
1375 self.request_focus_with_options(
1376 elem,
1377 focus_initiator,
1378 FocusOptions {
1379 preventScroll: true,
1380 },
1381 can_gc,
1382 );
1383 }
1384
1385 pub(crate) fn request_focus_with_options(
1391 &self,
1392 target: Option<&Element>,
1393 focus_initiator: FocusInitiator,
1394 focus_options: FocusOptions,
1395 can_gc: CanGc,
1396 ) {
1397 if target.is_some_and(|target| match focus_initiator {
1399 FocusInitiator::Keyboard => !target.is_sequentially_focusable(),
1400 FocusInitiator::Click => !target.is_click_focusable(),
1401 FocusInitiator::Script | FocusInitiator::Remote => !target.is_focusable_area(),
1402 }) {
1403 return;
1404 }
1405
1406 let implicit_transaction = self.focus_transaction.borrow().is_none();
1407
1408 if implicit_transaction {
1409 self.begin_focus_transaction();
1410 }
1411
1412 {
1413 let mut focus_transaction = self.focus_transaction.borrow_mut();
1414 let focus_transaction = focus_transaction.as_mut().unwrap();
1415 focus_transaction.element = target.map(Dom::from_ref);
1416 focus_transaction.has_focus = true;
1417 focus_transaction.focus_options = focus_options;
1418 }
1419
1420 if implicit_transaction {
1421 self.commit_focus_transaction(focus_initiator, can_gc);
1422 }
1423 }
1424
1425 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1429 if self.window().parent_info().is_none() {
1430 warn!("Top-level document cannot be unfocused");
1431 return;
1432 }
1433
1434 assert!(
1437 self.focus_transaction.borrow().is_none(),
1438 "there mustn't be an in-progress focus transaction at this point"
1439 );
1440
1441 self.begin_focus_transaction();
1443
1444 {
1446 let mut focus_transaction = self.focus_transaction.borrow_mut();
1447 focus_transaction.as_mut().unwrap().has_focus = false;
1448 }
1449
1450 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1452 }
1453
1454 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1457 let (mut new_focused, new_focus_state, prevent_scroll) = {
1458 let focus_transaction = self.focus_transaction.borrow();
1459 let focus_transaction = focus_transaction
1460 .as_ref()
1461 .expect("no focus transaction in progress");
1462 (
1463 focus_transaction
1464 .element
1465 .as_ref()
1466 .map(|e| DomRoot::from_ref(&**e)),
1467 focus_transaction.has_focus,
1468 focus_transaction.focus_options.preventScroll,
1469 )
1470 };
1471 *self.focus_transaction.borrow_mut() = None;
1472
1473 if !new_focus_state {
1474 if new_focused.take().is_some() {
1477 trace!(
1478 "Forgetting the document's focused area because the \
1479 document's container was removed from the top-level BC's \
1480 focus chain"
1481 );
1482 }
1483 }
1484
1485 let old_focused = self.focused.get();
1486 let old_focus_state = self.has_focus.get();
1487
1488 debug!(
1489 "Committing focus transaction: {:?} → {:?}",
1490 (&old_focused, old_focus_state),
1491 (&new_focused, new_focus_state),
1492 );
1493
1494 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1497 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1498
1499 let trace_focus_chain = |name, element, doc| {
1500 trace!(
1501 "{} local focus chain: {}",
1502 name,
1503 match (element, doc) {
1504 (Some(e), _) => format!("[{:?}, document]", e),
1505 (None, true) => "[document]".to_owned(),
1506 (None, false) => "[]".to_owned(),
1507 }
1508 );
1509 };
1510
1511 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1512 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1513
1514 if old_focused_filtered != new_focused_filtered {
1515 if let Some(elem) = &old_focused_filtered {
1516 let node = elem.upcast::<Node>();
1517 elem.set_focus_state(false);
1518 if node.is_connected() {
1520 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1521 }
1522 }
1523 }
1524
1525 if old_focus_state != new_focus_state && !new_focus_state {
1526 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1527 }
1528
1529 self.focused.set(new_focused.as_deref());
1530 self.has_focus.set(new_focus_state);
1531
1532 if old_focus_state != new_focus_state && new_focus_state {
1533 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1534 }
1535
1536 if old_focused_filtered != new_focused_filtered {
1537 if let Some(elem) = &new_focused_filtered {
1538 elem.set_focus_state(true);
1539 let node = elem.upcast::<Node>();
1540 if let Some(html_element) = elem.downcast::<HTMLElement>() {
1541 html_element.handle_focus_state_for_contenteditable(can_gc);
1542 }
1543 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1545
1546 if !prevent_scroll {
1549 let scroll_axis = ScrollAxisState {
1552 position: ScrollLogicalPosition::Center,
1553 requirement: ScrollRequirement::IfNotVisible,
1554 };
1555
1556 elem.scroll_into_view_with_options(
1560 ScrollBehavior::Smooth,
1561 scroll_axis,
1562 scroll_axis,
1563 None,
1564 None,
1565 );
1566 }
1567 }
1568 }
1569
1570 if focus_initiator == FocusInitiator::Remote {
1571 return;
1572 }
1573
1574 match (old_focus_state, new_focus_state) {
1577 (_, true) => {
1578 let child_browsing_context_id = new_focused
1599 .as_ref()
1600 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1601 .and_then(|iframe| iframe.browsing_context_id());
1602
1603 let sequence = self.increment_fetch_focus_sequence();
1604
1605 debug!(
1606 "Advertising the focus request to the constellation \
1607 with sequence number {} and child BC ID {}",
1608 sequence,
1609 child_browsing_context_id
1610 .as_ref()
1611 .map(|id| id as &dyn std::fmt::Display)
1612 .unwrap_or(&"(none)"),
1613 );
1614
1615 self.window()
1616 .send_to_constellation(ScriptToConstellationMessage::Focus(
1617 child_browsing_context_id,
1618 sequence,
1619 ));
1620 },
1621 (false, false) => {
1622 },
1625 (true, false) => {
1626 unreachable!(
1627 "Can't lose the document's focus without specifying \
1628 another one to focus"
1629 );
1630 },
1631 }
1632 }
1633
1634 pub(crate) fn title_changed(&self) {
1636 if self.browsing_context().is_some() {
1637 self.send_title_to_embedder();
1638 let title = String::from(self.Title());
1639 self.window
1640 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1641 self.window.pipeline_id(),
1642 title.clone(),
1643 ));
1644 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1645 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1646 self.window.pipeline_id(),
1647 title,
1648 ));
1649 }
1650 }
1651 }
1652
1653 fn title(&self) -> Option<DOMString> {
1657 let title = self.GetDocumentElement().and_then(|root| {
1658 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1659 root.upcast::<Node>()
1661 .child_elements()
1662 .find(|node| {
1663 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1664 })
1665 .map(DomRoot::upcast::<Node>)
1666 } else {
1667 root.upcast::<Node>()
1669 .traverse_preorder(ShadowIncluding::No)
1670 .find(|node| node.is::<HTMLTitleElement>())
1671 }
1672 });
1673
1674 title.map(|title| {
1675 let value = title.child_text_content();
1677 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1678 })
1679 }
1680
1681 pub(crate) fn send_title_to_embedder(&self) {
1683 let window = self.window();
1684 if window.is_top_level() {
1685 let title = self.title().map(String::from);
1686 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1687 }
1688 }
1689
1690 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1691 let window = self.window();
1692 window.send_to_embedder(msg);
1693 }
1694
1695 pub(crate) fn dirty_all_nodes(&self) {
1696 let root = match self.GetDocumentElement() {
1697 Some(root) => root,
1698 None => return,
1699 };
1700 for node in root
1701 .upcast::<Node>()
1702 .traverse_preorder(ShadowIncluding::Yes)
1703 {
1704 node.dirty(NodeDamage::Other)
1705 }
1706 }
1707
1708 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1710 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1722 for target in notify_list.iter() {
1723 if target.downcast::<Document>().is_some() {
1724 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1727 } else if target.downcast::<Element>().is_some() {
1728 target.fire_event(Atom::from("scroll"), can_gc);
1731 }
1732 }
1733
1734 }
1738
1739 pub(crate) fn handle_viewport_scroll_event(&self) {
1743 let target = self.upcast::<EventTarget>();
1752 if self
1753 .pending_scroll_event_targets
1754 .borrow()
1755 .iter()
1756 .any(|other_target| *other_target == target)
1757 {
1758 return;
1759 }
1760
1761 self.pending_scroll_event_targets
1764 .borrow_mut()
1765 .push(Dom::from_ref(target));
1766 }
1767
1768 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1772 let target = element.upcast::<EventTarget>();
1782 if self
1783 .pending_scroll_event_targets
1784 .borrow()
1785 .iter()
1786 .any(|other_target| *other_target == target)
1787 {
1788 return;
1789 }
1790
1791 self.pending_scroll_event_targets
1794 .borrow_mut()
1795 .push(Dom::from_ref(target));
1796 }
1797
1798 pub(crate) fn node_from_nodes_and_strings(
1800 &self,
1801 mut nodes: Vec<NodeOrString>,
1802 can_gc: CanGc,
1803 ) -> Fallible<DomRoot<Node>> {
1804 if nodes.len() == 1 {
1805 Ok(match nodes.pop().unwrap() {
1806 NodeOrString::Node(node) => node,
1807 NodeOrString::String(string) => {
1808 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1809 },
1810 })
1811 } else {
1812 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1813 for node in nodes {
1814 match node {
1815 NodeOrString::Node(node) => {
1816 fragment.AppendChild(&node, can_gc)?;
1817 },
1818 NodeOrString::String(string) => {
1819 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1820 fragment.AppendChild(&node, can_gc).unwrap();
1823 },
1824 }
1825 }
1826 Ok(fragment)
1827 }
1828 }
1829
1830 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1831 match self.GetBody() {
1832 Some(ref body) if body.is_body_element() => {
1833 body.upcast::<Element>().get_string_attribute(local_name)
1834 },
1835 _ => DOMString::new(),
1836 }
1837 }
1838
1839 pub(crate) fn set_body_attribute(
1840 &self,
1841 local_name: &LocalName,
1842 value: DOMString,
1843 can_gc: CanGc,
1844 ) {
1845 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1846 let body = body.upcast::<Element>();
1847 let value = body.parse_attribute(&ns!(), local_name, value);
1848 body.set_attribute(local_name, value, can_gc);
1849 }
1850 }
1851
1852 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1853 self.current_script.set(script);
1854 }
1855
1856 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1857 self.script_blocking_stylesheets_count.get()
1858 }
1859
1860 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1861 let count_cell = &self.script_blocking_stylesheets_count;
1862 count_cell.set(count_cell.get() + 1);
1863 }
1864
1865 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1866 let count_cell = &self.script_blocking_stylesheets_count;
1867 assert!(count_cell.get() > 0);
1868 count_cell.set(count_cell.get() - 1);
1869 }
1870
1871 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1872 self.render_blocking_element_count.get()
1873 }
1874
1875 pub(crate) fn increment_render_blocking_element_count(&self) {
1876 let count_cell = &self.render_blocking_element_count;
1877 count_cell.set(count_cell.get() + 1);
1878 }
1879
1880 pub(crate) fn decrement_render_blocking_element_count(&self) {
1881 let count_cell = &self.render_blocking_element_count;
1882 assert!(count_cell.get() > 0);
1883 count_cell.set(count_cell.get() - 1);
1884 }
1885
1886 pub(crate) fn invalidate_stylesheets(&self) {
1887 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1888
1889 if let Some(element) = self.GetDocumentElement() {
1893 element.upcast::<Node>().dirty(NodeDamage::Style);
1894 }
1895 }
1896
1897 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1900 !self.animation_frame_list.borrow().is_empty()
1901 }
1902
1903 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1905 let ident = self.animation_frame_ident.get() + 1;
1906 self.animation_frame_ident.set(ident);
1907
1908 let had_animation_frame_callbacks;
1909 {
1910 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1911 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1912 animation_frame_list.push_back((ident, Some(callback)));
1913 }
1914
1915 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1921 self.window().send_to_constellation(
1922 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1923 AnimationState::AnimationCallbacksPresent,
1924 ),
1925 );
1926 }
1927
1928 ident
1929 }
1930
1931 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1933 let mut list = self.animation_frame_list.borrow_mut();
1934 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1935 pair.1 = None;
1936 }
1937 }
1938
1939 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1941 let _realm = enter_realm(self);
1942
1943 self.running_animation_callbacks.set(true);
1944 let timing = self.global().performance().Now();
1945
1946 let num_callbacks = self.animation_frame_list.borrow().len();
1947 for _ in 0..num_callbacks {
1948 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1949 if let Some(callback) = maybe_callback {
1950 callback.call(self, *timing, can_gc);
1951 }
1952 }
1953 self.running_animation_callbacks.set(false);
1954
1955 if self.animation_frame_list.borrow().is_empty() {
1956 self.window().send_to_constellation(
1957 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1958 AnimationState::NoAnimationCallbacksPresent,
1959 ),
1960 );
1961 }
1962 }
1963
1964 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1965 self.policy_container.borrow()
1966 }
1967
1968 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1969 *self.policy_container.borrow_mut() = policy_container;
1970 }
1971
1972 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1973 self.policy_container.borrow_mut().set_csp_list(csp_list);
1974 }
1975
1976 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
1977 Ref::map(self.policy_container.borrow(), |policy_container| {
1978 &policy_container.csp_list
1979 })
1980 }
1981
1982 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1983 self.preloaded_resources.borrow()
1984 }
1985
1986 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1987 self.preloaded_resources
1988 .borrow_mut()
1989 .insert(key, preload_id);
1990 }
1991
1992 pub(crate) fn fetch<Listener: FetchResponseListener>(
1993 &self,
1994 load: LoadType,
1995 mut request: RequestBuilder,
1996 listener: Listener,
1997 ) {
1998 request = request
1999 .insecure_requests_policy(self.insecure_requests_policy())
2000 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2001 let callback = NetworkListener {
2002 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2003 task_source: self
2004 .owner_global()
2005 .task_manager()
2006 .networking_task_source()
2007 .into(),
2008 }
2009 .into_callback();
2010 self.loader_mut()
2011 .fetch_async_with_callback(load, request, callback);
2012 }
2013
2014 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
2015 &self,
2016 mut request: RequestBuilder,
2017 listener: Listener,
2018 ) {
2019 request = request
2020 .insecure_requests_policy(self.insecure_requests_policy())
2021 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2022 let callback = NetworkListener {
2023 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2024 task_source: self
2025 .owner_global()
2026 .task_manager()
2027 .networking_task_source()
2028 .into(),
2029 }
2030 .into_callback();
2031 self.loader_mut().fetch_async_background(request, callback);
2032 }
2033
2034 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
2036 match self.window().window_proxy().frame_element() {
2037 None => DomRoot::from_ref(self),
2040 Some(container) => container.owner_document().deferred_fetch_control_document(),
2042 }
2043 }
2044
2045 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
2047 let control_document = self.deferred_fetch_control_document();
2049 let navigable = control_document.window();
2051 let is_top_level = navigable.is_top_level();
2054 let deferred_fetch_allowed = true;
2058 let deferred_fetch_minimal_allowed = true;
2062 let mut quota = match is_top_level {
2064 true if !deferred_fetch_allowed => 0,
2066 true if !deferred_fetch_minimal_allowed => 640 * 1024,
2068 true => 512 * 1024,
2070 _ if deferred_fetch_allowed => 0,
2074 _ if deferred_fetch_minimal_allowed => 8 * 1024,
2078 _ => 0,
2080 } as isize;
2081 let mut quota_for_request_origin = 64 * 1024_isize;
2083 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
2092 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
2094 continue;
2095 }
2096 let request_length = deferred_fetch.request.total_request_length();
2098 quota -= request_length as isize;
2100 if deferred_fetch.request.url().origin() == origin {
2103 quota_for_request_origin -= request_length as isize;
2104 }
2105 }
2106 if quota <= 0 {
2108 return 0;
2109 }
2110 if quota < quota_for_request_origin {
2112 return quota;
2113 }
2114 quota_for_request_origin
2116 }
2117
2118 pub(crate) fn update_document_for_history_step_application(
2120 &self,
2121 old_url: &ServoUrl,
2122 new_url: &ServoUrl,
2123 ) {
2124 if old_url.as_url()[Position::BeforeFragment..] !=
2154 new_url.as_url()[Position::BeforeFragment..]
2155 {
2156 let window = Trusted::new(self.owner_window().deref());
2157 let old_url = old_url.to_string();
2158 let new_url = new_url.to_string();
2159 self.owner_global()
2160 .task_manager()
2161 .dom_manipulation_task_source()
2162 .queue(task!(hashchange_event: move || {
2163 let window = window.root();
2164 HashChangeEvent::new(
2165 &window,
2166 atom!("hashchange"),
2167 false,
2168 false,
2169 old_url,
2170 new_url,
2171 CanGc::note(),
2172 )
2173 .upcast::<Event>()
2174 .fire(window.upcast(), CanGc::note());
2175 }));
2176 }
2177 }
2178
2179 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut js::context::JSContext) {
2182 debug!("Document got finish_load: {:?}", load);
2184 self.loader.borrow_mut().finish_load(&load);
2185
2186 match load {
2187 LoadType::Stylesheet(_) => {
2188 self.process_pending_parsing_blocking_script(cx);
2191
2192 self.process_deferred_scripts(CanGc::from_cx(cx));
2194 },
2195 LoadType::PageSource(_) => {
2196 if self.has_browsing_context && self.is_fully_active() {
2199 self.window().allow_layout_if_necessary();
2200 }
2201
2202 self.process_deferred_scripts(CanGc::from_cx(cx));
2207 },
2208 _ => {},
2209 }
2210
2211 let loader = self.loader.borrow();
2218
2219 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
2221 update_with_current_instant(&self.top_level_dom_complete);
2222 }
2223
2224 if loader.is_blocked() || loader.events_inhibited() {
2225 return;
2227 }
2228
2229 ScriptThread::mark_document_with_no_blocked_loads(self);
2230 }
2231
2232 pub(crate) fn check_if_unloading_is_cancelled(
2234 &self,
2235 recursive_flag: bool,
2236 can_gc: CanGc,
2237 ) -> bool {
2238 self.incr_ignore_opens_during_unload_counter();
2241 let beforeunload_event = BeforeUnloadEvent::new(
2243 &self.window,
2244 atom!("beforeunload"),
2245 EventBubbles::Bubbles,
2246 EventCancelable::Cancelable,
2247 can_gc,
2248 );
2249 let event = beforeunload_event.upcast::<Event>();
2250 event.set_trusted(true);
2251 let event_target = self.window.upcast::<EventTarget>();
2252 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2253 self.window
2254 .dispatch_event_with_target_override(event, can_gc);
2255 if has_listeners {
2258 self.salvageable.set(false);
2259 }
2260 let mut can_unload = true;
2261 let default_prevented = event.DefaultPrevented();
2263 let return_value_not_empty = !event
2264 .downcast::<BeforeUnloadEvent>()
2265 .unwrap()
2266 .ReturnValue()
2267 .is_empty();
2268 if default_prevented || return_value_not_empty {
2269 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2270 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2271 self.send_to_embedder(msg);
2272 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2273 }
2274 if !recursive_flag {
2276 let iframes: Vec<_> = self.iframes().iter().collect();
2279 for iframe in &iframes {
2280 let document = iframe.owner_document();
2282 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2283 if !document.salvageable() {
2284 self.salvageable.set(false);
2285 }
2286 if !can_unload {
2287 break;
2288 }
2289 }
2290 }
2291 self.decr_ignore_opens_during_unload_counter();
2293 can_unload
2294 }
2295
2296 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2298 self.incr_ignore_opens_during_unload_counter();
2301 if self.page_showing.get() {
2303 self.page_showing.set(false);
2305 let event = PageTransitionEvent::new(
2308 &self.window,
2309 atom!("pagehide"),
2310 false, false, self.salvageable.get(), can_gc,
2314 );
2315 let event = event.upcast::<Event>();
2316 event.set_trusted(true);
2317 self.window
2318 .dispatch_event_with_target_override(event, can_gc);
2319 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2321 }
2322 if !self.fired_unload.get() {
2324 let event = Event::new(
2325 self.window.upcast(),
2326 atom!("unload"),
2327 EventBubbles::Bubbles,
2328 EventCancelable::Cancelable,
2329 can_gc,
2330 );
2331 event.set_trusted(true);
2332 let event_target = self.window.upcast::<EventTarget>();
2333 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2334 self.window
2335 .dispatch_event_with_target_override(&event, can_gc);
2336 self.fired_unload.set(true);
2337 if has_listeners {
2339 self.salvageable.set(false);
2340 }
2341 }
2342 if !recursive_flag {
2346 let iframes: Vec<_> = self.iframes().iter().collect();
2349 for iframe in &iframes {
2350 let document = iframe.owner_document();
2352 document.unload(true, can_gc);
2353 if !document.salvageable() {
2354 self.salvageable.set(false);
2355 }
2356 }
2357 }
2358
2359 self.unloading_cleanup_steps();
2361
2362 self.window.as_global_scope().clean_up_all_file_resources();
2364
2365 self.decr_ignore_opens_during_unload_counter();
2367
2368 }
2371
2372 fn completely_finish_loading(&self) {
2374 self.completely_loaded.set(true);
2379 self.notify_constellation_load();
2388
2389 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2398 &*self.declarative_refresh.borrow()
2399 {
2400 self.window.as_global_scope().schedule_callback(
2401 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2402 window: DomRoot::from_ref(self.window()),
2403 url: url.clone(),
2404 }),
2405 Duration::from_secs(*time),
2406 );
2407 }
2408 }
2409
2410 pub(crate) fn maybe_queue_document_completion(&self) {
2412 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2414 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2415 None => false,
2416 };
2417
2418 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2423 !self.is_fully_active() ||
2424 is_in_delaying_load_events_mode ||
2425 self.loader.borrow().events_inhibited();
2428
2429 if not_ready_for_load {
2430 return;
2432 }
2433
2434 self.loader.borrow_mut().inhibit_events();
2435
2436 debug!("Document loads are complete.");
2441 let document = Trusted::new(self);
2442 self.owner_global()
2443 .task_manager()
2444 .dom_manipulation_task_source()
2445 .queue(task!(fire_load_event: move || {
2446 let document = document.root();
2447 let window = document.window();
2449 if !window.is_alive() {
2450 return;
2451 }
2452
2453 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2455
2456 if document.browsing_context().is_none() {
2458 return;
2459 }
2460
2461 update_with_current_instant(&document.load_event_start);
2463
2464 let load_event = Event::new(
2466 window.upcast(),
2467 atom!("load"),
2468 EventBubbles::DoesNotBubble,
2469 EventCancelable::NotCancelable,
2470 CanGc::note(),
2471 );
2472 load_event.set_trusted(true);
2473 debug!("About to dispatch load for {:?}", document.url());
2474 window.dispatch_event_with_target_override(&load_event, CanGc::note());
2475
2476 update_with_current_instant(&document.load_event_end);
2486
2487 document.page_showing.set(true);
2492
2493 let page_show_event = PageTransitionEvent::new(
2495 window,
2496 atom!("pageshow"),
2497 false, false, false, CanGc::note(),
2501 );
2502 let page_show_event = page_show_event.upcast::<Event>();
2503 page_show_event.set_trusted(true);
2504 page_show_event.fire(window.upcast(), CanGc::note());
2505
2506 document.completely_finish_loading();
2508
2509 if let Some(fragment) = document.url().fragment() {
2513 document.scroll_to_the_fragment(fragment);
2514 }
2515 }));
2516
2517 #[cfg(feature = "webxr")]
2532 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2533 self.window.Navigator().Xr().dispatch_sessionavailable();
2534 }
2535 }
2536
2537 pub(crate) fn completely_loaded(&self) -> bool {
2538 self.completely_loaded.get()
2539 }
2540
2541 pub(crate) fn set_pending_parsing_blocking_script(
2543 &self,
2544 script: &HTMLScriptElement,
2545 load: Option<ScriptResult>,
2546 ) {
2547 assert!(!self.has_pending_parsing_blocking_script());
2548 *self.pending_parsing_blocking_script.borrow_mut() =
2549 Some(PendingScript::new_with_load(script, load));
2550 }
2551
2552 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2554 self.pending_parsing_blocking_script.borrow().is_some()
2555 }
2556
2557 pub(crate) fn pending_parsing_blocking_script_loaded(
2559 &self,
2560 element: &HTMLScriptElement,
2561 result: ScriptResult,
2562 cx: &mut js::context::JSContext,
2563 ) {
2564 {
2565 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2566 let entry = blocking_script.as_mut().unwrap();
2567 assert!(&*entry.element == element);
2568 entry.loaded(result);
2569 }
2570 self.process_pending_parsing_blocking_script(cx);
2571 }
2572
2573 fn process_pending_parsing_blocking_script(&self, cx: &mut js::context::JSContext) {
2574 if self.script_blocking_stylesheets_count.get() > 0 {
2575 return;
2576 }
2577 let pair = self
2578 .pending_parsing_blocking_script
2579 .borrow_mut()
2580 .as_mut()
2581 .and_then(PendingScript::take_result);
2582 if let Some((element, result)) = pair {
2583 *self.pending_parsing_blocking_script.borrow_mut() = None;
2584 self.get_current_parser()
2585 .unwrap()
2586 .resume_with_pending_parsing_blocking_script(&element, result, cx);
2587 }
2588 }
2589
2590 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2592 self.asap_scripts_set
2593 .borrow_mut()
2594 .push(Dom::from_ref(script));
2595 }
2596
2597 pub(crate) fn asap_script_loaded(
2600 &self,
2601 element: &HTMLScriptElement,
2602 result: ScriptResult,
2603 can_gc: CanGc,
2604 ) {
2605 {
2606 let mut scripts = self.asap_scripts_set.borrow_mut();
2607 let idx = scripts
2608 .iter()
2609 .position(|entry| &**entry == element)
2610 .unwrap();
2611 scripts.swap_remove(idx);
2612 }
2613 element.execute(result, can_gc);
2614 }
2615
2616 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2618 self.asap_in_order_scripts_list.push(script);
2619 }
2620
2621 pub(crate) fn asap_in_order_script_loaded(
2624 &self,
2625 element: &HTMLScriptElement,
2626 result: ScriptResult,
2627 can_gc: CanGc,
2628 ) {
2629 self.asap_in_order_scripts_list.loaded(element, result);
2630 while let Some((element, result)) = self
2631 .asap_in_order_scripts_list
2632 .take_next_ready_to_be_executed()
2633 {
2634 element.execute(result, can_gc);
2635 }
2636 }
2637
2638 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2640 self.deferred_scripts.push(script);
2641 }
2642
2643 pub(crate) fn deferred_script_loaded(
2646 &self,
2647 element: &HTMLScriptElement,
2648 result: ScriptResult,
2649 can_gc: CanGc,
2650 ) {
2651 self.deferred_scripts.loaded(element, result);
2652 self.process_deferred_scripts(can_gc);
2653 }
2654
2655 fn process_deferred_scripts(&self, can_gc: CanGc) {
2657 if self.ready_state.get() != DocumentReadyState::Interactive {
2658 return;
2659 }
2660 loop {
2662 if self.script_blocking_stylesheets_count.get() > 0 {
2663 return;
2664 }
2665 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2666 {
2667 element.execute(result, can_gc);
2668 } else {
2669 break;
2670 }
2671 }
2672 if self.deferred_scripts.is_empty() {
2673 self.maybe_dispatch_dom_content_loaded();
2675 }
2676 }
2677
2678 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2680 if self.domcontentloaded_dispatched.get() {
2681 return;
2682 }
2683 self.domcontentloaded_dispatched.set(true);
2684 assert_ne!(
2685 self.ReadyState(),
2686 DocumentReadyState::Complete,
2687 "Complete before DOMContentLoaded?"
2688 );
2689
2690 update_with_current_instant(&self.dom_content_loaded_event_start);
2691
2692 let document = Trusted::new(self);
2694 self.owner_global()
2695 .task_manager()
2696 .dom_manipulation_task_source()
2697 .queue(
2698 task!(fire_dom_content_loaded_event: move || {
2699 let document = document.root();
2700 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2701 update_with_current_instant(&document.dom_content_loaded_event_end);
2702 })
2703 );
2704
2705 self.interactive_time
2707 .borrow()
2708 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2709
2710 }
2713
2714 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut js::context::JSContext) {
2716 if !self.is_fully_active() {
2718 self.salvageable.set(false);
2723 }
2727 for exited_iframe in self.iframes().iter() {
2740 debug!("Destroying nested iframe document");
2741 exited_iframe.destroy_document_and_its_descendants(cx);
2742 }
2743 self.destroy(cx);
2748 }
2751
2752 pub(crate) fn destroy(&self, cx: &mut js::context::JSContext) {
2754 let exited_window = self.window();
2755 self.abort(cx);
2757 self.salvageable.set(false);
2759 self.unloading_cleanup_steps();
2769
2770 exited_window
2773 .as_global_scope()
2774 .task_manager()
2775 .cancel_all_tasks_and_ignore_future_tasks();
2776
2777 exited_window.discard_browsing_context();
2779
2780 }
2792
2793 fn terminate_fetch_group(&self) -> bool {
2795 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2796
2797 for canceller in &mut load_cancellers {
2801 if !canceller.keep_alive() {
2802 canceller.terminate();
2803 }
2804 }
2805 self.owner_global().process_deferred_fetches();
2807
2808 !load_cancellers.is_empty()
2809 }
2810
2811 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
2813 self.loader.borrow_mut().inhibit_events();
2815
2816 for iframe in self.iframes().iter() {
2818 if let Some(document) = iframe.GetContentDocument() {
2819 document.abort(cx);
2820 }
2821 }
2822
2823 self.script_blocking_stylesheets_count.set(0);
2829 *self.pending_parsing_blocking_script.borrow_mut() = None;
2830 *self.asap_scripts_set.borrow_mut() = vec![];
2831 self.asap_in_order_scripts_list.clear();
2832 self.deferred_scripts.clear();
2833 let loads_cancelled = self.terminate_fetch_group();
2834 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2835 if loads_cancelled || event_sources_canceled {
2836 self.salvageable.set(false);
2838 };
2839
2840 self.owner_global()
2845 .task_manager()
2846 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2847
2848 if let Some(parser) = self.get_current_parser() {
2853 self.active_parser_was_aborted.set(true);
2855 parser.abort(cx);
2857 self.salvageable.set(false);
2859 }
2860 }
2861
2862 pub(crate) fn notify_constellation_load(&self) {
2863 self.window()
2864 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2865 }
2866
2867 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2868 self.current_parser.set(script);
2869 }
2870
2871 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2872 self.current_parser.get()
2873 }
2874
2875 pub(crate) fn get_current_parser_line(&self) -> u32 {
2876 self.get_current_parser()
2877 .map(|parser| parser.get_current_line())
2878 .unwrap_or(0)
2879 }
2880
2881 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2884 self.iframes.borrow_mut().validate(self);
2885 self.iframes.borrow()
2886 }
2887
2888 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2891 self.iframes.borrow_mut().validate(self);
2892 self.iframes.borrow_mut()
2893 }
2894
2895 pub(crate) fn invalidate_iframes_collection(&self) {
2896 self.iframes.borrow_mut().invalidate();
2897 }
2898
2899 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2900 self.dom_interactive.get()
2901 }
2902
2903 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2904 self.interactive_time
2905 .borrow_mut()
2906 .set_navigation_start(navigation_start);
2907 }
2908
2909 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2910 self.interactive_time.borrow()
2911 }
2912
2913 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2914 self.get_interactive_metrics().get_tti().is_some()
2915 }
2916
2917 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2918 self.dom_content_loaded_event_start.get()
2919 }
2920
2921 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2922 self.dom_content_loaded_event_end.get()
2923 }
2924
2925 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2926 self.dom_complete.get()
2927 }
2928
2929 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2930 self.top_level_dom_complete.get()
2931 }
2932
2933 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2934 self.load_event_start.get()
2935 }
2936
2937 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2938 self.load_event_end.get()
2939 }
2940
2941 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2942 self.unload_event_start.get()
2943 }
2944
2945 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2946 self.unload_event_end.get()
2947 }
2948
2949 pub(crate) fn start_tti(&self) {
2950 if self.get_interactive_metrics().needs_tti() {
2951 self.tti_window.borrow_mut().start_window();
2952 }
2953 }
2954
2955 pub(crate) fn record_tti_if_necessary(&self) {
2959 if self.has_recorded_tti_metric() {
2960 return;
2961 }
2962 if self.tti_window.borrow().needs_check() {
2963 self.get_interactive_metrics()
2964 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2965 self.tti_window.borrow().get_start(),
2966 ));
2967 }
2968 }
2969
2970 fn fire_focus_event(
2972 &self,
2973 focus_event_type: FocusEventType,
2974 event_target: &EventTarget,
2975 related_target: Option<&EventTarget>,
2976 can_gc: CanGc,
2977 ) {
2978 let (event_name, does_bubble) = match focus_event_type {
2979 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2980 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2981 };
2982 let event = FocusEvent::new(
2983 &self.window,
2984 event_name,
2985 does_bubble,
2986 EventCancelable::NotCancelable,
2987 Some(&self.window),
2988 0i32,
2989 related_target,
2990 can_gc,
2991 );
2992 let event = event.upcast::<Event>();
2993 event.set_trusted(true);
2994 event.fire(event_target, can_gc);
2995 }
2996
2997 pub(crate) fn is_cookie_averse(&self) -> bool {
2999 !self.has_browsing_context || !url_has_network_scheme(&self.url())
3000 }
3001
3002 pub(crate) fn lookup_custom_element_definition(
3004 &self,
3005 namespace: &Namespace,
3006 local_name: &LocalName,
3007 is: Option<&LocalName>,
3008 ) -> Option<Rc<CustomElementDefinition>> {
3009 if *namespace != ns!(html) {
3011 return None;
3012 }
3013
3014 if !self.has_browsing_context {
3016 return None;
3017 }
3018
3019 let registry = self.window.CustomElements();
3021
3022 registry.lookup_definition(local_name, is)
3023 }
3024
3025 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
3027 self.window.CustomElements()
3028 }
3029
3030 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
3031 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3032 self.throw_on_dynamic_markup_insertion_counter
3033 .set(counter + 1);
3034 }
3035
3036 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
3037 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3038 self.throw_on_dynamic_markup_insertion_counter
3039 .set(counter - 1);
3040 }
3041
3042 pub(crate) fn react_to_environment_changes(&self) {
3043 for image in self.responsive_images.borrow().iter() {
3044 image.react_to_environment_changes();
3045 }
3046 }
3047
3048 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3049 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3050 }
3051
3052 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3053 let index = self
3054 .responsive_images
3055 .borrow()
3056 .iter()
3057 .position(|x| **x == *img);
3058 if let Some(i) = index {
3059 self.responsive_images.borrow_mut().remove(i);
3060 }
3061 }
3062
3063 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3064 let did_have_these_media_controls = self
3065 .media_controls
3066 .borrow_mut()
3067 .insert(id.to_string(), Dom::from_ref(controls))
3068 .is_some();
3069 debug_assert!(
3070 !did_have_these_media_controls,
3071 "Trying to register known media controls"
3072 );
3073 }
3074
3075 pub(crate) fn unregister_media_controls(&self, id: &str) {
3076 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3077 debug_assert!(
3078 did_have_these_media_controls,
3079 "Trying to unregister unknown media controls"
3080 );
3081 }
3082
3083 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3084 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3085 if dirty_canvases
3086 .iter()
3087 .any(|dirty_canvas| dirty_canvas == canvas)
3088 {
3089 return;
3090 }
3091 dirty_canvases.push(canvas.clone());
3092 }
3093
3094 pub(crate) fn needs_rendering_update(&self) -> bool {
3098 if !self.is_fully_active() {
3099 return false;
3100 }
3101 if !self.window().layout_blocked() &&
3102 (!self.restyle_reason().is_empty() ||
3103 self.window().layout().needs_new_display_list())
3104 {
3105 return true;
3106 }
3107 if !self.rendering_update_reasons.get().is_empty() {
3108 return true;
3109 }
3110 if self.event_handler.has_pending_input_events() {
3111 return true;
3112 }
3113 if self.has_pending_scroll_events() {
3114 return true;
3115 }
3116 if self.window().has_unhandled_resize_event() {
3117 return true;
3118 }
3119 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3120 {
3121 return true;
3122 }
3123
3124 false
3125 }
3126
3127 pub(crate) fn update_the_rendering(&self) -> (ReflowPhasesRun, ReflowStatistics) {
3135 if self.render_blocking_element_count() > 0 {
3136 return Default::default();
3137 }
3138
3139 let mut phases = ReflowPhasesRun::empty();
3140 if self.has_pending_animated_image_update.get() {
3141 self.image_animation_manager
3142 .borrow()
3143 .update_active_frames(&self.window, self.current_animation_timeline_value());
3144 self.has_pending_animated_image_update.set(false);
3145 phases.insert(ReflowPhasesRun::UpdatedImageData);
3146 }
3147
3148 self.current_rendering_epoch
3149 .set(self.current_rendering_epoch.get().next());
3150 let current_rendering_epoch = self.current_rendering_epoch.get();
3151
3152 let image_keys: Vec<_> = self
3154 .dirty_canvases
3155 .borrow_mut()
3156 .drain(..)
3157 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3158 .collect();
3159
3160 let pipeline_id = self.window().pipeline_id();
3163 if !image_keys.is_empty() {
3164 phases.insert(ReflowPhasesRun::UpdatedImageData);
3165 self.waiting_on_canvas_image_updates.set(true);
3166 self.window().paint_api().delay_new_frame_for_canvas(
3167 self.webview_id(),
3168 self.window().pipeline_id(),
3169 current_rendering_epoch,
3170 image_keys,
3171 );
3172 }
3173
3174 let (reflow_phases, statistics) = self.window().reflow(ReflowGoal::UpdateTheRendering);
3175 let phases = phases.union(reflow_phases);
3176
3177 self.window().paint_api().update_epoch(
3178 self.webview_id(),
3179 pipeline_id,
3180 current_rendering_epoch,
3181 );
3182
3183 (phases, statistics)
3184 }
3185
3186 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3187 self.waiting_on_canvas_image_updates.set(false);
3188 }
3189
3190 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3191 self.waiting_on_canvas_image_updates.get()
3192 }
3193
3194 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
3204 if !self.is_fully_active() {
3205 return false;
3206 }
3207
3208 let fonts = self.Fonts(can_gc);
3209 if !fonts.waiting_to_fullfill_promise() {
3210 return false;
3211 }
3212 if self.window().font_context().web_fonts_still_loading() != 0 {
3213 return false;
3214 }
3215 if self.ReadyState() != DocumentReadyState::Complete {
3216 return false;
3217 }
3218 if !self.restyle_reason().is_empty() {
3219 return false;
3220 }
3221 if !self.rendering_update_reasons.get().is_empty() {
3222 return false;
3223 }
3224
3225 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
3226
3227 if result {
3231 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3232 }
3233
3234 result
3235 }
3236
3237 pub(crate) fn id_map(
3238 &self,
3239 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3240 self.id_map.borrow()
3241 }
3242
3243 pub(crate) fn name_map(
3244 &self,
3245 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3246 self.name_map.borrow()
3247 }
3248
3249 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3251 self.resize_observers
3252 .borrow_mut()
3253 .push(Dom::from_ref(resize_observer));
3254 }
3255
3256 pub(crate) fn has_resize_observers(&self) -> bool {
3258 !self.resize_observers.borrow().is_empty()
3259 }
3260
3261 pub(crate) fn gather_active_resize_observations_at_depth(
3264 &self,
3265 depth: &ResizeObservationDepth,
3266 ) -> bool {
3267 let mut has_active_resize_observations = false;
3268 for observer in self.resize_observers.borrow_mut().iter_mut() {
3269 observer.gather_active_resize_observations_at_depth(
3270 depth,
3271 &mut has_active_resize_observations,
3272 );
3273 }
3274 has_active_resize_observations
3275 }
3276
3277 #[expect(clippy::redundant_iter_cloned)]
3279 pub(crate) fn broadcast_active_resize_observations(
3280 &self,
3281 can_gc: CanGc,
3282 ) -> ResizeObservationDepth {
3283 let mut shallowest = ResizeObservationDepth::max();
3284 let iterator: Vec<DomRoot<ResizeObserver>> = self
3288 .resize_observers
3289 .borrow()
3290 .iter()
3291 .cloned()
3292 .map(|obs| DomRoot::from_ref(&*obs))
3293 .collect();
3294 for observer in iterator {
3295 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3296 }
3297 shallowest
3298 }
3299
3300 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3302 self.resize_observers
3303 .borrow()
3304 .iter()
3305 .any(|observer| observer.has_skipped_resize_observations())
3306 }
3307
3308 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3310 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3311 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3312 ..Default::default()
3313 };
3314 self.window
3315 .as_global_scope()
3316 .report_an_error(error_info, HandleValue::null(), can_gc);
3317 }
3318
3319 pub(crate) fn status_code(&self) -> Option<u16> {
3320 self.status_code
3321 }
3322
3323 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3325 let encoding = self.encoding.get();
3331
3332 let base_url = self.base_url();
3338
3339 url::Url::options()
3341 .base_url(Some(base_url.as_url()))
3342 .encoding_override(Some(&|input| {
3343 servo_url::encoding::encode_as_url_query_string(input, encoding)
3344 }))
3345 .parse(url)
3346 .map(ServoUrl::from)
3347 }
3348
3349 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3351 if !self.has_browsing_context {
3353 return false;
3354 }
3355
3356 if !self.is_fully_active() {
3358 return false;
3359 }
3360
3361 true
3367 }
3368
3369 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3372 self.intersection_observers
3373 .borrow_mut()
3374 .push(Dom::from_ref(intersection_observer));
3375 }
3376
3377 pub(crate) fn remove_intersection_observer(
3381 &self,
3382 intersection_observer: &IntersectionObserver,
3383 ) {
3384 self.intersection_observers
3385 .borrow_mut()
3386 .retain(|observer| *observer != intersection_observer)
3387 }
3388
3389 pub(crate) fn update_intersection_observer_steps(
3391 &self,
3392 time: CrossProcessInstant,
3393 can_gc: CanGc,
3394 ) {
3395 for intersection_observer in &*self.intersection_observers.borrow() {
3397 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3398 }
3399 }
3400
3401 fn update_single_intersection_observer_steps(
3403 &self,
3404 intersection_observer: &IntersectionObserver,
3405 time: CrossProcessInstant,
3406 can_gc: CanGc,
3407 ) {
3408 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3411
3412 intersection_observer.update_intersection_observations_steps(
3416 self,
3417 time,
3418 root_bounds,
3419 can_gc,
3420 );
3421 }
3422
3423 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3425 self.intersection_observer_task_queued.set(false);
3428
3429 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3434
3435 for intersection_observer in notify_list.iter() {
3438 intersection_observer.invoke_callback_if_necessary(can_gc);
3440 }
3441 }
3442
3443 pub(crate) fn queue_an_intersection_observer_task(&self) {
3445 if self.intersection_observer_task_queued.get() {
3448 return;
3449 }
3450
3451 self.intersection_observer_task_queued.set(true);
3454
3455 let document = Trusted::new(self);
3459 self.owner_global()
3460 .task_manager()
3461 .intersection_observer_task_source()
3462 .queue(task!(notify_intersection_observers: move || {
3463 document.root().notify_intersection_observers(CanGc::note());
3464 }));
3465 }
3466
3467 pub(crate) fn handle_paint_metric(
3468 &self,
3469 metric_type: ProgressiveWebMetricType,
3470 metric_value: CrossProcessInstant,
3471 first_reflow: bool,
3472 can_gc: CanGc,
3473 ) {
3474 let metrics = self.interactive_time.borrow();
3475 match metric_type {
3476 ProgressiveWebMetricType::FirstPaint |
3477 ProgressiveWebMetricType::FirstContentfulPaint => {
3478 let binding = PerformancePaintTiming::new(
3479 self.window.as_global_scope(),
3480 metric_type.clone(),
3481 metric_value,
3482 can_gc,
3483 );
3484 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3485 let entry = binding.upcast::<PerformanceEntry>();
3486 self.window.Performance().queue_entry(entry);
3487 },
3488 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3489 let binding = LargestContentfulPaint::new(
3490 self.window.as_global_scope(),
3491 metric_value,
3492 area,
3493 url,
3494 can_gc,
3495 );
3496 metrics.set_largest_contentful_paint(metric_value, area);
3497 let entry = binding.upcast::<PerformanceEntry>();
3498 self.window.Performance().queue_entry(entry);
3499 },
3500 ProgressiveWebMetricType::TimeToInteractive => {
3501 unreachable!("Unexpected non-paint metric.")
3502 },
3503 }
3504 }
3505
3506 fn write(
3508 &self,
3509 cx: &mut js::context::JSContext,
3510 text: Vec<TrustedHTMLOrString>,
3511 line_feed: bool,
3512 containing_class: &str,
3513 field: &str,
3514 ) -> ErrorResult {
3515 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3517 let mut is_trusted = true;
3519 for value in text {
3521 match value {
3522 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3524 strings.push(trusted_html.to_string());
3525 },
3526 TrustedHTMLOrString::String(str_) => {
3527 is_trusted = false;
3529 strings.push(str_.into());
3531 },
3532 };
3533 }
3534 let mut string = itertools::join(strings, "");
3535 if !is_trusted {
3539 string = TrustedHTML::get_trusted_script_compliant_string(
3540 &self.global(),
3541 TrustedHTMLOrString::String(string.into()),
3542 &format!("{} {}", containing_class, field),
3543 CanGc::from_cx(cx),
3544 )?
3545 .str()
3546 .to_owned();
3547 }
3548 if line_feed {
3550 string.push('\n');
3551 }
3552 if !self.is_html_document() {
3554 return Err(Error::InvalidState(None));
3555 }
3556
3557 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3560 return Err(Error::InvalidState(None));
3561 }
3562
3563 if !self.is_active() || self.active_parser_was_aborted.get() {
3565 return Ok(());
3566 }
3567
3568 let parser = match self.get_current_parser() {
3569 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3570 _ => {
3572 if self.is_prompting_or_unloading() ||
3575 self.ignore_destructive_writes_counter.get() > 0
3576 {
3577 return Ok(());
3578 }
3579 self.Open(cx, None, None)?;
3581 self.get_current_parser().unwrap()
3582 },
3583 };
3584
3585 parser.write(string.into(), cx);
3587
3588 Ok(())
3589 }
3590
3591 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3592 RefMut::map(
3593 self.details_name_groups.borrow_mut(),
3594 |details_name_groups| details_name_groups.get_or_insert_default(),
3595 )
3596 }
3597}
3598
3599#[derive(MallocSizeOf, PartialEq)]
3600pub(crate) enum DocumentSource {
3601 FromParser,
3602 NotFromParser,
3603}
3604
3605pub(crate) trait LayoutDocumentHelpers<'dom> {
3606 fn is_html_document_for_layout(&self) -> bool;
3607 fn quirks_mode(self) -> QuirksMode;
3608 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3609 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3610 fn shadow_roots_styles_changed(self) -> bool;
3611 fn flush_shadow_roots_stylesheets(self);
3612 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>];
3613}
3614
3615#[expect(unsafe_code)]
3616impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3617 #[inline]
3618 fn is_html_document_for_layout(&self) -> bool {
3619 self.unsafe_get().is_html_document
3620 }
3621
3622 #[inline]
3623 fn quirks_mode(self) -> QuirksMode {
3624 self.unsafe_get().quirks_mode.get()
3625 }
3626
3627 #[inline]
3628 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3629 self.unsafe_get().style_shared_lock()
3630 }
3631
3632 #[inline]
3633 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3634 unsafe {
3639 self.unsafe_get()
3640 .shadow_roots
3641 .borrow_for_layout()
3642 .iter()
3643 .map(|sr| sr.to_layout())
3644 .collect()
3645 }
3646 }
3647
3648 #[inline]
3649 fn shadow_roots_styles_changed(self) -> bool {
3650 self.unsafe_get().shadow_roots_styles_changed.get()
3651 }
3652
3653 #[inline]
3654 fn flush_shadow_roots_stylesheets(self) {
3655 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3656 }
3657
3658 fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3659 let id_map = unsafe { self.unsafe_get().id_map.borrow_for_layout() };
3660 let matching_elements = id_map.get(id).map(Vec::as_slice).unwrap_or_default();
3661 unsafe { LayoutDom::to_layout_slice(matching_elements) }
3662 }
3663}
3664
3665pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3669 host_suffix_string: &str,
3670 original_host: Host,
3671) -> Option<Host> {
3672 if host_suffix_string.is_empty() {
3674 return None;
3675 }
3676
3677 let host = match Host::parse(host_suffix_string) {
3679 Ok(host) => host,
3680 Err(_) => return None,
3681 };
3682
3683 if host != original_host {
3685 let host = match host {
3687 Host::Domain(ref host) => host,
3688 _ => return None,
3689 };
3690 let original_host = match original_host {
3691 Host::Domain(ref original_host) => original_host,
3692 _ => return None,
3693 };
3694
3695 let index = original_host.len().checked_sub(host.len())?;
3697 let (prefix, suffix) = original_host.split_at(index);
3698
3699 if !prefix.ends_with('.') {
3700 return None;
3701 }
3702 if suffix != host {
3703 return None;
3704 }
3705
3706 if is_pub_domain(host) {
3708 return None;
3709 }
3710 }
3711
3712 Some(host)
3714}
3715
3716fn url_has_network_scheme(url: &ServoUrl) -> bool {
3718 matches!(url.scheme(), "ftp" | "http" | "https")
3719}
3720
3721#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3722pub(crate) enum HasBrowsingContext {
3723 No,
3724 Yes,
3725}
3726
3727impl Document {
3728 #[allow(clippy::too_many_arguments)]
3729 pub(crate) fn new_inherited(
3730 window: &Window,
3731 has_browsing_context: HasBrowsingContext,
3732 url: Option<ServoUrl>,
3733 about_base_url: Option<ServoUrl>,
3734 origin: MutableOrigin,
3735 is_html_document: IsHTMLDocument,
3736 content_type: Option<Mime>,
3737 last_modified: Option<String>,
3738 activity: DocumentActivity,
3739 source: DocumentSource,
3740 doc_loader: DocumentLoader,
3741 referrer: Option<String>,
3742 status_code: Option<u16>,
3743 canceller: FetchCanceller,
3744 is_initial_about_blank: bool,
3745 allow_declarative_shadow_roots: bool,
3746 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3747 has_trustworthy_ancestor_origin: bool,
3748 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3749 creation_sandboxing_flag_set: SandboxingFlagSet,
3750 ) -> Document {
3751 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3752
3753 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3754 (DocumentReadyState::Loading, false)
3755 } else {
3756 (DocumentReadyState::Complete, true)
3757 };
3758
3759 let frame_type = match window.is_top_level() {
3760 true => TimerMetadataFrameType::RootWindow,
3761 false => TimerMetadataFrameType::IFrame,
3762 };
3763 let interactive_time = ProgressiveWebMetrics::new(
3764 window.time_profiler_chan().clone(),
3765 url.clone(),
3766 frame_type,
3767 );
3768
3769 let content_type = content_type.unwrap_or_else(|| {
3770 match is_html_document {
3771 IsHTMLDocument::HTMLDocument => "text/html",
3773 IsHTMLDocument::NonHTMLDocument => "application/xml",
3775 }
3776 .parse()
3777 .unwrap()
3778 });
3779
3780 let encoding = content_type
3781 .get_parameter(CHARSET)
3782 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3783 .unwrap_or(UTF_8);
3784
3785 let has_focus = window.parent_info().is_none();
3786
3787 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3788
3789 Document {
3790 node: Node::new_document_node(),
3791 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3792 window: Dom::from_ref(window),
3793 has_browsing_context,
3794 implementation: Default::default(),
3795 content_type,
3796 last_modified,
3797 url: DomRefCell::new(url),
3798 about_base_url: DomRefCell::new(about_base_url),
3799 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3801 event_handler: DocumentEventHandler::new(window),
3802 embedder_controls: DocumentEmbedderControls::new(window),
3803 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3804 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3805 encoding: Cell::new(encoding),
3807 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3808 activity: Cell::new(activity),
3809 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3810 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3811 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3812 images: Default::default(),
3813 embeds: Default::default(),
3814 links: Default::default(),
3815 forms: Default::default(),
3816 scripts: Default::default(),
3817 anchors: Default::default(),
3818 applets: Default::default(),
3819 iframes: RefCell::new(IFrameCollection::new()),
3820 style_shared_lock: {
3821 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3828 LazyLock::new(StyleSharedRwLock::new);
3829
3830 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3831 },
3833 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3834 stylesheet_list: MutNullableDom::new(None),
3835 ready_state: Cell::new(ready_state),
3836 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3837 focus_transaction: DomRefCell::new(None),
3838 focused: Default::default(),
3839 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3840 has_focus: Cell::new(has_focus),
3841 current_script: Default::default(),
3842 pending_parsing_blocking_script: Default::default(),
3843 script_blocking_stylesheets_count: Default::default(),
3844 render_blocking_element_count: Default::default(),
3845 deferred_scripts: Default::default(),
3846 asap_in_order_scripts_list: Default::default(),
3847 asap_scripts_set: Default::default(),
3848 animation_frame_ident: Cell::new(0),
3849 animation_frame_list: DomRefCell::new(VecDeque::new()),
3850 running_animation_callbacks: Cell::new(false),
3851 loader: DomRefCell::new(doc_loader),
3852 current_parser: Default::default(),
3853 base_element: Default::default(),
3854 target_base_element: Default::default(),
3855 appropriate_template_contents_owner_document: Default::default(),
3856 pending_restyles: DomRefCell::new(FxHashMap::default()),
3857 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3858 dom_interactive: Cell::new(Default::default()),
3859 dom_content_loaded_event_start: Cell::new(Default::default()),
3860 dom_content_loaded_event_end: Cell::new(Default::default()),
3861 dom_complete: Cell::new(Default::default()),
3862 top_level_dom_complete: Cell::new(Default::default()),
3863 load_event_start: Cell::new(Default::default()),
3864 load_event_end: Cell::new(Default::default()),
3865 unload_event_start: Cell::new(Default::default()),
3866 unload_event_end: Cell::new(Default::default()),
3867 https_state: Cell::new(HttpsState::None),
3868 origin,
3869 referrer,
3870 target_element: MutNullableDom::new(None),
3871 policy_container: DomRefCell::new(PolicyContainer::default()),
3872 preloaded_resources: Default::default(),
3873 ignore_destructive_writes_counter: Default::default(),
3874 ignore_opens_during_unload_counter: Default::default(),
3875 spurious_animation_frames: Cell::new(0),
3876 dom_count: Cell::new(1),
3877 fullscreen_element: MutNullableDom::new(None),
3878 form_id_listener_map: Default::default(),
3879 interactive_time: DomRefCell::new(interactive_time),
3880 tti_window: DomRefCell::new(InteractiveWindow::default()),
3881 canceller,
3882 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3883 page_showing: Cell::new(false),
3884 salvageable: Cell::new(true),
3885 active_parser_was_aborted: Cell::new(false),
3886 fired_unload: Cell::new(false),
3887 responsive_images: Default::default(),
3888 redirect_count: Cell::new(0),
3889 completely_loaded: Cell::new(false),
3890 script_and_layout_blockers: Cell::new(0),
3891 delayed_tasks: Default::default(),
3892 shadow_roots: DomRefCell::new(HashSet::new()),
3893 shadow_roots_styles_changed: Cell::new(false),
3894 media_controls: DomRefCell::new(HashMap::new()),
3895 dirty_canvases: DomRefCell::new(Default::default()),
3896 has_pending_animated_image_update: Cell::new(false),
3897 selection: MutNullableDom::new(None),
3898 animation_timeline: if pref!(layout_animations_test_enabled) {
3899 DomRefCell::new(AnimationTimeline::new_for_testing())
3900 } else {
3901 DomRefCell::new(AnimationTimeline::new())
3902 },
3903 animations: Animations::new(),
3904 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3905 dirty_root: Default::default(),
3906 declarative_refresh: Default::default(),
3907 resize_observers: Default::default(),
3908 fonts: Default::default(),
3909 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3910 status_code,
3911 is_initial_about_blank: Cell::new(is_initial_about_blank),
3912 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3913 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3914 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3915 intersection_observer_task_queued: Cell::new(false),
3916 intersection_observers: Default::default(),
3917 highlighted_dom_node: Default::default(),
3918 adopted_stylesheets: Default::default(),
3919 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3920 pending_scroll_event_targets: Default::default(),
3921 rendering_update_reasons: Default::default(),
3922 waiting_on_canvas_image_updates: Cell::new(false),
3923 current_rendering_epoch: Default::default(),
3924 custom_element_reaction_stack,
3925 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3926 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3927 favicon: RefCell::new(None),
3928 websockets: DOMTracker::new(),
3929 details_name_groups: Default::default(),
3930 protocol_handler_automation_mode: Default::default(),
3931 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3932 state_override: Default::default(),
3933 value_override: Default::default(),
3934 }
3935 }
3936
3937 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3939 if let Some(csp_list) = self.get_csp_list().as_ref() {
3940 for policy in &csp_list.0 {
3941 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3942 policy.disposition == PolicyDisposition::Enforce
3943 {
3944 return InsecureRequestsPolicy::Upgrade;
3945 }
3946 }
3947 }
3948
3949 self.inherited_insecure_requests_policy
3950 .get()
3951 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3952 }
3953
3954 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3956 &self.event_handler
3957 }
3958
3959 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3961 &self.embedder_controls
3962 }
3963
3964 fn has_pending_scroll_events(&self) -> bool {
3967 !self.pending_scroll_event_targets.borrow().is_empty()
3968 }
3969
3970 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3973 self.rendering_update_reasons
3974 .set(self.rendering_update_reasons.get().union(reason));
3975 }
3976
3977 pub(crate) fn clear_rendering_update_reasons(&self) {
3979 self.rendering_update_reasons
3980 .set(RenderingUpdateReason::empty())
3981 }
3982
3983 pub(crate) fn add_script_and_layout_blocker(&self) {
3990 self.script_and_layout_blockers
3991 .set(self.script_and_layout_blockers.get() + 1);
3992 }
3993
3994 #[expect(unsafe_code)]
3995 pub(crate) fn remove_script_and_layout_blocker(&self) {
3999 assert!(self.script_and_layout_blockers.get() > 0);
4000 self.script_and_layout_blockers
4001 .set(self.script_and_layout_blockers.get() - 1);
4002 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
4003 {
4004 let task = self.delayed_tasks.borrow_mut().remove(0);
4005 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
4006 task.run_box(&mut cx);
4007 }
4008 }
4009
4010 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
4012 self.delayed_tasks.borrow_mut().push(Box::new(task));
4013 }
4014
4015 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
4018 assert_eq!(
4019 self.script_and_layout_blockers.get(),
4020 0,
4021 "Attempt to use script or layout while DOM not in a stable state"
4022 );
4023 }
4024
4025 #[allow(clippy::too_many_arguments)]
4026 pub(crate) fn new(
4027 window: &Window,
4028 has_browsing_context: HasBrowsingContext,
4029 url: Option<ServoUrl>,
4030 about_base_url: Option<ServoUrl>,
4031 origin: MutableOrigin,
4032 doctype: IsHTMLDocument,
4033 content_type: Option<Mime>,
4034 last_modified: Option<String>,
4035 activity: DocumentActivity,
4036 source: DocumentSource,
4037 doc_loader: DocumentLoader,
4038 referrer: Option<String>,
4039 status_code: Option<u16>,
4040 canceller: FetchCanceller,
4041 is_initial_about_blank: bool,
4042 allow_declarative_shadow_roots: bool,
4043 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4044 has_trustworthy_ancestor_origin: bool,
4045 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4046 creation_sandboxing_flag_set: SandboxingFlagSet,
4047 can_gc: CanGc,
4048 ) -> DomRoot<Document> {
4049 Self::new_with_proto(
4050 window,
4051 None,
4052 has_browsing_context,
4053 url,
4054 about_base_url,
4055 origin,
4056 doctype,
4057 content_type,
4058 last_modified,
4059 activity,
4060 source,
4061 doc_loader,
4062 referrer,
4063 status_code,
4064 canceller,
4065 is_initial_about_blank,
4066 allow_declarative_shadow_roots,
4067 inherited_insecure_requests_policy,
4068 has_trustworthy_ancestor_origin,
4069 custom_element_reaction_stack,
4070 creation_sandboxing_flag_set,
4071 can_gc,
4072 )
4073 }
4074
4075 #[allow(clippy::too_many_arguments)]
4076 fn new_with_proto(
4077 window: &Window,
4078 proto: Option<HandleObject>,
4079 has_browsing_context: HasBrowsingContext,
4080 url: Option<ServoUrl>,
4081 about_base_url: Option<ServoUrl>,
4082 origin: MutableOrigin,
4083 doctype: IsHTMLDocument,
4084 content_type: Option<Mime>,
4085 last_modified: Option<String>,
4086 activity: DocumentActivity,
4087 source: DocumentSource,
4088 doc_loader: DocumentLoader,
4089 referrer: Option<String>,
4090 status_code: Option<u16>,
4091 canceller: FetchCanceller,
4092 is_initial_about_blank: bool,
4093 allow_declarative_shadow_roots: bool,
4094 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4095 has_trustworthy_ancestor_origin: bool,
4096 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4097 creation_sandboxing_flag_set: SandboxingFlagSet,
4098 can_gc: CanGc,
4099 ) -> DomRoot<Document> {
4100 let document = reflect_dom_object_with_proto(
4101 Box::new(Document::new_inherited(
4102 window,
4103 has_browsing_context,
4104 url,
4105 about_base_url,
4106 origin,
4107 doctype,
4108 content_type,
4109 last_modified,
4110 activity,
4111 source,
4112 doc_loader,
4113 referrer,
4114 status_code,
4115 canceller,
4116 is_initial_about_blank,
4117 allow_declarative_shadow_roots,
4118 inherited_insecure_requests_policy,
4119 has_trustworthy_ancestor_origin,
4120 custom_element_reaction_stack,
4121 creation_sandboxing_flag_set,
4122 )),
4123 window,
4124 proto,
4125 can_gc,
4126 );
4127 {
4128 let node = document.upcast::<Node>();
4129 node.set_owner_doc(&document);
4130 }
4131 document
4132 }
4133
4134 pub(crate) fn get_redirect_count(&self) -> u16 {
4135 self.redirect_count.get()
4136 }
4137
4138 pub(crate) fn set_redirect_count(&self, count: u16) {
4139 self.redirect_count.set(count)
4140 }
4141
4142 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4143 if name.is_empty() {
4144 return 0;
4145 }
4146 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4147 }
4148
4149 pub(crate) fn nth_element_by_name(
4150 &self,
4151 index: u32,
4152 name: &DOMString,
4153 ) -> Option<DomRoot<Node>> {
4154 if name.is_empty() {
4155 return None;
4156 }
4157 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4158 }
4159
4160 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4163 let element = match node.downcast::<Element>() {
4164 Some(element) => element,
4165 None => return false,
4166 };
4167 if element.namespace() != &ns!(html) {
4168 return false;
4169 }
4170 element.get_name().is_some_and(|n| &*n == name)
4171 }
4172
4173 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4174 let doc = self.GetDocumentElement();
4175 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4176 maybe_node
4177 .iter()
4178 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4179 .filter(|node| callback(node))
4180 .count() as u32
4181 }
4182
4183 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4184 &self,
4185 index: u32,
4186 callback: F,
4187 ) -> Option<DomRoot<Node>> {
4188 let doc = self.GetDocumentElement();
4189 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4190 maybe_node
4191 .iter()
4192 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4193 .filter(|node| callback(node))
4194 .nth(index as usize)
4195 .map(|n| DomRoot::from_ref(&*n))
4196 }
4197
4198 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4199 self.GetDocumentElement().and_then(DomRoot::downcast)
4200 }
4201
4202 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
4204 &self.style_shared_lock
4205 }
4206
4207 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4209 let mut stylesheets = self.stylesheets.borrow_mut();
4216 let have_changed = stylesheets.has_changed();
4217 stylesheets.flush_without_invalidation();
4218 have_changed
4219 }
4220
4221 pub(crate) fn salvageable(&self) -> bool {
4222 self.salvageable.get()
4223 }
4224
4225 pub(crate) fn appropriate_template_contents_owner_document(
4227 &self,
4228 can_gc: CanGc,
4229 ) -> DomRoot<Document> {
4230 self.appropriate_template_contents_owner_document
4231 .or_init(|| {
4232 let doctype = if self.is_html_document {
4233 IsHTMLDocument::HTMLDocument
4234 } else {
4235 IsHTMLDocument::NonHTMLDocument
4236 };
4237 let new_doc = Document::new(
4238 self.window(),
4239 HasBrowsingContext::No,
4240 None,
4241 None,
4242 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4244 doctype,
4245 None,
4246 None,
4247 DocumentActivity::Inactive,
4248 DocumentSource::NotFromParser,
4249 DocumentLoader::new(&self.loader()),
4250 None,
4251 None,
4252 Default::default(),
4253 false,
4254 self.allow_declarative_shadow_roots(),
4255 Some(self.insecure_requests_policy()),
4256 self.has_trustworthy_ancestor_or_current_origin(),
4257 self.custom_element_reaction_stack.clone(),
4258 self.creation_sandboxing_flag_set(),
4259 can_gc,
4260 );
4261 new_doc
4262 .appropriate_template_contents_owner_document
4263 .set(Some(&new_doc));
4264 new_doc
4265 })
4266 }
4267
4268 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4269 self.id_map
4270 .borrow()
4271 .get(id)
4272 .map(|elements| DomRoot::from_ref(&*elements[0]))
4273 }
4274
4275 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4276 let map = self.pending_restyles.borrow_mut();
4277 RefMut::map(map, |m| {
4278 &mut m
4279 .entry(Dom::from_ref(el))
4280 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4281 .0
4282 })
4283 }
4284
4285 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4286 let mut entry = self.ensure_pending_restyle(el);
4292 if entry.snapshot.is_none() {
4293 entry.snapshot = Some(Snapshot::new());
4294 }
4295 if attr.local_name() == &local_name!("style") {
4296 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4297 }
4298
4299 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4300 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4301 }
4302
4303 let snapshot = entry.snapshot.as_mut().unwrap();
4304 if attr.local_name() == &local_name!("id") {
4305 if snapshot.id_changed {
4306 return;
4307 }
4308 snapshot.id_changed = true;
4309 } else if attr.local_name() == &local_name!("class") {
4310 if snapshot.class_changed {
4311 return;
4312 }
4313 snapshot.class_changed = true;
4314 } else {
4315 snapshot.other_attributes_changed = true;
4316 }
4317 let local_name = style::LocalName::cast(attr.local_name());
4318 if !snapshot.changed_attrs.contains(local_name) {
4319 snapshot.changed_attrs.push(local_name.clone());
4320 }
4321 if snapshot.attrs.is_none() {
4322 let attrs = el
4323 .attrs()
4324 .iter()
4325 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4326 .collect();
4327 snapshot.attrs = Some(attrs);
4328 }
4329 }
4330
4331 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4332 self.policy_container
4333 .borrow_mut()
4334 .set_referrer_policy(policy);
4335 }
4336
4337 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4338 self.policy_container.borrow().get_referrer_policy()
4339 }
4340
4341 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4342 if let Some(ref element) = self.target_element.get() {
4343 element.set_target_state(false);
4344 }
4345
4346 self.target_element.set(node);
4347
4348 if let Some(ref element) = self.target_element.get() {
4349 element.set_target_state(true);
4350 }
4351 }
4352
4353 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4354 self.ignore_destructive_writes_counter
4355 .set(self.ignore_destructive_writes_counter.get() + 1);
4356 }
4357
4358 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4359 self.ignore_destructive_writes_counter
4360 .set(self.ignore_destructive_writes_counter.get() - 1);
4361 }
4362
4363 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4364 self.ignore_opens_during_unload_counter.get() > 0
4365 }
4366
4367 fn incr_ignore_opens_during_unload_counter(&self) {
4368 self.ignore_opens_during_unload_counter
4369 .set(self.ignore_opens_during_unload_counter.get() + 1);
4370 }
4371
4372 fn decr_ignore_opens_during_unload_counter(&self) {
4373 self.ignore_opens_during_unload_counter
4374 .set(self.ignore_opens_during_unload_counter.get() - 1);
4375 }
4376
4377 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4379 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4386 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4387
4388 if !self.is_fully_active() {
4391 promise.reject_error(
4392 Error::Type(c"Document is not fully active".to_owned()),
4393 can_gc,
4394 );
4395 return promise;
4396 }
4397
4398 let mut error = false;
4401
4402 {
4405 match *pending.namespace() {
4407 ns!(mathml) => {
4408 if pending.local_name().as_ref() != "math" {
4409 error = true;
4410 }
4411 },
4412 ns!(svg) => {
4413 if pending.local_name().as_ref() != "svg" {
4414 error = true;
4415 }
4416 },
4417 ns!(html) => (),
4418 _ => error = true,
4419 }
4420
4421 if pending.is::<HTMLDialogElement>() {
4423 error = true;
4424 }
4425
4426 if !pending.fullscreen_element_ready_check() {
4428 error = true;
4429 }
4430
4431 if !pending.owner_window().has_transient_activation() {
4439 error = true;
4440 }
4441 }
4442
4443 if pref!(dom_fullscreen_test) {
4444 info!("Tests don't really enter fullscreen.");
4447 } else {
4448 warn!("Fullscreen not supported yet");
4451 }
4452
4453 if !error {
4456 pending.owner_window().consume_user_activation();
4457 }
4458
4459 if !error {
4465 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4466 self.send_to_embedder(event);
4467 }
4468
4469 let pipeline_id = self.window().pipeline_id();
4472
4473 let trusted_pending = Trusted::new(pending);
4474 let trusted_pending_doc = Trusted::new(self);
4475 let trusted_promise = TrustedPromise::new(promise.clone());
4476 let handler = ElementPerformFullscreenEnter::new(
4477 trusted_pending,
4478 trusted_pending_doc,
4479 trusted_promise,
4480 error,
4481 );
4482 let script_msg = CommonScriptMsg::Task(
4483 ScriptThreadEventCategory::EnterFullscreen,
4484 handler,
4485 Some(pipeline_id),
4486 TaskSourceName::DOMManipulation,
4487 );
4488 let msg = MainThreadScriptMsg::Common(script_msg);
4489 self.window().main_thread_script_chan().send(msg).unwrap();
4490
4491 promise
4492 }
4493
4494 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4496 let global = self.global();
4497
4498 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4501 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4502
4503 if !self.is_fully_active() || self.fullscreen_element.get().is_none() {
4506 promise.reject_error(
4507 Error::Type(
4508 c"No fullscreen element to exit or document is not fully active".to_owned(),
4509 ),
4510 can_gc,
4511 );
4512 return promise;
4513 }
4514
4515 let element = self.fullscreen_element.get().unwrap();
4518 let window = self.window();
4519
4520 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4524 self.send_to_embedder(event);
4525
4526 let trusted_element = Trusted::new(&*element);
4529 let trusted_promise = TrustedPromise::new(promise.clone());
4530 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4531 let pipeline_id = Some(global.pipeline_id());
4532 let script_msg = CommonScriptMsg::Task(
4533 ScriptThreadEventCategory::ExitFullscreen,
4534 handler,
4535 pipeline_id,
4536 TaskSourceName::DOMManipulation,
4537 );
4538 let msg = MainThreadScriptMsg::Common(script_msg);
4539 window.main_thread_script_chan().send(msg).unwrap();
4540
4541 promise
4542 }
4543
4544 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4545 self.fullscreen_element.set(element);
4546 }
4547
4548 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4549 match self.browsing_context() {
4551 None => false,
4553 Some(_) => {
4554 let window = self.window();
4556 if window.is_top_level() {
4557 true
4558 } else {
4559 window
4561 .GetFrameElement()
4562 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4563 }
4564 },
4565 }
4566 }
4567
4568 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4569 let map = self.form_id_listener_map.borrow();
4570 if let Some(listeners) = map.get(id) {
4571 for listener in listeners {
4572 listener
4573 .as_maybe_form_control()
4574 .expect("Element must be a form control")
4575 .reset_form_owner(can_gc);
4576 }
4577 }
4578 }
4579
4580 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4581 self.shadow_roots
4582 .borrow_mut()
4583 .insert(Dom::from_ref(shadow_root));
4584 self.invalidate_shadow_roots_stylesheets();
4585 }
4586
4587 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4588 let mut shadow_roots = self.shadow_roots.borrow_mut();
4589 shadow_roots.remove(&Dom::from_ref(shadow_root));
4590 }
4591
4592 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4593 self.shadow_roots_styles_changed.set(true);
4594 }
4595
4596 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4597 self.shadow_roots_styles_changed.get()
4598 }
4599
4600 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4601 if !self.shadow_roots_styles_changed.get() {
4602 return;
4603 }
4604 self.shadow_roots_styles_changed.set(false);
4605 }
4606
4607 pub(crate) fn stylesheet_count(&self) -> usize {
4608 self.stylesheets.borrow().len()
4609 }
4610
4611 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4612 let stylesheets = self.stylesheets.borrow();
4613
4614 stylesheets
4615 .get(Origin::Author, index)
4616 .and_then(|s| s.owner.get_cssom_object())
4617 }
4618
4619 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4626 let stylesheets = &mut *self.stylesheets.borrow_mut();
4627
4628 let insertion_point = stylesheets
4630 .iter()
4631 .map(|(sheet, _origin)| sheet)
4632 .find(|sheet_in_doc| {
4633 match &sheet_in_doc.owner {
4634 StylesheetSource::Element(other_node) => {
4635 owner_node.upcast::<Node>().is_before(other_node.upcast())
4636 },
4637 StylesheetSource::Constructed(_) => true,
4640 }
4641 })
4642 .cloned();
4643
4644 if self.has_browsing_context() {
4645 let document_context = self.window.web_font_context();
4646
4647 self.window.layout_mut().add_stylesheet(
4648 sheet.clone(),
4649 insertion_point.as_ref().map(|s| s.sheet.clone()),
4650 &document_context,
4651 );
4652 }
4653
4654 DocumentOrShadowRoot::add_stylesheet(
4655 StylesheetSource::Element(Dom::from_ref(owner_node)),
4656 StylesheetSetRef::Document(stylesheets),
4657 sheet,
4658 insertion_point,
4659 self.style_shared_lock(),
4660 );
4661 }
4662
4663 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4668 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4669 debug_assert!(cssom_stylesheet.is_constructed());
4670
4671 let stylesheets = &mut *self.stylesheets.borrow_mut();
4672 let sheet = cssom_stylesheet.style_stylesheet().clone();
4673
4674 let insertion_point = stylesheets
4675 .iter()
4676 .last()
4677 .map(|(sheet, _origin)| sheet)
4678 .cloned();
4679
4680 if self.has_browsing_context() {
4681 self.window.layout_mut().add_stylesheet(
4682 sheet.clone(),
4683 insertion_point.as_ref().map(|s| s.sheet.clone()),
4684 &self.window.web_font_context(),
4685 );
4686 }
4687
4688 DocumentOrShadowRoot::add_stylesheet(
4689 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4690 StylesheetSetRef::Document(stylesheets),
4691 sheet,
4692 insertion_point,
4693 self.style_shared_lock(),
4694 );
4695 }
4696
4697 pub(crate) fn load_web_fonts_from_stylesheet(
4699 &self,
4700 stylesheet: &Arc<Stylesheet>,
4701 document_context: &WebFontDocumentContext,
4702 ) {
4703 self.window
4704 .layout()
4705 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4706 }
4707
4708 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4711 if self.has_browsing_context() {
4712 self.window
4713 .layout_mut()
4714 .remove_stylesheet(stylesheet.clone());
4715 }
4716
4717 DocumentOrShadowRoot::remove_stylesheet(
4718 owner,
4719 stylesheet,
4720 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4721 )
4722 }
4723
4724 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4725 Ref::map(self.id_map.borrow(), |map| {
4726 map.get(id).map(|vec| &**vec).unwrap_or_default()
4727 })
4728 }
4729
4730 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4731 Ref::map(self.name_map.borrow(), |map| {
4732 map.get(name).map(|vec| &**vec).unwrap_or_default()
4733 })
4734 }
4735
4736 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4737 self.pending_restyles
4738 .borrow_mut()
4739 .drain()
4740 .filter_map(|(elem, restyle)| {
4741 let node = elem.upcast::<Node>();
4742 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4743 return None;
4744 }
4745 node.note_dirty_descendants();
4746 Some((node.to_trusted_node_address(), restyle.0))
4747 })
4748 .collect()
4749 }
4750
4751 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4752 self.animation_timeline.borrow_mut().advance_specific(delta);
4753 let current_timeline_value = self.current_animation_timeline_value();
4754 self.animations
4755 .update_for_new_timeline_value(&self.window, current_timeline_value);
4756 }
4757
4758 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4759 let current_timeline_value = self.current_animation_timeline_value();
4760 self.animations
4761 .mark_animating_nodes_as_dirty(current_timeline_value);
4762 }
4763
4764 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4765 self.animation_timeline.borrow().current_value()
4766 }
4767
4768 pub(crate) fn animations(&self) -> &Animations {
4769 &self.animations
4770 }
4771
4772 pub(crate) fn update_animations_post_reflow(&self) {
4773 self.animations
4774 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4775 self.image_animation_manager
4776 .borrow()
4777 .maybe_schedule_update_after_layout(
4778 &self.window,
4779 self.current_animation_timeline_value(),
4780 );
4781 }
4782
4783 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4784 self.animations.cancel_animations_for_node(node);
4785 self.image_animation_manager
4786 .borrow()
4787 .cancel_animations_for_node(node);
4788 }
4789
4790 pub(crate) fn update_animations_and_send_events(&self, cx: &mut js::context::JSContext) {
4792 if !self.layout_animations_test_enabled {
4794 self.animation_timeline.borrow_mut().update();
4795 }
4796
4797 let current_timeline_value = self.current_animation_timeline_value();
4804 self.animations
4805 .update_for_new_timeline_value(&self.window, current_timeline_value);
4806 self.maybe_mark_animating_nodes_as_dirty();
4807
4808 self.window().perform_a_microtask_checkpoint(cx);
4810
4811 let _realm = enter_realm(self);
4813 self.animations()
4814 .send_pending_events(self.window(), CanGc::from_cx(cx));
4815 }
4816
4817 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4818 self.image_animation_manager.borrow()
4819 }
4820
4821 pub(crate) fn set_has_pending_animated_image_update(&self) {
4822 self.has_pending_animated_image_update.set(true);
4823 }
4824
4825 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4827 if self.will_declaratively_refresh() {
4829 return;
4830 }
4831
4832 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4834 Regex::new(
4838 r#"(?xs)
4839 ^
4840 \s* # 3
4841 ((?<time>[0-9]+)|\.) # 5-6
4842 [0-9.]* # 8
4843 (
4844 (
4845 (\s*;|\s*,|\s) # 10.3
4846 \s* # 10.4
4847 )
4848 (
4849 (
4850 (U|u)(R|r)(L|l) # 11.2-11.4
4851 \s*=\s* # 11.5-11.7
4852 )?
4853 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4854 |
4855 (?<url4>(?s-u:.)*)
4856 )
4857 )?
4858 $
4859 "#,
4860 )
4861 .unwrap()
4862 });
4863
4864 let mut url_record = self.url();
4866 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4867 captures
4868 } else {
4869 return;
4870 };
4871 let time = if let Some(time_string) = captures.name("time") {
4872 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4873 } else {
4874 0
4875 };
4876 let captured_url = captures.name("url1").or(captures
4877 .name("url2")
4878 .or(captures.name("url3").or(captures.name("url4"))));
4879
4880 if let Some(url_match) = captured_url {
4882 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4883 Some(&url_record),
4884 &String::from_utf8_lossy(url_match.as_bytes()),
4885 ) {
4886 info!("Refresh to {}", url.debug_compact());
4887 url
4888 } else {
4889 return;
4891 }
4892 }
4893 if self.completely_loaded() {
4895 self.window.as_global_scope().schedule_callback(
4897 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4898 window: DomRoot::from_ref(self.window()),
4899 url: url_record,
4900 }),
4901 Duration::from_secs(time),
4902 );
4903 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4904 } else {
4905 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4906 url: url_record,
4907 time,
4908 });
4909 }
4910 }
4911
4912 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4913 self.declarative_refresh.borrow().is_some()
4914 }
4915 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4916 *self.declarative_refresh.borrow_mut() = Some(refresh);
4917 }
4918
4919 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4921 if self.visibility_state.get() == visibility_state {
4923 return;
4924 }
4925 self.visibility_state.set(visibility_state);
4927 let entry = VisibilityStateEntry::new(
4930 &self.global(),
4931 visibility_state,
4932 CrossProcessInstant::now(),
4933 can_gc,
4934 );
4935 self.window
4936 .Performance()
4937 .queue_entry(entry.upcast::<PerformanceEntry>());
4938
4939 #[cfg(feature = "gamepad")]
4950 if visibility_state == DocumentVisibilityState::Hidden {
4951 self.window
4952 .Navigator()
4953 .GetGamepads()
4954 .iter_mut()
4955 .for_each(|gamepad| {
4956 if let Some(g) = gamepad {
4957 g.vibration_actuator().handle_visibility_change();
4958 }
4959 });
4960 }
4961
4962 self.upcast::<EventTarget>()
4964 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4965 }
4966
4967 pub(crate) fn is_initial_about_blank(&self) -> bool {
4969 self.is_initial_about_blank.get()
4970 }
4971
4972 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4974 self.allow_declarative_shadow_roots.get()
4975 }
4976
4977 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4978 self.has_trustworthy_ancestor_origin.get()
4979 }
4980
4981 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4982 self.has_trustworthy_ancestor_origin.get() ||
4983 self.origin().immutable().is_potentially_trustworthy()
4984 }
4985
4986 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4987 self.highlighted_dom_node.set(node);
4988 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4989 }
4990
4991 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4992 self.highlighted_dom_node.get()
4993 }
4994
4995 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4996 self.custom_element_reaction_stack.clone()
4997 }
4998
4999 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
5000 self.active_sandboxing_flag_set.get().contains(flag)
5001 }
5002
5003 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
5004 self.active_sandboxing_flag_set.set(flags)
5005 }
5006
5007 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
5008 self.creation_sandboxing_flag_set.get()
5009 }
5010
5011 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
5012 &self,
5013 ) -> SandboxingFlagSet {
5014 self.window()
5015 .window_proxy()
5016 .frame_element()
5017 .and_then(|element| element.downcast::<HTMLIFrameElement>())
5018 .map(HTMLIFrameElement::sandboxing_flag_set)
5019 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
5020 }
5021
5022 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
5023 self.window()
5024 .scrolling_box_query(None, flags)
5025 .expect("We should always have a ScrollingBox for the Viewport")
5026 }
5027
5028 pub(crate) fn notify_embedder_favicon(&self) {
5029 if let Some(ref image) = *self.favicon.borrow() {
5030 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
5031 }
5032 }
5033
5034 pub(crate) fn set_favicon(&self, favicon: Image) {
5035 *self.favicon.borrow_mut() = Some(favicon);
5036 self.notify_embedder_favicon();
5037 }
5038
5039 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
5040 self.fullscreen_element.get()
5041 }
5042
5043 pub(crate) fn state_override(&self) -> bool {
5045 self.state_override.get()
5046 }
5047
5048 pub(crate) fn value_override(&self) -> Option<DOMString> {
5050 self.value_override.borrow().clone()
5051 }
5052}
5053
5054impl DocumentMethods<crate::DomTypeHolder> for Document {
5055 fn Constructor(
5057 window: &Window,
5058 proto: Option<HandleObject>,
5059 can_gc: CanGc,
5060 ) -> Fallible<DomRoot<Document>> {
5061 let doc = window.Document();
5063 let docloader = DocumentLoader::new(&doc.loader());
5064 Ok(Document::new_with_proto(
5065 window,
5066 proto,
5067 HasBrowsingContext::No,
5068 None,
5069 None,
5070 doc.origin().clone(),
5071 IsHTMLDocument::NonHTMLDocument,
5072 None,
5073 None,
5074 DocumentActivity::Inactive,
5075 DocumentSource::NotFromParser,
5076 docloader,
5077 None,
5078 None,
5079 Default::default(),
5080 false,
5081 doc.allow_declarative_shadow_roots(),
5082 Some(doc.insecure_requests_policy()),
5083 doc.has_trustworthy_ancestor_or_current_origin(),
5084 doc.custom_element_reaction_stack(),
5085 doc.active_sandboxing_flag_set.get(),
5086 can_gc,
5087 ))
5088 }
5089
5090 fn ParseHTMLUnsafe(
5092 cx: &mut js::context::JSContext,
5093 window: &Window,
5094 s: TrustedHTMLOrString,
5095 ) -> Fallible<DomRoot<Self>> {
5096 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
5100 window.as_global_scope(),
5101 s,
5102 "Document parseHTMLUnsafe",
5103 CanGc::from_cx(cx),
5104 )?;
5105
5106 let url = window.get_url();
5107 let doc = window.Document();
5108 let loader = DocumentLoader::new(&doc.loader());
5109
5110 let content_type = "text/html"
5111 .parse()
5112 .expect("Supported type is not a MIME type");
5113 let document = Document::new(
5116 window,
5117 HasBrowsingContext::No,
5118 Some(ServoUrl::parse("about:blank").unwrap()),
5119 None,
5120 doc.origin().clone(),
5121 IsHTMLDocument::HTMLDocument,
5122 Some(content_type),
5123 None,
5124 DocumentActivity::Inactive,
5125 DocumentSource::FromParser,
5126 loader,
5127 None,
5128 None,
5129 Default::default(),
5130 false,
5131 true,
5132 Some(doc.insecure_requests_policy()),
5133 doc.has_trustworthy_ancestor_or_current_origin(),
5134 doc.custom_element_reaction_stack(),
5135 doc.creation_sandboxing_flag_set(),
5136 CanGc::from_cx(cx),
5137 );
5138 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, cx);
5140 document.set_ready_state(DocumentReadyState::Complete, CanGc::from_cx(cx));
5142 Ok(document)
5143 }
5144
5145 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
5147 self.stylesheet_list.or_init(|| {
5148 StyleSheetList::new(
5149 &self.window,
5150 StyleSheetListOwner::Document(Dom::from_ref(self)),
5151 can_gc,
5152 )
5153 })
5154 }
5155
5156 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
5158 self.implementation
5159 .or_init(|| DOMImplementation::new(self, can_gc))
5160 }
5161
5162 fn URL(&self) -> USVString {
5164 USVString(String::from(self.url().as_str()))
5165 }
5166
5167 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5169 self.document_or_shadow_root.get_active_element(
5170 self.get_focused_element(),
5171 self.GetBody(),
5172 self.GetDocumentElement(),
5173 )
5174 }
5175
5176 fn HasFocus(&self) -> bool {
5178 if self.window().parent_info().is_none() {
5200 self.is_fully_active()
5202 } else {
5203 self.is_fully_active() && self.has_focus.get()
5205 }
5206 }
5207
5208 fn Domain(&self) -> DOMString {
5210 match self.origin.effective_domain() {
5212 None => DOMString::new(),
5214 Some(Host::Domain(domain)) => DOMString::from(domain),
5216 Some(host) => DOMString::from(host.to_string()),
5217 }
5218 }
5219
5220 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5222 if !self.has_browsing_context {
5224 return Err(Error::Security(None));
5225 }
5226
5227 if self.has_active_sandboxing_flag(
5230 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5231 ) {
5232 return Err(Error::Security(None));
5233 }
5234
5235 let effective_domain = match self.origin.effective_domain() {
5237 Some(effective_domain) => effective_domain,
5238 None => return Err(Error::Security(None)),
5240 };
5241
5242 let host =
5244 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5245 None => return Err(Error::Security(None)),
5246 Some(host) => host,
5247 };
5248
5249 self.origin.set_domain(host);
5254
5255 Ok(())
5256 }
5257
5258 fn Referrer(&self) -> DOMString {
5260 match self.referrer {
5261 Some(ref referrer) => DOMString::from(referrer.to_string()),
5262 None => DOMString::new(),
5263 }
5264 }
5265
5266 fn DocumentURI(&self) -> USVString {
5268 self.URL()
5269 }
5270
5271 fn CompatMode(&self) -> DOMString {
5273 DOMString::from(match self.quirks_mode.get() {
5274 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5275 QuirksMode::Quirks => "BackCompat",
5276 })
5277 }
5278
5279 fn CharacterSet(&self) -> DOMString {
5281 DOMString::from(self.encoding.get().name())
5282 }
5283
5284 fn Charset(&self) -> DOMString {
5286 self.CharacterSet()
5287 }
5288
5289 fn InputEncoding(&self) -> DOMString {
5291 self.CharacterSet()
5292 }
5293
5294 fn ContentType(&self) -> DOMString {
5296 DOMString::from(self.content_type.to_string())
5297 }
5298
5299 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5301 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5302 }
5303
5304 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5306 self.upcast::<Node>().child_elements().next()
5307 }
5308
5309 fn GetElementsByTagName(
5311 &self,
5312 qualified_name: DOMString,
5313 can_gc: CanGc,
5314 ) -> DomRoot<HTMLCollection> {
5315 let qualified_name = LocalName::from(qualified_name);
5316 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5317 return DomRoot::from_ref(entry);
5318 }
5319 let result = HTMLCollection::by_qualified_name(
5320 &self.window,
5321 self.upcast(),
5322 qualified_name.clone(),
5323 can_gc,
5324 );
5325 self.tag_map
5326 .borrow_mut()
5327 .insert(qualified_name, Dom::from_ref(&*result));
5328 result
5329 }
5330
5331 fn GetElementsByTagNameNS(
5333 &self,
5334 maybe_ns: Option<DOMString>,
5335 tag_name: DOMString,
5336 can_gc: CanGc,
5337 ) -> DomRoot<HTMLCollection> {
5338 let ns = namespace_from_domstring(maybe_ns);
5339 let local = LocalName::from(tag_name);
5340 let qname = QualName::new(None, ns, local);
5341 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5342 return DomRoot::from_ref(collection);
5343 }
5344 let result =
5345 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
5346 self.tagns_map
5347 .borrow_mut()
5348 .insert(qname, Dom::from_ref(&*result));
5349 result
5350 }
5351
5352 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5354 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5355 .map(Atom::from)
5356 .collect();
5357 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5358 return DomRoot::from_ref(collection);
5359 }
5360 let result = HTMLCollection::by_atomic_class_name(
5361 &self.window,
5362 self.upcast(),
5363 class_atoms.clone(),
5364 can_gc,
5365 );
5366 self.classes_map
5367 .borrow_mut()
5368 .insert(class_atoms, Dom::from_ref(&*result));
5369 result
5370 }
5371
5372 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5374 self.get_element_by_id(&Atom::from(id))
5375 }
5376
5377 fn CreateElement(
5379 &self,
5380 mut local_name: DOMString,
5381 options: StringOrElementCreationOptions,
5382 can_gc: CanGc,
5383 ) -> Fallible<DomRoot<Element>> {
5384 if !is_valid_element_local_name(&local_name.str()) {
5387 debug!("Not a valid element name");
5388 return Err(Error::InvalidCharacter(None));
5389 }
5390
5391 if self.is_html_document {
5392 local_name.make_ascii_lowercase();
5393 }
5394
5395 let ns = if self.is_html_document || self.is_xhtml_document() {
5396 ns!(html)
5397 } else {
5398 ns!()
5399 };
5400
5401 let name = QualName::new(None, ns, LocalName::from(local_name));
5402 let is = match options {
5403 StringOrElementCreationOptions::String(_) => None,
5404 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5405 options.is.as_ref().map(LocalName::from)
5406 },
5407 };
5408 Ok(Element::create(
5409 name,
5410 is,
5411 self,
5412 ElementCreator::ScriptCreated,
5413 CustomElementCreationMode::Synchronous,
5414 None,
5415 can_gc,
5416 ))
5417 }
5418
5419 fn CreateElementNS(
5421 &self,
5422 namespace: Option<DOMString>,
5423 qualified_name: DOMString,
5424 options: StringOrElementCreationOptions,
5425 can_gc: CanGc,
5426 ) -> Fallible<DomRoot<Element>> {
5427 let context = domname::Context::Element;
5430 let (namespace, prefix, local_name) =
5431 domname::validate_and_extract(namespace, &qualified_name, context)?;
5432
5433 let name = QualName::new(prefix, namespace, local_name);
5436 let is = match options {
5437 StringOrElementCreationOptions::String(_) => None,
5438 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5439 options.is.as_ref().map(LocalName::from)
5440 },
5441 };
5442
5443 Ok(Element::create(
5445 name,
5446 is,
5447 self,
5448 ElementCreator::ScriptCreated,
5449 CustomElementCreationMode::Synchronous,
5450 None,
5451 can_gc,
5452 ))
5453 }
5454
5455 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5457 if !is_valid_attribute_local_name(&local_name.str()) {
5460 debug!("Not a valid attribute name");
5461 return Err(Error::InvalidCharacter(None));
5462 }
5463 if self.is_html_document {
5464 local_name.make_ascii_lowercase();
5465 }
5466 let name = LocalName::from(local_name);
5467 let value = AttrValue::String("".to_owned());
5468
5469 Ok(Attr::new(
5470 self,
5471 name.clone(),
5472 value,
5473 name,
5474 ns!(),
5475 None,
5476 None,
5477 can_gc,
5478 ))
5479 }
5480
5481 fn CreateAttributeNS(
5483 &self,
5484 namespace: Option<DOMString>,
5485 qualified_name: DOMString,
5486 can_gc: CanGc,
5487 ) -> Fallible<DomRoot<Attr>> {
5488 let context = domname::Context::Attribute;
5491 let (namespace, prefix, local_name) =
5492 domname::validate_and_extract(namespace, &qualified_name, context)?;
5493 let value = AttrValue::String("".to_owned());
5494 let qualified_name = LocalName::from(qualified_name);
5495 Ok(Attr::new(
5496 self,
5497 local_name,
5498 value,
5499 qualified_name,
5500 namespace,
5501 prefix,
5502 None,
5503 can_gc,
5504 ))
5505 }
5506
5507 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5509 DocumentFragment::new(self, can_gc)
5510 }
5511
5512 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5514 Text::new(data, self, can_gc)
5515 }
5516
5517 fn CreateCDATASection(
5519 &self,
5520 data: DOMString,
5521 can_gc: CanGc,
5522 ) -> Fallible<DomRoot<CDATASection>> {
5523 if self.is_html_document {
5525 return Err(Error::NotSupported(None));
5526 }
5527
5528 if data.contains("]]>") {
5530 return Err(Error::InvalidCharacter(None));
5531 }
5532
5533 Ok(CDATASection::new(data, self, can_gc))
5535 }
5536
5537 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5539 Comment::new(data, self, None, can_gc)
5540 }
5541
5542 fn CreateProcessingInstruction(
5544 &self,
5545 target: DOMString,
5546 data: DOMString,
5547 can_gc: CanGc,
5548 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5549 if !matches_name_production(&target.str()) {
5551 return Err(Error::InvalidCharacter(None));
5552 }
5553
5554 if data.contains("?>") {
5556 return Err(Error::InvalidCharacter(None));
5557 }
5558
5559 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5561 }
5562
5563 fn ImportNode(
5565 &self,
5566 node: &Node,
5567 options: BooleanOrImportNodeOptions,
5568 can_gc: CanGc,
5569 ) -> Fallible<DomRoot<Node>> {
5570 if node.is::<Document>() || node.is::<ShadowRoot>() {
5572 return Err(Error::NotSupported(None));
5573 }
5574 let (subtree, registry) = match options {
5576 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5579 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5581 let subtree = (!options.selfOnly).into();
5583 let registry = options.customElementRegistry;
5585 (subtree, registry)
5589 },
5590 };
5591 let registry = registry
5594 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5595
5596 Ok(Node::clone(node, Some(self), subtree, registry, can_gc))
5599 }
5600
5601 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5603 if node.is::<Document>() {
5605 return Err(Error::NotSupported(None));
5606 }
5607
5608 if node.is::<ShadowRoot>() {
5610 return Err(Error::HierarchyRequest(None));
5611 }
5612
5613 Node::adopt(node, self, can_gc);
5615
5616 Ok(DomRoot::from_ref(node))
5618 }
5619
5620 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5622 interface.make_ascii_lowercase();
5623 match &*interface.str() {
5624 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5625 &self.window,
5626 can_gc,
5627 ))),
5628 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5629 CompositionEvent::new_uninitialized(&self.window, can_gc),
5630 )),
5631 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5632 self.window.upcast(),
5633 can_gc,
5634 ))),
5635 "events" | "event" | "htmlevents" | "svgevents" => {
5638 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5639 },
5640 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5641 &self.window,
5642 can_gc,
5643 ))),
5644 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5645 &self.window,
5646 can_gc,
5647 ))),
5648 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5649 &self.window,
5650 can_gc,
5651 ))),
5652 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5653 self.window.upcast(),
5654 can_gc,
5655 ))),
5656 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5657 &self.window,
5658 can_gc,
5659 ))),
5660 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5661 &self.window,
5662 "".into(),
5663 can_gc,
5664 ))),
5665 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5666 &self.window,
5667 &TouchList::new(&self.window, &[], can_gc),
5668 &TouchList::new(&self.window, &[], can_gc),
5669 &TouchList::new(&self.window, &[], can_gc),
5670 can_gc,
5671 ))),
5672 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5673 &self.window,
5674 can_gc,
5675 ))),
5676 _ => Err(Error::NotSupported(None)),
5677 }
5678 }
5679
5680 fn LastModified(&self) -> DOMString {
5682 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5683 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5689 }))
5690 }
5691
5692 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5694 Range::new_with_doc(self, None, can_gc)
5695 }
5696
5697 fn CreateNodeIterator(
5699 &self,
5700 root: &Node,
5701 what_to_show: u32,
5702 filter: Option<Rc<NodeFilter>>,
5703 can_gc: CanGc,
5704 ) -> DomRoot<NodeIterator> {
5705 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5706 }
5707
5708 fn CreateTreeWalker(
5710 &self,
5711 root: &Node,
5712 what_to_show: u32,
5713 filter: Option<Rc<NodeFilter>>,
5714 ) -> DomRoot<TreeWalker> {
5715 TreeWalker::new(self, root, what_to_show, filter)
5716 }
5717
5718 fn Title(&self) -> DOMString {
5720 self.title().unwrap_or_else(|| DOMString::from(""))
5721 }
5722
5723 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5725 let root = match self.GetDocumentElement() {
5726 Some(root) => root,
5727 None => return,
5728 };
5729
5730 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5731 let elem = root.upcast::<Node>().child_elements().find(|node| {
5732 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5733 });
5734 match elem {
5735 Some(elem) => DomRoot::upcast::<Node>(elem),
5736 None => {
5737 let name = QualName::new(None, ns!(svg), local_name!("title"));
5738 let elem = Element::create(
5739 name,
5740 None,
5741 self,
5742 ElementCreator::ScriptCreated,
5743 CustomElementCreationMode::Synchronous,
5744 None,
5745 can_gc,
5746 );
5747 let parent = root.upcast::<Node>();
5748 let child = elem.upcast::<Node>();
5749 parent
5750 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5751 .unwrap()
5752 },
5753 }
5754 } else if root.namespace() == &ns!(html) {
5755 let elem = root
5756 .upcast::<Node>()
5757 .traverse_preorder(ShadowIncluding::No)
5758 .find(|node| node.is::<HTMLTitleElement>());
5759 match elem {
5760 Some(elem) => elem,
5761 None => match self.GetHead() {
5762 Some(head) => {
5763 let name = QualName::new(None, ns!(html), local_name!("title"));
5764 let elem = Element::create(
5765 name,
5766 None,
5767 self,
5768 ElementCreator::ScriptCreated,
5769 CustomElementCreationMode::Synchronous,
5770 None,
5771 can_gc,
5772 );
5773 head.upcast::<Node>()
5774 .AppendChild(elem.upcast(), can_gc)
5775 .unwrap()
5776 },
5777 None => return,
5778 },
5779 }
5780 } else {
5781 return;
5782 };
5783
5784 node.set_text_content_for_element(Some(title), can_gc);
5785 }
5786
5787 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5789 self.get_html_element()
5790 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5791 }
5792
5793 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5795 self.current_script.get()
5796 }
5797
5798 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5800 self.get_html_element().and_then(|root| {
5801 let node = root.upcast::<Node>();
5802 node.children()
5803 .find(|child| {
5804 matches!(
5805 child.type_id(),
5806 NodeTypeId::Element(ElementTypeId::HTMLElement(
5807 HTMLElementTypeId::HTMLBodyElement,
5808 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5809 HTMLElementTypeId::HTMLFrameSetElement,
5810 ))
5811 )
5812 })
5813 .map(|node| DomRoot::downcast(node).unwrap())
5814 })
5815 }
5816
5817 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5819 let new_body = match new_body {
5821 Some(new_body) => new_body,
5822 None => return Err(Error::HierarchyRequest(None)),
5823 };
5824
5825 let node = new_body.upcast::<Node>();
5826 match node.type_id() {
5827 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5828 NodeTypeId::Element(ElementTypeId::HTMLElement(
5829 HTMLElementTypeId::HTMLFrameSetElement,
5830 )) => {},
5831 _ => return Err(Error::HierarchyRequest(None)),
5832 }
5833
5834 let old_body = self.GetBody();
5836 if old_body.as_deref() == Some(new_body) {
5837 return Ok(());
5838 }
5839
5840 match (self.GetDocumentElement(), &old_body) {
5841 (Some(ref root), Some(child)) => {
5843 let root = root.upcast::<Node>();
5844 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5845 .unwrap();
5846 },
5847
5848 (None, _) => return Err(Error::HierarchyRequest(None)),
5850
5851 (Some(ref root), &None) => {
5853 let root = root.upcast::<Node>();
5854 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5855 },
5856 }
5857 Ok(())
5858 }
5859
5860 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5862 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5863 }
5864
5865 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5867 self.images.or_init(|| {
5868 HTMLCollection::new_with_filter_fn(
5869 &self.window,
5870 self.upcast(),
5871 |element, _| element.is::<HTMLImageElement>(),
5872 can_gc,
5873 )
5874 })
5875 }
5876
5877 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5879 self.embeds.or_init(|| {
5880 HTMLCollection::new_with_filter_fn(
5881 &self.window,
5882 self.upcast(),
5883 |element, _| element.is::<HTMLEmbedElement>(),
5884 can_gc,
5885 )
5886 })
5887 }
5888
5889 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5891 self.Embeds(can_gc)
5892 }
5893
5894 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5896 self.links.or_init(|| {
5897 HTMLCollection::new_with_filter_fn(
5898 &self.window,
5899 self.upcast(),
5900 |element, _| {
5901 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5902 element.has_attribute(&local_name!("href"))
5903 },
5904 can_gc,
5905 )
5906 })
5907 }
5908
5909 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5911 self.forms.or_init(|| {
5912 HTMLCollection::new_with_filter_fn(
5913 &self.window,
5914 self.upcast(),
5915 |element, _| element.is::<HTMLFormElement>(),
5916 can_gc,
5917 )
5918 })
5919 }
5920
5921 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5923 self.scripts.or_init(|| {
5924 HTMLCollection::new_with_filter_fn(
5925 &self.window,
5926 self.upcast(),
5927 |element, _| element.is::<HTMLScriptElement>(),
5928 can_gc,
5929 )
5930 })
5931 }
5932
5933 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5935 self.anchors.or_init(|| {
5936 HTMLCollection::new_with_filter_fn(
5937 &self.window,
5938 self.upcast(),
5939 |element, _| {
5940 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5941 },
5942 can_gc,
5943 )
5944 })
5945 }
5946
5947 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5949 self.applets
5950 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5951 }
5952
5953 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5955 if self.is_fully_active() {
5956 Some(self.window.Location())
5957 } else {
5958 None
5959 }
5960 }
5961
5962 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5964 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5965 }
5966
5967 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5969 self.upcast::<Node>().child_elements().next()
5970 }
5971
5972 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5974 self.upcast::<Node>()
5975 .rev_children()
5976 .find_map(DomRoot::downcast)
5977 }
5978
5979 fn ChildElementCount(&self) -> u32 {
5981 self.upcast::<Node>().child_elements().count() as u32
5982 }
5983
5984 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5986 self.upcast::<Node>().prepend(nodes, can_gc)
5987 }
5988
5989 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5991 self.upcast::<Node>().append(nodes, can_gc)
5992 }
5993
5994 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5996 self.upcast::<Node>().replace_children(nodes, can_gc)
5997 }
5998
5999 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
6001 self.upcast::<Node>().query_selector(selectors)
6002 }
6003
6004 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
6006 self.upcast::<Node>().query_selector_all(selectors)
6007 }
6008
6009 fn ReadyState(&self) -> DocumentReadyState {
6011 self.ready_state.get()
6012 }
6013
6014 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
6016 if self.has_browsing_context {
6017 Some(DomRoot::from_ref(&*self.window))
6018 } else {
6019 None
6020 }
6021 }
6022
6023 fn GetCookie(&self) -> Fallible<DOMString> {
6025 if self.is_cookie_averse() {
6026 return Ok(DOMString::new());
6027 }
6028
6029 if !self.origin.is_tuple() {
6030 return Err(Error::Security(None));
6031 }
6032
6033 let url = self.url();
6034 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
6035 let _ = self
6036 .window
6037 .as_global_scope()
6038 .resource_threads()
6039 .send(GetCookiesForUrl(url, tx, NonHTTP));
6040 let cookies = rx.recv().unwrap();
6041 Ok(cookies.map_or(DOMString::new(), DOMString::from))
6042 }
6043
6044 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
6046 if self.is_cookie_averse() {
6047 return Ok(());
6048 }
6049
6050 if !self.origin.is_tuple() {
6051 return Err(Error::Security(None));
6052 }
6053
6054 if !cookie.is_valid_for_cookie() {
6055 return Ok(());
6056 }
6057
6058 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6059 vec![cookie]
6060 } else {
6061 vec![]
6062 };
6063
6064 let _ = self
6065 .window
6066 .as_global_scope()
6067 .resource_threads()
6068 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6069 Ok(())
6070 }
6071
6072 fn BgColor(&self) -> DOMString {
6074 self.get_body_attribute(&local_name!("bgcolor"))
6075 }
6076
6077 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
6079 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
6080 }
6081
6082 fn FgColor(&self) -> DOMString {
6084 self.get_body_attribute(&local_name!("text"))
6085 }
6086
6087 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
6089 self.set_body_attribute(&local_name!("text"), value, can_gc)
6090 }
6091
6092 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
6094 if name.is_empty() {
6095 return None;
6096 }
6097 let name = Atom::from(name);
6098
6099 let elements_with_name = self.get_elements_with_name(&name);
6102 let name_iter = elements_with_name
6103 .iter()
6104 .filter(|elem| is_named_element_with_name_attribute(elem));
6105 let elements_with_id = self.get_elements_with_id(&name);
6106 let id_iter = elements_with_id
6107 .iter()
6108 .filter(|elem| is_named_element_with_id_attribute(elem));
6109 let mut elements = name_iter.chain(id_iter);
6110
6111 let first = elements.next()?;
6118 if elements.all(|other| first == other) {
6119 if let Some(nested_window_proxy) = first
6120 .downcast::<HTMLIFrameElement>()
6121 .and_then(|iframe| iframe.GetContentWindow())
6122 {
6123 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6124 }
6125
6126 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6128 }
6129
6130 #[derive(JSTraceable, MallocSizeOf)]
6133 struct DocumentNamedGetter {
6134 #[no_trace]
6135 name: Atom,
6136 }
6137 impl CollectionFilter for DocumentNamedGetter {
6138 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6139 let type_ = match elem.upcast::<Node>().type_id() {
6140 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6141 _ => return false,
6142 };
6143 match type_ {
6144 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6145 elem.get_name().as_ref() == Some(&self.name)
6146 },
6147 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6148 name == *self.name ||
6149 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6150 }),
6151 _ => false,
6155 }
6156 }
6157 }
6158 let collection = HTMLCollection::create(
6159 self.window(),
6160 self.upcast(),
6161 Box::new(DocumentNamedGetter { name }),
6162 can_gc,
6163 );
6164 Some(NamedPropertyValue::HTMLCollection(collection))
6165 }
6166
6167 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
6169 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
6170
6171 let name_map = self.name_map.borrow();
6172 for (name, elements) in &(name_map).0 {
6173 if name.is_empty() {
6174 continue;
6175 }
6176 let mut name_iter = elements
6177 .iter()
6178 .filter(|elem| is_named_element_with_name_attribute(elem));
6179 if let Some(first) = name_iter.next() {
6180 names_with_first_named_element_map.insert(name, first);
6181 }
6182 }
6183 let id_map = self.id_map.borrow();
6184 for (id, elements) in &(id_map).0 {
6185 if id.is_empty() {
6186 continue;
6187 }
6188 let mut id_iter = elements
6189 .iter()
6190 .filter(|elem| is_named_element_with_id_attribute(elem));
6191 if let Some(first) = id_iter.next() {
6192 match names_with_first_named_element_map.entry(id) {
6193 Vacant(entry) => drop(entry.insert(first)),
6194 Occupied(mut entry) => {
6195 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6196 *entry.get_mut() = first;
6197 }
6198 },
6199 }
6200 }
6201 }
6202
6203 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
6204 names_with_first_named_element_map
6205 .iter()
6206 .map(|(k, v)| (*k, *v))
6207 .collect();
6208 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6209 if a.1 == b.1 {
6210 a.0.cmp(b.0)
6213 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6214 Ordering::Less
6215 } else {
6216 Ordering::Greater
6217 }
6218 });
6219
6220 names_with_first_named_element_vec
6221 .iter()
6222 .map(|(k, _v)| DOMString::from(&***k))
6223 .collect()
6224 }
6225
6226 fn Clear(&self) {
6228 }
6230
6231 fn CaptureEvents(&self) {
6233 }
6235
6236 fn ReleaseEvents(&self) {
6238 }
6240
6241 global_event_handlers!();
6243
6244 event_handler!(
6246 readystatechange,
6247 GetOnreadystatechange,
6248 SetOnreadystatechange
6249 );
6250
6251 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6253 self.document_or_shadow_root.element_from_point(
6254 x,
6255 y,
6256 self.GetDocumentElement(),
6257 self.has_browsing_context,
6258 )
6259 }
6260
6261 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6263 self.document_or_shadow_root.elements_from_point(
6264 x,
6265 y,
6266 self.GetDocumentElement(),
6267 self.has_browsing_context,
6268 )
6269 }
6270
6271 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6273 if self.quirks_mode() == QuirksMode::Quirks {
6275 if let Some(ref body) = self.GetBody() {
6277 let e = body.upcast::<Element>();
6278 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6282 return Some(DomRoot::from_ref(e));
6283 }
6284 }
6285
6286 return None;
6288 }
6289
6290 self.GetDocumentElement()
6293 }
6294
6295 fn Open(
6297 &self,
6298 cx: &mut js::context::JSContext,
6299 _unused1: Option<DOMString>,
6300 _unused2: Option<DOMString>,
6301 ) -> Fallible<DomRoot<Document>> {
6302 if !self.is_html_document() {
6304 return Err(Error::InvalidState(None));
6305 }
6306
6307 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6309 return Err(Error::InvalidState(None));
6310 }
6311
6312 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6314
6315 if !self.origin.same_origin(&entry_responsible_document.origin) {
6317 return Err(Error::Security(None));
6318 }
6319
6320 if self
6322 .get_current_parser()
6323 .is_some_and(|parser| parser.is_active())
6324 {
6325 return Ok(DomRoot::from_ref(self));
6326 }
6327
6328 if self.is_prompting_or_unloading() {
6330 return Ok(DomRoot::from_ref(self));
6331 }
6332
6333 if self.active_parser_was_aborted.get() {
6335 return Ok(DomRoot::from_ref(self));
6336 }
6337
6338 self.window().set_navigation_start();
6342
6343 if self.has_browsing_context() {
6346 self.abort(cx);
6349 }
6350
6351 for node in self
6353 .upcast::<Node>()
6354 .traverse_preorder(ShadowIncluding::Yes)
6355 {
6356 node.upcast::<EventTarget>().remove_all_listeners();
6357 }
6358
6359 if self.window.Document() == DomRoot::from_ref(self) {
6361 self.window.upcast::<EventTarget>().remove_all_listeners();
6362 }
6363
6364 Node::replace_all(None, self.upcast::<Node>(), CanGc::from_cx(cx));
6366
6367 if self.is_fully_active() {
6374 let mut new_url = entry_responsible_document.url();
6376
6377 if entry_responsible_document != DomRoot::from_ref(self) {
6379 new_url.set_fragment(None);
6380 }
6381
6382 self.set_url(new_url);
6385 }
6386
6387 self.is_initial_about_blank.set(false);
6389
6390 self.set_quirks_mode(QuirksMode::NoQuirks);
6396
6397 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6403 *self.loader.borrow_mut() =
6404 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6405 ServoParser::parse_html_script_input(self, self.url());
6406
6407 self.ready_state.set(DocumentReadyState::Loading);
6413
6414 Ok(DomRoot::from_ref(self))
6416 }
6417
6418 fn Open_(
6420 &self,
6421 cx: &mut js::context::JSContext,
6422 url: USVString,
6423 target: DOMString,
6424 features: DOMString,
6425 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6426 self.browsing_context()
6427 .ok_or(Error::InvalidAccess(None))?
6428 .open(url, target, features, CanGc::from_cx(cx))
6429 }
6430
6431 fn Write(
6433 &self,
6434 cx: &mut js::context::JSContext,
6435 text: Vec<TrustedHTMLOrString>,
6436 ) -> ErrorResult {
6437 self.write(cx, text, false, "Document", "write")
6440 }
6441
6442 fn Writeln(
6444 &self,
6445 cx: &mut js::context::JSContext,
6446 text: Vec<TrustedHTMLOrString>,
6447 ) -> ErrorResult {
6448 self.write(cx, text, true, "Document", "writeln")
6451 }
6452
6453 fn Close(&self, cx: &mut js::context::JSContext) -> ErrorResult {
6455 if !self.is_html_document() {
6456 return Err(Error::InvalidState(None));
6458 }
6459
6460 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6463 return Err(Error::InvalidState(None));
6464 }
6465
6466 let parser = match self.get_current_parser() {
6468 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6469 _ => {
6470 return Ok(());
6471 },
6472 };
6473
6474 parser.close(cx);
6476
6477 Ok(())
6478 }
6479
6480 fn ExecCommand(
6482 &self,
6483 command_id: DOMString,
6484 _show_ui: bool,
6485 value: TrustedHTMLOrString,
6486 can_gc: CanGc,
6487 ) -> Fallible<bool> {
6488 let value = if command_id == "insertHTML" {
6489 TrustedHTML::get_trusted_script_compliant_string(
6490 self.window.as_global_scope(),
6491 value,
6492 "Document execCommand",
6493 can_gc,
6494 )?
6495 } else {
6496 match value {
6497 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6498 TrustedHTMLOrString::String(value) => value,
6499 }
6500 };
6501
6502 Ok(self.exec_command_for_command_id(command_id, value, can_gc))
6503 }
6504
6505 fn QueryCommandEnabled(&self, command_id: DOMString, can_gc: CanGc) -> bool {
6507 self.check_support_and_enabled(command_id, can_gc).is_some()
6509 }
6510
6511 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6513 self.is_command_supported(command_id)
6517 }
6518
6519 fn QueryCommandIndeterm(&self, command_id: DOMString) -> bool {
6521 self.is_command_indeterminate(command_id)
6522 }
6523
6524 fn QueryCommandState(&self, command_id: DOMString) -> bool {
6526 self.command_state_for_command(command_id)
6527 }
6528
6529 fn QueryCommandValue(&self, command_id: DOMString) -> DOMString {
6531 self.command_value_for_command(command_id)
6532 }
6533
6534 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6536
6537 event_handler!(
6539 fullscreenchange,
6540 GetOnfullscreenchange,
6541 SetOnfullscreenchange
6542 );
6543
6544 fn FullscreenEnabled(&self) -> bool {
6546 self.get_allow_fullscreen()
6547 }
6548
6549 fn Fullscreen(&self) -> bool {
6551 self.fullscreen_element.get().is_some()
6552 }
6553
6554 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6556 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6557 }
6558
6559 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6561 self.exit_fullscreen(can_gc)
6562 }
6563
6564 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6568 match self.media_controls.borrow().get(&*id.str()) {
6569 Some(m) => Ok(DomRoot::from_ref(m)),
6570 None => Err(Error::InvalidAccess(None)),
6571 }
6572 }
6573
6574 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6576 if self.has_browsing_context {
6577 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6578 } else {
6579 None
6580 }
6581 }
6582
6583 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6585 self.fonts
6586 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6587 }
6588
6589 fn Hidden(&self) -> bool {
6591 self.visibility_state.get() == DocumentVisibilityState::Hidden
6592 }
6593
6594 fn VisibilityState(&self) -> DocumentVisibilityState {
6596 self.visibility_state.get()
6597 }
6598
6599 fn CreateExpression(
6600 &self,
6601 expression: DOMString,
6602 resolver: Option<Rc<XPathNSResolver>>,
6603 can_gc: CanGc,
6604 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6605 let parsed_expression =
6606 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6607 Ok(XPathExpression::new(
6608 &self.window,
6609 None,
6610 can_gc,
6611 parsed_expression,
6612 ))
6613 }
6614
6615 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6616 let global = self.global();
6617 let window = global.as_window();
6618 let evaluator = XPathEvaluator::new(window, None, can_gc);
6619 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6620 }
6621
6622 fn Evaluate(
6623 &self,
6624 expression: DOMString,
6625 context_node: &Node,
6626 resolver: Option<Rc<XPathNSResolver>>,
6627 result_type: u16,
6628 result: Option<&super::types::XPathResult>,
6629 can_gc: CanGc,
6630 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6631 let parsed_expression =
6632 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6633 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6634 context_node,
6635 result_type,
6636 result,
6637 can_gc,
6638 )
6639 }
6640
6641 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6643 self.adopted_stylesheets_frozen_types.get_or_init(
6644 || {
6645 self.adopted_stylesheets
6646 .borrow()
6647 .clone()
6648 .iter()
6649 .map(|sheet| sheet.as_rooted())
6650 .collect()
6651 },
6652 context,
6653 retval,
6654 can_gc,
6655 );
6656 }
6657
6658 fn SetAdoptedStyleSheets(
6660 &self,
6661 context: JSContext,
6662 val: HandleValue,
6663 can_gc: CanGc,
6664 ) -> ErrorResult {
6665 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6666 context,
6667 self.adopted_stylesheets.borrow_mut().as_mut(),
6668 val,
6669 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6670 can_gc,
6671 );
6672
6673 if result.is_ok() {
6675 self.adopted_stylesheets_frozen_types.clear()
6676 }
6677
6678 result
6679 }
6680}
6681
6682fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6683 if marker.get().is_none() {
6684 marker.set(Some(CrossProcessInstant::now()))
6685 }
6686}
6687
6688#[derive(Clone, Copy, PartialEq)]
6690pub(crate) enum FocusType {
6691 Element, Parent, }
6694
6695#[derive(Clone, Copy, PartialEq)]
6697pub enum FocusInitiator {
6698 Keyboard,
6701 Click,
6704 Script,
6707 Remote,
6710}
6711
6712pub(crate) enum FocusEventType {
6714 Focus, Blur, }
6717
6718#[derive(JSTraceable, MallocSizeOf)]
6719pub(crate) enum AnimationFrameCallback {
6720 DevtoolsFramerateTick {
6721 actor_name: String,
6722 },
6723 FrameRequestCallback {
6724 #[conditional_malloc_size_of]
6725 callback: Rc<FrameRequestCallback>,
6726 },
6727}
6728
6729impl AnimationFrameCallback {
6730 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6731 match *self {
6732 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6733 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6734 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6735 devtools_sender.send(msg).unwrap();
6736 },
6737 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6738 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6741 },
6742 }
6743 }
6744}
6745
6746#[derive(Default, JSTraceable, MallocSizeOf)]
6747#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6748struct PendingInOrderScriptVec {
6749 scripts: DomRefCell<VecDeque<PendingScript>>,
6750}
6751
6752impl PendingInOrderScriptVec {
6753 fn is_empty(&self) -> bool {
6754 self.scripts.borrow().is_empty()
6755 }
6756
6757 fn push(&self, element: &HTMLScriptElement) {
6758 self.scripts
6759 .borrow_mut()
6760 .push_back(PendingScript::new(element));
6761 }
6762
6763 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6764 let mut scripts = self.scripts.borrow_mut();
6765 let entry = scripts
6766 .iter_mut()
6767 .find(|entry| &*entry.element == element)
6768 .unwrap();
6769 entry.loaded(result);
6770 }
6771
6772 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6773 let mut scripts = self.scripts.borrow_mut();
6774 let pair = scripts.front_mut()?.take_result()?;
6775 scripts.pop_front();
6776 Some(pair)
6777 }
6778
6779 fn clear(&self) {
6780 *self.scripts.borrow_mut() = Default::default();
6781 }
6782}
6783
6784#[derive(JSTraceable, MallocSizeOf)]
6785#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6786struct PendingScript {
6787 element: Dom<HTMLScriptElement>,
6788 load: Option<ScriptResult>,
6790}
6791
6792impl PendingScript {
6793 fn new(element: &HTMLScriptElement) -> Self {
6794 Self {
6795 element: Dom::from_ref(element),
6796 load: None,
6797 }
6798 }
6799
6800 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6801 Self {
6802 element: Dom::from_ref(element),
6803 load,
6804 }
6805 }
6806
6807 fn loaded(&mut self, result: ScriptResult) {
6808 assert!(self.load.is_none());
6809 self.load = Some(result);
6810 }
6811
6812 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6813 self.load
6814 .take()
6815 .map(|result| (DomRoot::from_ref(&*self.element), result))
6816 }
6817}
6818
6819fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6820 let type_ = match elem.upcast::<Node>().type_id() {
6821 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6822 _ => return false,
6823 };
6824 match type_ {
6825 HTMLElementTypeId::HTMLFormElement |
6826 HTMLElementTypeId::HTMLIFrameElement |
6827 HTMLElementTypeId::HTMLImageElement => true,
6828 _ => false,
6832 }
6833}
6834
6835fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6836 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6840}
6841
6842impl DocumentHelpers for Document {
6843 fn ensure_safe_to_run_script_or_layout(&self) {
6844 Document::ensure_safe_to_run_script_or_layout(self)
6845 }
6846}
6847
6848pub(crate) struct SameoriginAncestorNavigablesIterator {
6852 document: DomRoot<Document>,
6853}
6854
6855impl SameoriginAncestorNavigablesIterator {
6856 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6857 Self { document }
6858 }
6859}
6860
6861impl Iterator for SameoriginAncestorNavigablesIterator {
6862 type Item = DomRoot<Document>;
6863
6864 fn next(&mut self) -> Option<Self::Item> {
6865 let window_proxy = self.document.browsing_context()?;
6866 self.document = window_proxy.parent()?.document()?;
6867 Some(self.document.clone())
6868 }
6869}
6870
6871pub(crate) struct SameOriginDescendantNavigablesIterator {
6876 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6877}
6878
6879impl SameOriginDescendantNavigablesIterator {
6880 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6881 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6882 Self {
6883 stack: vec![Box::new(iframes.into_iter())],
6884 }
6885 }
6886
6887 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6888 let mut cur_iframe = self.stack.last_mut()?.next();
6889 while cur_iframe.is_none() {
6890 self.stack.pop();
6891 cur_iframe = self.stack.last_mut()?.next();
6892 }
6893 cur_iframe
6894 }
6895}
6896
6897impl Iterator for SameOriginDescendantNavigablesIterator {
6898 type Item = DomRoot<Document>;
6899
6900 fn next(&mut self) -> Option<Self::Item> {
6901 while let Some(iframe) = self.get_next_iframe() {
6902 let Some(pipeline_id) = iframe.pipeline_id() else {
6903 continue;
6904 };
6905
6906 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6907 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6908 document.iframes().iter().collect();
6909 self.stack.push(Box::new(child_iframes.into_iter()));
6910 return Some(document);
6911 } else {
6912 continue;
6913 };
6914 }
6915 None
6916 }
6917}