1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use bitflags::bitflags;
17use chrono::Local;
18use content_security_policy::sandboxing_directive::SandboxingFlagSet;
19use content_security_policy::{CspList, Policy as CspPolicy, PolicyDisposition};
20use cookie::Cookie;
21use data_url::mime::Mime;
22use devtools_traits::ScriptToDevtoolsControlMsg;
23use dom_struct::dom_struct;
24use embedder_traits::{
25 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, Image, LoadStatus,
26};
27use encoding_rs::{Encoding, UTF_8};
28use html5ever::{LocalName, Namespace, QualName, local_name, ns};
29use hyper_serde::Serde;
30use js::context::{JSContext, NoGC};
31use js::realm::CurrentRealm;
32use js::rust::{HandleObject, HandleValue, MutableHandleValue};
33use layout_api::{
34 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
35 ScrollContainerQueryFlags, TrustedNodeAddress,
36};
37use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
38use net_traits::CookieSource::NonHTTP;
39use net_traits::CoreResourceMsg::{GetCookieStringForUrl, SetCookiesForUrl};
40use net_traits::policy_container::PolicyContainer;
41use net_traits::pub_domains::is_pub_domain;
42use net_traits::request::{
43 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
44};
45use net_traits::{ReferrerPolicy, ResourceFetchTiming};
46use percent_encoding::percent_decode;
47use profile_traits::generic_channel as profile_generic_channel;
48use profile_traits::time::TimerMetadataFrameType;
49use regex::bytes::Regex;
50use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
51use script_bindings::cell::{DomRefCell, Ref, RefMut};
52use script_bindings::interfaces::DocumentHelpers;
53use script_bindings::reflector::reflect_dom_object_with_proto;
54use script_traits::{DocumentActivity, ProgressiveWebMetricType};
55use servo_arc::Arc;
56use servo_base::cross_process_instant::CrossProcessInstant;
57use servo_base::generic_channel::GenericSend;
58use servo_base::id::WebViewId;
59use servo_base::{Epoch, generic_channel};
60use servo_config::pref;
61use servo_constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
62use servo_media::{ClientContextId, ServoMedia};
63use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
64use style::attr::AttrValue;
65use style::context::QuirksMode;
66use style::dom::OpaqueNode;
67use style::invalidation::element::restyle_hints::RestyleHint;
68use style::selector_parser::Snapshot;
69use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
70use style::str::{split_html_space_chars, str_join};
71use style::stylesheet_set::DocumentStylesheetSet;
72use style::stylesheets::{Origin, OriginSet, Stylesheet};
73use style::stylist::Stylist;
74use stylo_atoms::Atom;
75use time::Duration as TimeDuration;
76use url::{Host, Position};
77
78use crate::animations::Animations;
79use crate::document_loader::{DocumentLoader, LoadType};
80use crate::dom::animationtimeline::AnimationTimeline;
81use crate::dom::attr::Attr;
82use crate::dom::beforeunloadevent::BeforeUnloadEvent;
83use crate::dom::bindings::callback::ExceptionHandling;
84use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
85use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
86 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
87};
88use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
89use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
90use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
91#[cfg(any(feature = "webxr", feature = "gamepad"))]
92use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
93use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
94use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
95use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
96use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
97use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
98 SetHTMLOptions, SetHTMLUnsafeOptions,
99};
100use crate::dom::bindings::codegen::Bindings::WindowBinding::{
101 FrameRequestCallback, ScrollBehavior, WindowMethods,
102};
103use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
104use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
105use crate::dom::bindings::codegen::UnionTypes::{
106 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
107};
108use crate::dom::bindings::domname::{
109 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
110};
111use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
112use crate::dom::bindings::frozenarray::CachedFrozenArray;
113use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
114use crate::dom::bindings::num::Finite;
115use crate::dom::bindings::refcounted::Trusted;
116use crate::dom::bindings::reflector::DomGlobal;
117use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout, UnrootedDom};
118use crate::dom::bindings::str::{DOMString, USVString};
119use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
120use crate::dom::bindings::weakref::DOMTracker;
121use crate::dom::bindings::xmlname::matches_name_production;
122use crate::dom::cdatasection::CDATASection;
123use crate::dom::comment::Comment;
124use crate::dom::compositionevent::CompositionEvent;
125use crate::dom::css::cssstylesheet::CSSStyleSheet;
126use crate::dom::css::fontfaceset::FontFaceSet;
127use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
128use crate::dom::customelementregistry::{
129 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
130};
131use crate::dom::customevent::CustomEvent;
132use crate::dom::document::accessibility_data::AccessibilityData;
133use crate::dom::document::focus::{DocumentFocusHandler, FocusableArea};
134use crate::dom::document_embedder_controls::DocumentEmbedderControls;
135use crate::dom::document_event_handler::DocumentEventHandler;
136use crate::dom::documentfragment::DocumentFragment;
137use crate::dom::documentorshadowroot::{
138 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
139};
140use crate::dom::documenttimeline::DocumentTimeline;
141use crate::dom::documenttype::DocumentType;
142use crate::dom::domimplementation::DOMImplementation;
143use crate::dom::element::attributes::storage::AttrRef;
144use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
145use crate::dom::event::{Event, EventBubbles, EventCancelable};
146use crate::dom::eventtarget::EventTarget;
147use crate::dom::execcommand::basecommand::{CommandName, DefaultSingleLineContainerName};
148use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
149use crate::dom::focusevent::FocusEvent;
150use crate::dom::globalscope::GlobalScope;
151use crate::dom::hashchangeevent::HashChangeEvent;
152use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
153use crate::dom::html::htmlareaelement::HTMLAreaElement;
154use crate::dom::html::htmlbaseelement::HTMLBaseElement;
155use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
156use crate::dom::html::htmlelement::HTMLElement;
157use crate::dom::html::htmlembedelement::HTMLEmbedElement;
158use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
159use crate::dom::html::htmlheadelement::HTMLHeadElement;
160use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
161use crate::dom::html::htmliframeelement::HTMLIFrameElement;
162use crate::dom::html::htmlimageelement::HTMLImageElement;
163use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
164use crate::dom::html::htmltitleelement::HTMLTitleElement;
165use crate::dom::htmldetailselement::DetailsNameGroups;
166use crate::dom::intersectionobserver::IntersectionObserver;
167use crate::dom::iterators::ShadowIncluding;
168use crate::dom::keyboardevent::KeyboardEvent;
169use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
170use crate::dom::location::Location;
171use crate::dom::messageevent::MessageEvent;
172use crate::dom::mouseevent::MouseEvent;
173use crate::dom::node::treewalker::TreeWalker;
174use crate::dom::node::virtualmethods::vtable_for;
175use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits};
176use crate::dom::nodeiterator::NodeIterator;
177use crate::dom::nodelist::NodeList;
178use crate::dom::pagetransitionevent::PageTransitionEvent;
179use crate::dom::performance::performanceentry::PerformanceEntry;
180use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
181use crate::dom::processinginstruction::ProcessingInstruction;
182use crate::dom::promise::Promise;
183use crate::dom::range::Range;
184use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
185use crate::dom::sanitizer::Sanitizer;
186use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
187use crate::dom::selection::Selection;
188use crate::dom::servoparser::ServoParser;
189use crate::dom::shadowroot::ShadowRoot;
190use crate::dom::storageevent::StorageEvent;
191use crate::dom::text::Text;
192use crate::dom::touchevent::TouchEvent as DomTouchEvent;
193use crate::dom::touchlist::TouchList;
194use crate::dom::tree_ordered_index_map::TreeOrderedIndexMap;
195use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
196use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
197use crate::dom::uievent::UIEvent;
198use crate::dom::websocket::WebSocket;
199use crate::dom::window::Window;
200use crate::dom::windowproxy::WindowProxy;
201use crate::dom::xpathevaluator::XPathEvaluator;
202use crate::dom::xpathexpression::XPathExpression;
203use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
204use crate::iframe_collection::IFrameCollection;
205use crate::image_animation::ImageAnimationManager;
206use crate::mime::{APPLICATION, CHARSET};
207use crate::navigation::navigate;
208use crate::network_listener::{FetchResponseListener, NetworkListener};
209use crate::script_runtime::CanGc;
210use crate::script_thread::{ScriptThread, SharedRwLocks};
211use crate::stylesheet_set::StylesheetSetRef;
212use crate::task::NonSendTaskBox;
213use crate::task_source::TaskSourceName;
214use crate::timers::OneshotTimerCallback;
215use crate::xpath::parse_expression;
216
217#[derive(Clone, Copy, PartialEq)]
218pub(crate) enum FireMouseEventType {
219 Move,
220 Over,
221 Out,
222 Enter,
223 Leave,
224}
225
226impl FireMouseEventType {
227 pub(crate) fn as_str(&self) -> &str {
228 match *self {
229 FireMouseEventType::Move => "mousemove",
230 FireMouseEventType::Over => "mouseover",
231 FireMouseEventType::Out => "mouseout",
232 FireMouseEventType::Enter => "mouseenter",
233 FireMouseEventType::Leave => "mouseleave",
234 }
235 }
236}
237
238#[derive(JSTraceable, MallocSizeOf)]
239pub(crate) struct RefreshRedirectDue {
240 #[no_trace]
241 pub(crate) url: ServoUrl,
242 #[ignore_malloc_size_of = "non-owning"]
243 pub(crate) window: DomRoot<Window>,
244 pub(crate) from_meta_element: bool,
246}
247impl RefreshRedirectDue {
248 pub(crate) fn invoke(self, cx: &mut JSContext) {
250 if self.from_meta_element &&
257 self.window.Document().has_active_sandboxing_flag(
258 SandboxingFlagSet::SANDBOXED_AUTOMATIC_FEATURES_BROWSING_CONTEXT_FLAG,
259 )
260 {
261 return;
262 }
263 let load_data = self
264 .window
265 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
266 navigate(
267 cx,
268 &self.window,
269 NavigationHistoryBehavior::Replace,
270 false,
271 load_data,
272 );
273 }
274}
275
276#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
277pub(crate) enum IsHTMLDocument {
278 HTMLDocument,
279 NonHTMLDocument,
280}
281
282#[derive(JSTraceable, MallocSizeOf)]
284pub(crate) enum DeclarativeRefresh {
285 PendingLoad {
286 #[no_trace]
287 url: ServoUrl,
288 time: u64,
289 from_meta_element: bool,
291 },
292 CreatedAfterLoad,
293}
294
295#[derive(JSTraceable, MallocSizeOf, PartialEq)]
296#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
297struct PendingScrollEvent {
298 target: Dom<EventTarget>,
300 #[no_trace]
302 event: Atom,
303}
304
305impl PendingScrollEvent {
306 fn equivalent(&self, target: &EventTarget, event: &Atom) -> bool {
307 &*self.target == target && self.event == *event
308 }
309}
310
311#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
314pub(crate) struct RenderingUpdateReason(u8);
315
316bitflags! {
317 impl RenderingUpdateReason: u8 {
318 const ResizeObserverStartedObservingTarget = 1 << 0;
321 const IntersectionObserverStartedObservingTarget = 1 << 1;
324 const FontReadyPromiseFulfilled = 1 << 2;
328 }
329}
330
331#[derive(Clone, Debug, Default, MallocSizeOf)]
333pub(crate) struct NavigationTiming {
334 pub(crate) unload_event_start: Cell<Option<CrossProcessInstant>>,
336 pub(crate) unload_event_end: Cell<Option<CrossProcessInstant>>,
338 pub(crate) dom_interactive: Cell<Option<CrossProcessInstant>>,
340 pub(crate) dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
342 pub(crate) dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
344 pub(crate) dom_complete: Cell<Option<CrossProcessInstant>>,
346 pub(crate) load_event_start: Cell<Option<CrossProcessInstant>>,
348 pub(crate) load_event_end: Cell<Option<CrossProcessInstant>>,
350 pub(crate) top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
352}
353
354#[dom_struct]
356pub(crate) struct Document {
357 node: Node,
358 document_or_shadow_root: DocumentOrShadowRoot,
359 window: Dom<Window>,
360 implementation: MutNullableDom<DOMImplementation>,
361 #[ignore_malloc_size_of = "type from external crate"]
362 #[no_trace]
363 content_type: Mime,
364 last_modified: Option<String>,
365 #[no_trace]
366 encoding: Cell<&'static Encoding>,
367 has_browsing_context: bool,
368 is_html_document: bool,
369 #[no_trace]
370 activity: Cell<DocumentActivity>,
371 #[no_trace]
373 url: DomRefCell<ServoUrl>,
374 #[no_trace]
376 about_base_url: DomRefCell<Option<ServoUrl>>,
377 #[ignore_malloc_size_of = "defined in selectors"]
378 #[no_trace]
379 quirks_mode: Cell<QuirksMode>,
380 event_handler: DocumentEventHandler,
382 focus_handler: DocumentFocusHandler,
384 embedder_controls: DocumentEmbedderControls,
386 id_map: TreeOrderedIndexMap,
387 name_map: TreeOrderedIndexMap,
388 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
389 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
390 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
391 images: MutNullableDom<HTMLCollection>,
392 embeds: MutNullableDom<HTMLCollection>,
393 links: MutNullableDom<HTMLCollection>,
394 forms: MutNullableDom<HTMLCollection>,
395 scripts: MutNullableDom<HTMLCollection>,
396 anchors: MutNullableDom<HTMLCollection>,
397 applets: MutNullableDom<HTMLCollection>,
398 iframes: RefCell<IFrameCollection>,
400 #[no_trace]
404 shared_style_locks: SharedRwLocks,
405 #[custom_trace]
407 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
408 stylesheet_list: MutNullableDom<StyleSheetList>,
409 ready_state: Cell<DocumentReadyState>,
410 domcontentloaded_dispatched: Cell<bool>,
412 current_script: MutNullableDom<HTMLScriptElement>,
414 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
416 script_blocking_stylesheets_count: Cell<u32>,
418 render_blocking_element_count: Cell<u32>,
421 deferred_scripts: PendingInOrderScriptVec,
423 asap_in_order_scripts_list: PendingInOrderScriptVec,
425 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
427 animation_frame_ident: Cell<u32>,
430 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
433 running_animation_callbacks: Cell<bool>,
438 loader: DomRefCell<DocumentLoader>,
440 current_parser: MutNullableDom<ServoParser>,
442 base_element: MutNullableDom<HTMLBaseElement>,
444 target_base_element: MutNullableDom<HTMLBaseElement>,
446 appropriate_template_contents_owner_document: MutNullableDom<Document>,
449 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
452 #[no_trace]
456 needs_restyle: Cell<RestyleReason>,
457 #[no_trace]
459 origin: DomRefCell<MutableOrigin>,
460 referrer: Option<String>,
462 target_element: MutNullableDom<Element>,
464 #[no_trace]
466 policy_container: DomRefCell<PolicyContainer>,
467 #[no_trace]
469 preloaded_resources: DomRefCell<PreloadedResources>,
470 ignore_destructive_writes_counter: Cell<u32>,
472 ignore_opens_during_unload_counter: Cell<u32>,
474 spurious_animation_frames: Cell<u8>,
478
479 fullscreen_element: MutNullableDom<Element>,
481 form_id_listener_map:
488 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
489 #[no_trace]
490 interactive_time: DomRefCell<ProgressiveWebMetrics>,
491 #[no_trace]
492 tti_window: DomRefCell<InteractiveWindow>,
493 canceller: FetchCanceller,
495 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
497 page_showing: Cell<bool>,
499 salvageable: Cell<bool>,
501 active_parser_was_aborted: Cell<bool>,
503 fired_unload: Cell<bool>,
505 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
507
508 #[no_trace]
510 navigation_timing: NavigationTiming,
511
512 #[no_trace]
514 resource_fetch_timing: RefCell<Option<ResourceFetchTiming>>,
515
516 script_and_layout_blockers: Cell<u32>,
518 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
520 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
521 completely_loaded: Cell<bool>,
523 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
525 shadow_roots_styles_changed: Cell<bool>,
527 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
533 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
536 has_pending_animated_image_update: Cell<bool>,
538 selection: MutNullableDom<Selection>,
540 timeline: Dom<DocumentTimeline>,
543 animations: Animations,
545 image_animation_manager: DomRefCell<ImageAnimationManager>,
547 dirty_root: MutNullableDom<Element>,
549 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
551 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
560 fonts: MutNullableDom<FontFaceSet>,
563 visibility_state: Cell<DocumentVisibilityState>,
565 status_code: Option<u16>,
567 is_initial_about_blank: Cell<bool>,
569 allow_declarative_shadow_roots: Cell<bool>,
571 #[no_trace]
573 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
574 has_trustworthy_ancestor_origin: Cell<bool>,
576 intersection_observer_task_queued: Cell<bool>,
578 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
590 highlighted_dom_node: MutNullableDom<Node>,
592 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
595 #[ignore_malloc_size_of = "mozjs"]
597 adopted_stylesheets_frozen_types: CachedFrozenArray,
598 pending_scroll_events: DomRefCell<Vec<PendingScrollEvent>>,
602 rendering_update_reasons: Cell<RenderingUpdateReason>,
604 waiting_on_canvas_image_updates: Cell<bool>,
608 root_removal_noted: Cell<bool>,
610 #[no_trace]
618 current_rendering_epoch: Cell<Epoch>,
619 #[conditional_malloc_size_of]
621 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
622 #[no_trace]
623 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
625 #[no_trace]
626 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
633 #[no_trace]
635 favicon: RefCell<Option<Image>>,
636
637 websockets: DOMTracker<WebSocket>,
639
640 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
642
643 #[no_trace]
645 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
646
647 layout_animations_test_enabled: bool,
649
650 #[no_trace]
652 state_override: DomRefCell<FxHashMap<CommandName, bool>>,
653
654 #[no_trace]
656 value_override: DomRefCell<FxHashMap<CommandName, DOMString>>,
657
658 #[no_trace]
660 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
661
662 css_styling_flag: Cell<bool>,
664
665 accessibility_data: DomRefCell<AccessibilityData>,
667}
668
669impl Document {
670 fn unloading_cleanup_steps(&self) {
672 if self.close_outstanding_websockets() {
675 self.salvageable.set(false);
677 }
678
679 if !self.salvageable.get() {
684 let global_scope = self.window.as_global_scope();
685
686 global_scope.close_event_sources();
688
689 let msg = ScriptToConstellationMessage::DiscardDocument;
694 let _ = global_scope.script_to_constellation_chan().send(msg);
695 }
696 }
697
698 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
699 self.websockets.track(websocket);
700 }
701
702 fn close_outstanding_websockets(&self) -> bool {
703 let mut closed_any_websocket = false;
704 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
705 if websocket.make_disappear() {
706 closed_any_websocket = true;
707 }
708 });
709 closed_any_websocket
710 }
711
712 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
713 debug_assert!(*node.owner_doc() == *self);
714 if !node.is_connected() {
715 return;
716 }
717
718 let parent = match node.parent_in_flat_tree() {
719 Some(parent) => parent,
720 None => {
721 let Some(document_element) = self.GetDocumentElement() else {
724 if !self.root_removal_noted.get() {
726 self.add_restyle_reason(RestyleReason::DOMChanged);
727 self.root_removal_noted.set(true);
728 }
729 return;
730 };
731 self.root_removal_noted.set(false);
734
735 if let Some(dirty_root) = self.dirty_root.get() &&
736 dirty_root.is_connected()
737 {
738 for ancestor in dirty_root
741 .upcast::<Node>()
742 .inclusive_ancestors_in_flat_tree()
743 {
744 if ancestor.is::<Element>() {
745 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
746 }
747 }
748 }
749 self.dirty_root.set(Some(&document_element));
750 return;
751 },
752 };
753
754 if let Some(parent_element) = parent.downcast::<Element>() {
755 if !parent_element.is_styled() {
756 return;
757 }
758 if parent_element.is_display_none() {
759 return;
760 }
761 }
762
763 let element_parent: DomRoot<Element>;
764 let element = match node.downcast::<Element>() {
765 Some(element) => element,
766 None => {
767 match DomRoot::downcast::<Element>(parent) {
770 Some(parent) => {
771 element_parent = parent;
772 &element_parent
773 },
774 None => {
775 return;
779 },
780 }
781 },
782 };
783
784 let dirty_root = match self.dirty_root.get() {
785 Some(root) if root.is_connected() => root,
786 _ => {
787 element
788 .upcast::<Node>()
789 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
790 self.dirty_root.set(Some(element));
791 return;
792 },
793 };
794
795 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
796 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
797 return;
798 }
799
800 if ancestor.is::<Element>() {
801 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
802 }
803 }
804
805 let new_dirty_root = element
806 .upcast::<Node>()
807 .common_ancestor_in_flat_tree(dirty_root.upcast())
808 .expect("Couldn't find common ancestor");
809
810 let mut has_dirty_descendants = true;
811 for ancestor in dirty_root
812 .upcast::<Node>()
813 .inclusive_ancestors_in_flat_tree()
814 {
815 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
816 has_dirty_descendants &= *ancestor != *new_dirty_root;
817 }
818
819 self.dirty_root
820 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
821 }
822
823 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
824 self.dirty_root.take()
825 }
826
827 #[inline]
828 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
829 self.loader.borrow()
830 }
831
832 #[inline]
833 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
834 self.loader.borrow_mut()
835 }
836
837 #[inline]
838 pub(crate) fn has_browsing_context(&self) -> bool {
839 self.has_browsing_context
840 }
841
842 #[inline]
844 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
845 if self.has_browsing_context {
846 self.window.undiscarded_window_proxy()
847 } else {
848 None
849 }
850 }
851
852 pub(crate) fn webview_id(&self) -> WebViewId {
853 self.window.webview_id()
854 }
855
856 #[inline]
857 pub(crate) fn window(&self) -> &Window {
858 &self.window
859 }
860
861 #[inline]
862 pub(crate) fn is_html_document(&self) -> bool {
863 self.is_html_document
864 }
865
866 pub(crate) fn is_xhtml_document(&self) -> bool {
867 self.content_type.matches(APPLICATION, "xhtml+xml")
868 }
869
870 pub(crate) fn is_fully_active(&self) -> bool {
871 self.activity.get() == DocumentActivity::FullyActive
872 }
873
874 pub(crate) fn is_active(&self) -> bool {
875 self.activity.get() != DocumentActivity::Inactive
876 }
877
878 #[inline]
879 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
880 self.current_rendering_epoch.get()
881 }
882
883 pub(crate) fn set_activity(&self, cx: &mut JSContext, activity: DocumentActivity) {
884 assert!(self.has_browsing_context);
886 if activity == self.activity.get() {
887 return;
888 }
889
890 self.activity.set(activity);
892 let media = ServoMedia::get();
893 let pipeline_id = self.window().pipeline_id();
894 let client_context_id =
895 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
896
897 if activity != DocumentActivity::FullyActive {
898 self.window().suspend(cx);
899 media.suspend(&client_context_id);
900 return;
901 }
902
903 self.title_changed();
904 self.notify_embedder_favicon();
905 self.dirty_all_nodes();
906 self.window().resume(CanGc::from_cx(cx));
907 media.resume(&client_context_id);
908
909 if self.ready_state.get() != DocumentReadyState::Complete {
910 return;
911 }
912
913 let document = Trusted::new(self);
917 self.owner_global()
918 .task_manager()
919 .dom_manipulation_task_source()
920 .queue(task!(fire_pageshow_event: move |cx| {
921 let document = document.root();
922 let window = document.window();
923 if document.page_showing.get() {
925 return;
926 }
927 document.page_showing.set(true);
929 document.update_visibility_state(cx, DocumentVisibilityState::Visible);
931 let event = PageTransitionEvent::new(
934 cx,
935 window,
936 atom!("pageshow"),
937 false, false, true, );
941 let event = event.upcast::<Event>();
942 event.set_trusted(true);
943 window.dispatch_event_with_target_override(cx, event);
944 }))
945 }
946
947 pub(crate) fn origin(&self) -> Ref<'_, MutableOrigin> {
948 self.origin.borrow()
949 }
950
951 pub(crate) fn mark_as_internal(&self) {
954 *self.origin.borrow_mut() = MutableOrigin::new(ImmutableOrigin::new_opaque());
955 }
956
957 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
958 *self.protocol_handler_automation_mode.borrow_mut() = mode;
959 }
960
961 pub(crate) fn url(&self) -> ServoUrl {
963 self.url.borrow().clone()
964 }
965
966 pub(crate) fn set_url(&self, url: ServoUrl) {
967 *self.url.borrow_mut() = url;
968 }
969
970 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
971 self.about_base_url.borrow().clone()
972 }
973
974 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
975 *self.about_base_url.borrow_mut() = about_base_url;
976 }
977
978 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
980 let document_url = self.url();
981 if document_url.as_str() == "about:srcdoc" {
983 return self
986 .about_base_url()
987 .expect("about:srcdoc page should always have an about base URL");
988 }
989
990 if document_url.matches_about_blank() &&
993 let Some(about_base_url) = self.about_base_url()
994 {
995 return about_base_url;
996 }
997
998 document_url
1000 }
1001
1002 pub(crate) fn base_url(&self) -> ServoUrl {
1004 match self.base_element() {
1005 None => self.fallback_base_url(),
1007 Some(base) => base.frozen_base_url(),
1009 }
1010 }
1011
1012 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
1013 self.needs_restyle.set(self.needs_restyle.get() | reason)
1014 }
1015
1016 pub(crate) fn clear_restyle_reasons(&self) {
1017 self.needs_restyle.set(RestyleReason::empty());
1018 }
1019
1020 pub(crate) fn restyle_reason(&self) -> RestyleReason {
1021 let mut condition = self.needs_restyle.get();
1022 if self.stylesheets.borrow().has_changed() {
1023 condition.insert(RestyleReason::StylesheetsChanged);
1024 }
1025
1026 if let Some(root) = self.GetDocumentElement() &&
1030 root.upcast::<Node>().has_dirty_descendants()
1031 {
1032 condition.insert(RestyleReason::DOMChanged);
1033 }
1034
1035 if !self.pending_restyles.borrow().is_empty() {
1036 condition.insert(RestyleReason::PendingRestyles);
1037 }
1038
1039 condition
1040 }
1041
1042 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1044 self.base_element.get()
1045 }
1046
1047 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1049 self.target_base_element.get()
1050 }
1051
1052 pub(crate) fn refresh_base_element(&self) {
1054 if let Some(base_element) = self.base_element.get() {
1055 base_element.clear_frozen_base_url();
1056 }
1057 let new_base_element = self
1058 .upcast::<Node>()
1059 .traverse_preorder(ShadowIncluding::No)
1060 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1061 .find(|element| {
1062 element
1063 .upcast::<Element>()
1064 .has_attribute(&local_name!("href"))
1065 });
1066 if let Some(ref new_base_element) = new_base_element {
1067 new_base_element.set_frozen_base_url();
1068 }
1069 self.base_element.set(new_base_element.as_deref());
1070
1071 let new_target_base_element = self
1072 .upcast::<Node>()
1073 .traverse_preorder(ShadowIncluding::No)
1074 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1075 .next();
1076 self.target_base_element
1077 .set(new_target_base_element.as_deref());
1078 }
1079
1080 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1081 self.quirks_mode.get()
1082 }
1083
1084 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1085 let old_mode = self.quirks_mode.replace(new_mode);
1086
1087 if old_mode != new_mode {
1088 self.window.layout_mut().set_quirks_mode(new_mode);
1089 }
1090 }
1091
1092 pub(crate) fn encoding(&self) -> &'static Encoding {
1093 self.encoding.get()
1094 }
1095
1096 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1097 self.encoding.set(encoding);
1098 }
1099
1100 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1101 if node.is_connected() {
1102 node.note_dirty_descendants();
1103 }
1104
1105 node.dirty(NodeDamage::ContentOrHeritage);
1108 }
1109
1110 pub(crate) fn unregister_element_id(&self, cx: &mut JSContext, id: &Atom) {
1112 self.id_map.remove(id);
1113 self.reset_form_owner_for_listeners(cx, id);
1114 }
1115
1116 pub(crate) fn register_element_id(&self, cx: &mut JSContext, element: &Element, id: &Atom) {
1118 self.id_map.add(id, element);
1119 self.reset_form_owner_for_listeners(cx, id);
1120 }
1121
1122 pub(crate) fn unregister_element_name(&self, name: &Atom) {
1124 self.name_map.remove(name);
1125 }
1126
1127 pub(crate) fn register_element_name(&self, element: &Element, name: &Atom) {
1129 self.name_map.add(name, element);
1130 }
1131
1132 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1133 &self,
1134 id: DOMString,
1135 listener: &T,
1136 ) {
1137 let mut map = self.form_id_listener_map.borrow_mut();
1138 let listener = listener.to_element();
1139 let set = map.entry(Atom::from(id)).or_default();
1140 set.insert(Dom::from_ref(listener));
1141 }
1142
1143 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1144 &self,
1145 id: DOMString,
1146 listener: &T,
1147 ) {
1148 let mut map = self.form_id_listener_map.borrow_mut();
1149 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1150 entry
1151 .get_mut()
1152 .remove(&Dom::from_ref(listener.to_element()));
1153 if entry.get().is_empty() {
1154 entry.remove();
1155 }
1156 }
1157 }
1158
1159 fn find_a_potential_indicated_element(
1161 &self,
1162 cx: &mut JSContext,
1163 fragment: &str,
1164 ) -> Option<DomRoot<Element>> {
1165 self.get_element_by_id(cx.no_gc(), &Atom::from(fragment))
1169 .or_else(|| self.get_anchor_by_name(cx, fragment))
1173 }
1174
1175 fn select_indicated_part(&self, cx: &mut JSContext, fragment: &str) -> Option<DomRoot<Node>> {
1178 if fragment.is_empty() {
1188 return Some(DomRoot::from_ref(self.upcast()));
1189 }
1190 if let Some(potential_indicated_element) =
1192 self.find_a_potential_indicated_element(cx, fragment)
1193 {
1194 return Some(DomRoot::upcast(potential_indicated_element));
1196 }
1197 let fragment_bytes = percent_decode(fragment.as_bytes());
1199 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1201 return None;
1202 };
1203 if let Some(potential_indicated_element) =
1205 self.find_a_potential_indicated_element(cx, &decoded_fragment)
1206 {
1207 return Some(DomRoot::upcast(potential_indicated_element));
1209 }
1210 if decoded_fragment.eq_ignore_ascii_case("top") {
1212 return Some(DomRoot::from_ref(self.upcast()));
1213 }
1214 None
1216 }
1217
1218 pub(crate) fn scroll_to_the_fragment(&self, cx: &mut JSContext, fragment: &str) {
1220 let Some(indicated_part) = self.select_indicated_part(cx, fragment) else {
1225 self.set_target_element(None);
1226 return;
1227 };
1228 if *indicated_part == *self.upcast() {
1230 self.set_target_element(None);
1232 self.window.scroll(cx, 0.0, 0.0, ScrollBehavior::Instant);
1237 return;
1239 }
1240 let Some(target) = indicated_part.downcast::<Element>() else {
1243 unreachable!("Indicated part should always be an element");
1245 };
1246 self.set_target_element(Some(target));
1248 target.scroll_into_view_with_options(
1252 cx,
1253 ScrollBehavior::Auto,
1254 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1255 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1256 None,
1257 None,
1258 );
1259
1260 indicated_part.run_the_focusing_steps(cx, Some(FocusableArea::Viewport));
1263
1264 self.focus_handler()
1266 .set_sequential_focus_navigation_starting_point(target.upcast());
1267 }
1268
1269 fn get_anchor_by_name(&self, cx: &mut JSContext, name: &str) -> Option<DomRoot<Element>> {
1270 let document_element = self.GetDocumentElement()?;
1271 self.name_map
1272 .get_all(cx.no_gc(), document_element.upcast(), &Atom::from(name))
1273 .iter()
1274 .find(|element| element.is::<HTMLAnchorElement>())
1275 .map(|element| DomRoot::from_ref(&**element))
1276 }
1277
1278 pub(crate) fn set_ready_state(&self, cx: &mut JSContext, state: DocumentReadyState) {
1280 match state {
1281 DocumentReadyState::Loading => {
1282 if self.window().is_top_level() {
1283 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1284 self.webview_id(),
1285 LoadStatus::Started,
1286 ));
1287 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1288 }
1289 },
1290 DocumentReadyState::Complete => {
1291 if self.window().is_top_level() {
1292 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1293 self.webview_id(),
1294 LoadStatus::Complete,
1295 ));
1296 }
1297 update_with_current_instant(&self.navigation_timing.dom_complete);
1298 },
1299 DocumentReadyState::Interactive => {
1300 update_with_current_instant(&self.navigation_timing.dom_interactive)
1301 },
1302 };
1303
1304 self.ready_state.set(state);
1305
1306 self.upcast::<EventTarget>()
1307 .fire_event(cx, atom!("readystatechange"));
1308 }
1309
1310 pub(crate) fn scripting_enabled(&self) -> bool {
1313 self.has_browsing_context() &&
1316 !self.has_active_sandboxing_flag(
1320 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1321 )
1322 }
1323
1324 pub(crate) fn title_changed(&self) {
1326 if self.browsing_context().is_some() {
1327 self.send_title_to_embedder();
1328 let title = String::from(self.Title());
1329 self.window
1330 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1331 self.window.pipeline_id(),
1332 title.clone(),
1333 ));
1334 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1335 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1336 self.window.pipeline_id(),
1337 title,
1338 ));
1339 }
1340 }
1341 }
1342
1343 fn title(&self) -> Option<DOMString> {
1347 let title = self.GetDocumentElement().and_then(|root| {
1348 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1349 root.upcast::<Node>()
1351 .child_elements()
1352 .find(|node| {
1353 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1354 })
1355 .map(DomRoot::upcast::<Node>)
1356 } else {
1357 root.upcast::<Node>()
1359 .traverse_preorder(ShadowIncluding::No)
1360 .find(|node| node.is::<HTMLTitleElement>())
1361 }
1362 });
1363
1364 title.map(|title| {
1365 let value = title.child_text_content();
1367 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1368 })
1369 }
1370
1371 pub(crate) fn send_title_to_embedder(&self) {
1373 let window = self.window();
1374 if window.is_top_level() {
1375 let title = self.title().map(String::from);
1376 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1377 }
1378 }
1379
1380 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1381 let window = self.window();
1382 window.send_to_embedder(msg);
1383 }
1384
1385 pub(crate) fn dirty_all_nodes(&self) {
1386 let root = match self.GetDocumentElement() {
1387 Some(root) => root,
1388 None => return,
1389 };
1390 for node in root
1391 .upcast::<Node>()
1392 .traverse_preorder(ShadowIncluding::Yes)
1393 {
1394 node.dirty(NodeDamage::Other)
1395 }
1396 }
1397
1398 pub(crate) fn run_the_scroll_steps(&self, cx: &mut JSContext) {
1400 let boxes_that_were_scrolled: Vec<_> = self
1408 .pending_scroll_events
1409 .borrow()
1410 .iter()
1411 .filter_map(|pending_event| {
1412 if &*pending_event.event == "scroll" {
1413 Some(pending_event.target.as_rooted())
1414 } else {
1415 None
1416 }
1417 })
1418 .collect();
1419
1420 for target in boxes_that_were_scrolled.into_iter() {
1421 let Some(element) = target.downcast::<Element>() else {
1427 continue;
1428 };
1429 let document = element.owner_document();
1430
1431 let mut pending_scroll_events = document.pending_scroll_events.borrow_mut();
1438 let event = "scrollend".into();
1439 if pending_scroll_events
1440 .iter()
1441 .any(|existing| existing.equivalent(&target, &event))
1442 {
1443 continue;
1444 }
1445
1446 pending_scroll_events.push(PendingScrollEvent {
1448 target: target.as_traced(),
1449 event: "scrollend".into(),
1450 });
1451 }
1452
1453 rooted_vec!(let pending_scroll_events <- self.pending_scroll_events.take().into_iter());
1456 for pending_event in pending_scroll_events.iter() {
1457 let event = pending_event.event.clone();
1460 if pending_event.target.is::<Document>() {
1461 pending_event.target.fire_bubbling_event(cx, event);
1462 }
1463 else {
1472 pending_event.target.fire_event(cx, event);
1473 }
1474 }
1475
1476 }
1479
1480 pub(crate) fn handle_viewport_scroll_event(&self) {
1485 self.finish_handle_scroll_event(self.upcast());
1497 }
1498
1499 pub(crate) fn finish_handle_scroll_event(&self, event_target: &EventTarget) {
1504 let event = "scroll".into();
1507 if self
1508 .pending_scroll_events
1509 .borrow()
1510 .iter()
1511 .any(|existing| existing.equivalent(event_target, &event))
1512 {
1513 return;
1514 }
1515
1516 self.pending_scroll_events
1519 .borrow_mut()
1520 .push(PendingScrollEvent {
1521 target: Dom::from_ref(event_target),
1522 event: "scroll".into(),
1523 });
1524 }
1525
1526 pub(crate) fn node_from_nodes_and_strings(
1528 &self,
1529 cx: &mut JSContext,
1530 mut nodes: Vec<NodeOrString>,
1531 ) -> Fallible<DomRoot<Node>> {
1532 if nodes.len() == 1 {
1533 Ok(match nodes.pop().unwrap() {
1534 NodeOrString::Node(node) => node,
1535 NodeOrString::String(string) => DomRoot::upcast(self.CreateTextNode(cx, string)),
1536 })
1537 } else {
1538 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(cx));
1539 for node in nodes {
1540 match node {
1541 NodeOrString::Node(node) => {
1542 fragment.AppendChild(cx, &node)?;
1543 },
1544 NodeOrString::String(string) => {
1545 let node = DomRoot::upcast::<Node>(self.CreateTextNode(cx, string));
1546 fragment.AppendChild(cx, &node).unwrap();
1549 },
1550 }
1551 }
1552 Ok(fragment)
1553 }
1554 }
1555
1556 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1557 match self.GetBody() {
1558 Some(ref body) if body.is_body_element() => {
1559 body.upcast::<Element>().get_string_attribute(local_name)
1560 },
1561 _ => DOMString::new(),
1562 }
1563 }
1564
1565 pub(crate) fn set_body_attribute(
1566 &self,
1567 cx: &mut JSContext,
1568 local_name: &LocalName,
1569 value: DOMString,
1570 ) {
1571 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1572 let body = body.upcast::<Element>();
1573 let value = body.parse_attribute(&ns!(), local_name, value);
1574 body.set_attribute(cx, local_name, value);
1575 }
1576 }
1577
1578 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1579 self.current_script.set(script);
1580 }
1581
1582 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1583 self.script_blocking_stylesheets_count.get()
1584 }
1585
1586 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1587 let count_cell = &self.script_blocking_stylesheets_count;
1588 count_cell.set(count_cell.get() + 1);
1589 }
1590
1591 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1592 let count_cell = &self.script_blocking_stylesheets_count;
1593 assert!(count_cell.get() > 0);
1594 count_cell.set(count_cell.get() - 1);
1595 }
1596
1597 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1598 self.render_blocking_element_count.get()
1599 }
1600
1601 pub(crate) fn increment_render_blocking_element_count(&self) {
1603 assert!(self.allows_adding_render_blocking_elements());
1610 let count_cell = &self.render_blocking_element_count;
1611 count_cell.set(count_cell.get() + 1);
1612 }
1613
1614 pub(crate) fn decrement_render_blocking_element_count(&self) {
1616 let count_cell = &self.render_blocking_element_count;
1622 assert!(count_cell.get() > 0);
1623 count_cell.set(count_cell.get() - 1);
1624 }
1625
1626 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1628 self.is_html_document && self.GetBody().is_none()
1631 }
1632
1633 pub(crate) fn is_render_blocked(&self) -> bool {
1635 self.render_blocking_element_count() > 0
1639 }
1644
1645 pub(crate) fn invalidate_stylesheets(&self) {
1646 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1647
1648 if let Some(element) = self.GetDocumentElement() {
1652 element.upcast::<Node>().dirty(NodeDamage::Style);
1653 }
1654 }
1655
1656 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1659 !self.animation_frame_list.borrow().is_empty()
1660 }
1661
1662 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1664 let ident = self.animation_frame_ident.get() + 1;
1665 self.animation_frame_ident.set(ident);
1666
1667 let had_animation_frame_callbacks;
1668 {
1669 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1670 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1671 animation_frame_list.push_back((ident, Some(callback)));
1672 }
1673
1674 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1680 self.window().send_to_constellation(
1681 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1682 AnimationState::AnimationCallbacksPresent,
1683 ),
1684 );
1685 }
1686
1687 ident
1688 }
1689
1690 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1692 let mut list = self.animation_frame_list.borrow_mut();
1693 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1694 pair.1 = None;
1695 }
1696 }
1697
1698 pub(crate) fn run_the_animation_frame_callbacks(&self, cx: &mut CurrentRealm) {
1700 self.running_animation_callbacks.set(true);
1701 let timing = self.global().performance().Now();
1702
1703 let num_callbacks = self.animation_frame_list.borrow().len();
1704 for _ in 0..num_callbacks {
1705 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1706 if let Some(callback) = maybe_callback {
1707 callback.call(cx, self, *timing);
1708 }
1709 }
1710 self.running_animation_callbacks.set(false);
1711
1712 if self.animation_frame_list.borrow().is_empty() {
1713 self.window().send_to_constellation(
1714 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1715 AnimationState::NoAnimationCallbacksPresent,
1716 ),
1717 );
1718 }
1719 }
1720
1721 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1722 self.policy_container.borrow()
1723 }
1724
1725 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1726 *self.policy_container.borrow_mut() = policy_container;
1727 }
1728
1729 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1730 self.policy_container.borrow_mut().set_csp_list(csp_list);
1731 }
1732
1733 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
1735 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
1737 csp_list.push(policy);
1738 self.policy_container
1739 .borrow_mut()
1740 .set_csp_list(Some(csp_list));
1741 }
1742
1743 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
1744 Ref::map(self.policy_container.borrow(), |policy_container| {
1745 &policy_container.csp_list
1746 })
1747 }
1748
1749 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1750 self.preloaded_resources.borrow()
1751 }
1752
1753 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1754 self.preloaded_resources
1755 .borrow_mut()
1756 .insert(key, preload_id);
1757 }
1758
1759 pub(crate) fn fetch<Listener: FetchResponseListener>(
1760 &self,
1761 load: LoadType,
1762 mut request: RequestBuilder,
1763 listener: Listener,
1764 ) {
1765 request = request
1766 .insecure_requests_policy(self.insecure_requests_policy())
1767 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1768 let callback = NetworkListener {
1769 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1770 task_source: self
1771 .owner_global()
1772 .task_manager()
1773 .networking_task_source()
1774 .into(),
1775 }
1776 .into_callback();
1777 self.loader_mut()
1778 .fetch_async_with_callback(load, request, callback);
1779 }
1780
1781 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1782 &self,
1783 mut request: RequestBuilder,
1784 listener: Listener,
1785 ) {
1786 request = request
1787 .insecure_requests_policy(self.insecure_requests_policy())
1788 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1789 let callback = NetworkListener {
1790 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1791 task_source: self
1792 .owner_global()
1793 .task_manager()
1794 .networking_task_source()
1795 .into(),
1796 }
1797 .into_callback();
1798 self.loader_mut().fetch_async_background(request, callback);
1799 }
1800
1801 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
1803 match self.window().window_proxy().frame_element() {
1804 None => DomRoot::from_ref(self),
1807 Some(container) => container.owner_document().deferred_fetch_control_document(),
1809 }
1810 }
1811
1812 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
1814 let control_document = self.deferred_fetch_control_document();
1816 let navigable = control_document.window();
1818 let is_top_level = navigable.is_top_level();
1821 let deferred_fetch_allowed = true;
1825 let deferred_fetch_minimal_allowed = true;
1829 let mut quota = match is_top_level {
1831 true if !deferred_fetch_allowed => 0,
1833 true if !deferred_fetch_minimal_allowed => 640 * 1024,
1835 true => 512 * 1024,
1837 _ if deferred_fetch_allowed => 0,
1841 _ if deferred_fetch_minimal_allowed => 8 * 1024,
1845 _ => 0,
1847 } as isize;
1848 let mut quota_for_request_origin = 64 * 1024_isize;
1850 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
1859 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
1861 continue;
1862 }
1863 let request_length = deferred_fetch.request.total_request_length();
1865 quota -= request_length as isize;
1867 if deferred_fetch.request.url().origin() == origin {
1870 quota_for_request_origin -= request_length as isize;
1871 }
1872 }
1873 if quota <= 0 {
1875 return 0;
1876 }
1877 if quota < quota_for_request_origin {
1879 return quota;
1880 }
1881 quota_for_request_origin
1883 }
1884
1885 pub(crate) fn update_document_for_history_step_application(
1887 &self,
1888 old_url: &ServoUrl,
1889 new_url: &ServoUrl,
1890 ) {
1891 if old_url.as_url()[Position::BeforeFragment..] !=
1921 new_url.as_url()[Position::BeforeFragment..]
1922 {
1923 let window = Trusted::new(self.owner_window().deref());
1924 let old_url = old_url.to_string();
1925 let new_url = new_url.to_string();
1926 self.owner_global()
1927 .task_manager()
1928 .dom_manipulation_task_source()
1929 .queue(task!(hashchange_event: move |cx| {
1930 let window = window.root();
1931 HashChangeEvent::new(
1932 cx,
1933 &window,
1934 atom!("hashchange"),
1935 false,
1936 false,
1937 old_url,
1938 new_url,
1939 )
1940 .upcast::<Event>()
1941 .fire(cx, window.upcast());
1942 }));
1943 }
1944 }
1945
1946 pub(crate) fn finish_load_for_dropped_blocker(&self, load: LoadType) {
1947 let this = Trusted::new(self);
1948 self.owner_global()
1949 .task_manager()
1950 .dom_manipulation_task_source()
1951 .queue(task!(check_finished_load: move |cx| {
1952 this.root().finish_load(load, cx);
1953 }));
1954 }
1955
1956 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut JSContext) {
1959 debug!("Document got finish_load: {:?}", load);
1961 self.loader.borrow_mut().finish_load(&load);
1962
1963 match load {
1964 LoadType::Stylesheet(_) => {
1965 self.process_pending_parsing_blocking_script(cx);
1968
1969 self.process_deferred_scripts(cx);
1971 },
1972 LoadType::PageSource(_) => {
1973 if self.has_browsing_context && self.is_fully_active() {
1976 self.window().allow_layout_if_necessary(cx);
1977 }
1978
1979 self.process_deferred_scripts(cx);
1984 },
1985 _ => {},
1986 }
1987
1988 let loader = self.loader.borrow();
1995
1996 if self
1998 .navigation_timing
1999 .top_level_dom_complete
2000 .get()
2001 .is_none() &&
2002 loader.is_only_blocked_by_iframes()
2003 {
2004 update_with_current_instant(&self.navigation_timing.top_level_dom_complete);
2005 }
2006
2007 if loader.is_blocked() || loader.events_inhibited() {
2008 return;
2010 }
2011
2012 ScriptThread::mark_document_with_no_blocked_loads(self);
2013 }
2014
2015 pub(crate) fn check_if_unloading_is_cancelled(
2017 &self,
2018 cx: &mut JSContext,
2019 recursive_flag: bool,
2020 ) -> bool {
2021 self.incr_ignore_opens_during_unload_counter();
2024 let beforeunload_event = BeforeUnloadEvent::new(
2026 cx,
2027 &self.window,
2028 atom!("beforeunload"),
2029 EventBubbles::Bubbles,
2030 EventCancelable::Cancelable,
2031 );
2032 let event = beforeunload_event.upcast::<Event>();
2033 event.set_trusted(true);
2034 let event_target = self.window.upcast::<EventTarget>();
2035 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2036 self.window.dispatch_event_with_target_override(cx, event);
2037 if has_listeners {
2040 self.salvageable.set(false);
2041 }
2042 let mut can_unload = true;
2043 let default_prevented = event.DefaultPrevented();
2045 let return_value_not_empty = !event
2046 .downcast::<BeforeUnloadEvent>()
2047 .unwrap()
2048 .ReturnValue()
2049 .is_empty();
2050 if default_prevented || return_value_not_empty {
2051 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2052 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2053 self.send_to_embedder(msg);
2054 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2055 }
2056 if !recursive_flag {
2058 let iframes: Vec<_> = self.iframes().iter().collect();
2061 for iframe in &iframes {
2062 let document = iframe.owner_document();
2064 can_unload = document.check_if_unloading_is_cancelled(cx, true);
2065 if !document.salvageable() {
2066 self.salvageable.set(false);
2067 }
2068 if !can_unload {
2069 break;
2070 }
2071 }
2072 }
2073 self.decr_ignore_opens_during_unload_counter();
2075 can_unload
2076 }
2077
2078 pub(crate) fn unload(&self, cx: &mut JSContext, recursive_flag: bool) {
2080 self.incr_ignore_opens_during_unload_counter();
2083 if self.page_showing.get() {
2085 self.page_showing.set(false);
2087 let event = PageTransitionEvent::new(
2090 cx,
2091 &self.window,
2092 atom!("pagehide"),
2093 false, false, self.salvageable.get(), );
2097 let event = event.upcast::<Event>();
2098 event.set_trusted(true);
2099 self.window.dispatch_event_with_target_override(cx, event);
2100 self.update_visibility_state(cx, DocumentVisibilityState::Hidden);
2102 }
2103 if !self.fired_unload.get() {
2105 let event = Event::new(
2106 cx,
2107 self.window.upcast(),
2108 atom!("unload"),
2109 EventBubbles::Bubbles,
2110 EventCancelable::Cancelable,
2111 );
2112 event.set_trusted(true);
2113 let event_target = self.window.upcast::<EventTarget>();
2114 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2115 self.window.dispatch_event_with_target_override(cx, &event);
2116 self.fired_unload.set(true);
2117 if has_listeners {
2119 self.salvageable.set(false);
2120 }
2121 }
2122 if !recursive_flag {
2126 let iframes: Vec<_> = self.iframes().iter().collect();
2129 for iframe in &iframes {
2130 let document = iframe.owner_document();
2132 document.unload(cx, true);
2133 if !document.salvageable() {
2134 self.salvageable.set(false);
2135 }
2136 }
2137 }
2138
2139 self.unloading_cleanup_steps();
2141
2142 self.window.as_global_scope().clean_up_all_file_resources();
2144
2145 self.decr_ignore_opens_during_unload_counter();
2147
2148 }
2151
2152 fn completely_finish_loading(&self) {
2154 self.completely_loaded.set(true);
2159 self.notify_constellation_load();
2168
2169 if let Some(DeclarativeRefresh::PendingLoad {
2178 url,
2179 time,
2180 from_meta_element,
2181 }) = &*self.declarative_refresh.borrow()
2182 {
2183 self.window.as_global_scope().schedule_callback(
2184 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2185 window: DomRoot::from_ref(self.window()),
2186 url: url.clone(),
2187 from_meta_element: *from_meta_element,
2188 }),
2189 Duration::from_secs(*time),
2190 );
2191 }
2192 }
2193
2194 pub(crate) fn maybe_queue_document_completion(&self, cx: &mut JSContext) {
2196 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2198 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2199 None => false,
2200 };
2201
2202 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2207 !self.is_fully_active() ||
2208 is_in_delaying_load_events_mode ||
2209 self.loader.borrow().events_inhibited();
2212
2213 if not_ready_for_load {
2214 return;
2216 }
2217
2218 self.loader.borrow_mut().inhibit_events();
2219
2220 debug!("Document loads are complete.");
2225 let document = Trusted::new(self);
2226 self.owner_global()
2227 .task_manager()
2228 .dom_manipulation_task_source()
2229 .queue(task!(fire_load_event: move |cx| {
2230 let document = document.root();
2231 let window = document.window();
2233 if !window.is_alive() {
2234 return;
2235 }
2236
2237 document.set_ready_state(cx,DocumentReadyState::Complete);
2239
2240 if document.browsing_context().is_none() {
2242 return;
2243 }
2244
2245 update_with_current_instant(&document.navigation_timing.load_event_start);
2247
2248 let load_event = Event::new(
2250 cx,
2251 window.upcast(),
2252 atom!("load"),
2253 EventBubbles::DoesNotBubble,
2254 EventCancelable::NotCancelable,
2255 );
2256 load_event.set_trusted(true);
2257 debug!("About to dispatch load for {:?}", document.url());
2258 window.dispatch_event_with_target_override(cx, &load_event);
2259
2260 update_with_current_instant(&document.navigation_timing.load_event_end);
2270
2271 document.page_showing.set(true);
2276
2277 let page_show_event = PageTransitionEvent::new(
2279 cx,
2280 window,
2281 atom!("pageshow"),
2282 false, false, false, );
2286 let page_show_event = page_show_event.upcast::<Event>();
2287 page_show_event.set_trusted(true);
2288 page_show_event.fire(cx, window.upcast());
2289
2290 document.completely_finish_loading();
2292
2293 if let Some(fragment) = document.url().fragment() {
2297 document.scroll_to_the_fragment(cx, fragment);
2298 }
2299 }));
2300
2301 #[cfg(feature = "webxr")]
2316 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2317 self.window.Navigator().Xr(cx).dispatch_sessionavailable();
2318 }
2319 }
2320
2321 pub(crate) fn completely_loaded(&self) -> bool {
2322 self.completely_loaded.get()
2323 }
2324
2325 pub(crate) fn set_pending_parsing_blocking_script(
2327 &self,
2328 script: &HTMLScriptElement,
2329 load: Option<ScriptResult>,
2330 ) {
2331 assert!(!self.has_pending_parsing_blocking_script());
2332 *self.pending_parsing_blocking_script.borrow_mut() =
2333 Some(PendingScript::new_with_load(script, load));
2334 }
2335
2336 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2338 self.pending_parsing_blocking_script.borrow().is_some()
2339 }
2340
2341 pub(crate) fn pending_parsing_blocking_script_loaded(
2343 &self,
2344 element: &HTMLScriptElement,
2345 result: ScriptResult,
2346 cx: &mut JSContext,
2347 ) {
2348 {
2349 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2350 let entry = blocking_script.as_mut().unwrap();
2351 assert!(&*entry.element == element);
2352 entry.loaded(result);
2353 }
2354 self.process_pending_parsing_blocking_script(cx);
2355 }
2356
2357 fn process_pending_parsing_blocking_script(&self, cx: &mut JSContext) {
2358 if self.script_blocking_stylesheets_count.get() > 0 {
2359 return;
2360 }
2361 let pair = self
2362 .pending_parsing_blocking_script
2363 .borrow_mut()
2364 .as_mut()
2365 .and_then(PendingScript::take_result);
2366 if let Some((element, result)) = pair {
2367 *self.pending_parsing_blocking_script.borrow_mut() = None;
2368 self.get_current_parser()
2369 .unwrap()
2370 .resume_with_pending_parsing_blocking_script(cx, &element, result);
2371 }
2372 }
2373
2374 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2376 self.asap_scripts_set
2377 .borrow_mut()
2378 .push(Dom::from_ref(script));
2379 }
2380
2381 pub(crate) fn asap_script_loaded(
2384 &self,
2385 cx: &mut JSContext,
2386 element: &HTMLScriptElement,
2387 result: ScriptResult,
2388 ) {
2389 {
2390 let mut scripts = self.asap_scripts_set.borrow_mut();
2391 let idx = scripts
2392 .iter()
2393 .position(|entry| &**entry == element)
2394 .unwrap();
2395 scripts.swap_remove(idx);
2396 }
2397 element.execute(cx, result);
2398 }
2399
2400 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2402 self.asap_in_order_scripts_list.push(script);
2403 }
2404
2405 pub(crate) fn asap_in_order_script_loaded(
2408 &self,
2409 cx: &mut JSContext,
2410 element: &HTMLScriptElement,
2411 result: ScriptResult,
2412 ) {
2413 self.asap_in_order_scripts_list.loaded(element, result);
2414 while let Some((element, result)) = self
2415 .asap_in_order_scripts_list
2416 .take_next_ready_to_be_executed()
2417 {
2418 element.execute(cx, result);
2419 }
2420 }
2421
2422 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2424 self.deferred_scripts.push(script);
2425 }
2426
2427 pub(crate) fn deferred_script_loaded(
2430 &self,
2431 cx: &mut JSContext,
2432 element: &HTMLScriptElement,
2433 result: ScriptResult,
2434 ) {
2435 self.deferred_scripts.loaded(element, result);
2436 self.process_deferred_scripts(cx);
2437 }
2438
2439 fn process_deferred_scripts(&self, cx: &mut JSContext) {
2441 if self.ready_state.get() != DocumentReadyState::Interactive {
2442 return;
2443 }
2444 loop {
2446 if self.script_blocking_stylesheets_count.get() > 0 {
2447 return;
2448 }
2449 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2450 {
2451 element.execute(cx, result);
2452 } else {
2453 break;
2454 }
2455 }
2456 if self.deferred_scripts.is_empty() {
2457 self.maybe_dispatch_dom_content_loaded();
2459 }
2460 }
2461
2462 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2464 if self.domcontentloaded_dispatched.get() {
2465 return;
2466 }
2467 self.domcontentloaded_dispatched.set(true);
2468 assert_ne!(
2469 self.ReadyState(),
2470 DocumentReadyState::Complete,
2471 "Complete before DOMContentLoaded?"
2472 );
2473
2474 let document = Trusted::new(self);
2477 self.owner_global()
2478 .task_manager()
2479 .dom_manipulation_task_source()
2480 .queue(task!(fire_dom_content_loaded_event: move |cx| {
2481 let document = document.root();
2482
2483 update_with_current_instant(&document.navigation_timing.dom_content_loaded_event_start);
2486 document.upcast::<EventTarget>().fire_bubbling_event(cx, atom!("DOMContentLoaded"));
2489
2490 update_with_current_instant(&document.navigation_timing.dom_content_loaded_event_end);
2493
2494 }));
2501
2502 self.interactive_time
2504 .borrow()
2505 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2506
2507 }
2510
2511 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut JSContext) {
2513 if !self.is_fully_active() {
2515 self.salvageable.set(false);
2520 }
2524 for exited_iframe in self.iframes().iter() {
2537 debug!("Destroying nested iframe document");
2538 exited_iframe.destroy_document_and_its_descendants(cx);
2539 }
2540 self.destroy(cx);
2545 }
2548
2549 pub(crate) fn destroy(&self, cx: &mut JSContext) {
2551 let exited_window = self.window();
2552 self.abort(cx);
2554 self.salvageable.set(false);
2556 self.unloading_cleanup_steps();
2566
2567 exited_window
2570 .as_global_scope()
2571 .task_manager()
2572 .cancel_all_tasks_and_ignore_future_tasks();
2573
2574 exited_window.discard_browsing_context();
2576
2577 }
2589
2590 fn terminate_fetch_group(&self) -> bool {
2592 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2593
2594 for canceller in &mut load_cancellers {
2598 if !canceller.keep_alive() {
2599 canceller.terminate();
2600 }
2601 }
2602 self.owner_global().process_deferred_fetches();
2604
2605 !load_cancellers.is_empty()
2606 }
2607
2608 fn active_parser(&self) -> Option<DomRoot<ServoParser>> {
2610 self.get_current_parser()
2613 .filter(|parser| !(parser.has_stopped() || parser.has_aborted()))
2614 }
2615
2616 pub(crate) fn abort(&self, cx: &mut JSContext) {
2618 self.loader.borrow_mut().inhibit_events();
2620
2621 self.script_blocking_stylesheets_count.set(0);
2630 *self.pending_parsing_blocking_script.borrow_mut() = None;
2631 *self.asap_scripts_set.borrow_mut() = vec![];
2632 self.asap_in_order_scripts_list.clear();
2633 self.deferred_scripts.clear();
2634 let loads_cancelled = self.terminate_fetch_group();
2635 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2636 if loads_cancelled || event_sources_canceled {
2637 self.salvageable.set(false);
2639 };
2640
2641 self.owner_global()
2646 .task_manager()
2647 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2648
2649 if let Some(parser) = self.active_parser() {
2654 self.active_parser_was_aborted.set(true);
2656 parser.abort(cx);
2658 self.salvageable.set(false);
2660 }
2661 }
2662
2663 pub(crate) fn abort_a_document_and_its_descendants(&self, cx: &mut JSContext) {
2665 for iframe in self.iframes().iter() {
2673 if let Some(descendant_document) = iframe.GetContentDocument() {
2674 let trusted_descendant_document = Trusted::new(&*descendant_document);
2675 let document = Trusted::new(self);
2676 descendant_document
2677 .owner_global()
2678 .task_manager()
2679 .navigation_and_traversal_task_source()
2680 .queue(task!(abort_iframe_document: move |cx| {
2681 let descendant_document = trusted_descendant_document.root();
2682 descendant_document.abort(cx);
2684 if !descendant_document.salvageable.get() {
2686 document.root().salvageable.set(false);
2687 }
2688 }));
2689 }
2690 }
2691
2692 self.abort(cx);
2694 }
2695
2696 pub(crate) fn notify_constellation_load(&self) {
2697 self.window()
2698 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2699 }
2700
2701 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2702 self.current_parser.set(script);
2703 }
2704
2705 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2706 self.current_parser.get()
2707 }
2708
2709 pub(crate) fn get_current_parser_line(&self) -> u32 {
2710 self.get_current_parser()
2711 .map(|parser| parser.get_current_line())
2712 .unwrap_or(0)
2713 }
2714
2715 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2718 self.iframes.borrow()
2719 }
2720
2721 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2724 self.iframes.borrow_mut()
2725 }
2726
2727 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2728 self.interactive_time
2729 .borrow_mut()
2730 .set_navigation_start(navigation_start);
2731 }
2732
2733 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2734 self.interactive_time.borrow()
2735 }
2736
2737 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2738 self.get_interactive_metrics().get_tti().is_some()
2739 }
2740
2741 pub(crate) fn start_tti(&self) {
2742 if self.get_interactive_metrics().needs_tti() {
2743 self.tti_window.borrow_mut().start_window();
2744 }
2745 }
2746
2747 pub(crate) fn record_tti_if_necessary(&self) {
2751 if self.has_recorded_tti_metric() {
2752 return;
2753 }
2754 if self.tti_window.borrow().needs_check() {
2755 self.get_interactive_metrics()
2756 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2757 self.tti_window.borrow().get_start(),
2758 ));
2759 }
2760 }
2761
2762 pub(crate) fn is_cookie_averse(&self) -> bool {
2764 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2765 }
2766
2767 pub(crate) fn lookup_custom_element_definition(
2769 &self,
2770 cx: &mut JSContext,
2771 namespace: &Namespace,
2772 local_name: &LocalName,
2773 is: Option<&LocalName>,
2774 ) -> Option<Rc<CustomElementDefinition>> {
2775 if *namespace != ns!(html) {
2777 return None;
2778 }
2779
2780 if !self.has_browsing_context {
2782 return None;
2783 }
2784
2785 let registry = self.window.CustomElements(cx);
2787
2788 registry.lookup_definition(local_name, is)
2789 }
2790
2791 pub(crate) fn custom_element_registry(
2793 &self,
2794 cx: &mut JSContext,
2795 ) -> DomRoot<CustomElementRegistry> {
2796 self.window.CustomElements(cx)
2797 }
2798
2799 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2800 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2801 self.throw_on_dynamic_markup_insertion_counter
2802 .set(counter + 1);
2803 }
2804
2805 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2806 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2807 self.throw_on_dynamic_markup_insertion_counter
2808 .set(counter - 1);
2809 }
2810
2811 pub(crate) fn react_to_environment_changes(&self) {
2812 for image in self.responsive_images.borrow().iter() {
2813 image.react_to_environment_changes();
2814 }
2815 }
2816
2817 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2818 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2819 }
2820
2821 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2822 let index = self
2823 .responsive_images
2824 .borrow()
2825 .iter()
2826 .position(|x| **x == *img);
2827 if let Some(i) = index {
2828 self.responsive_images.borrow_mut().remove(i);
2829 }
2830 }
2831
2832 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
2833 let did_have_these_media_controls = self
2834 .media_controls
2835 .borrow_mut()
2836 .insert(id.to_string(), Dom::from_ref(controls))
2837 .is_some();
2838 debug_assert!(
2839 !did_have_these_media_controls,
2840 "Trying to register known media controls"
2841 );
2842 }
2843
2844 pub(crate) fn unregister_media_controls(&self, id: &str) {
2845 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2846 debug_assert!(
2847 did_have_these_media_controls,
2848 "Trying to unregister unknown media controls"
2849 );
2850 }
2851
2852 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
2853 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
2854 if dirty_canvases
2855 .iter()
2856 .any(|dirty_canvas| dirty_canvas == canvas)
2857 {
2858 return;
2859 }
2860 dirty_canvases.push(canvas.clone());
2861 }
2862
2863 pub(crate) fn needs_rendering_update(&self) -> bool {
2867 if !self.is_fully_active() {
2868 return false;
2869 }
2870 if !self.window().layout_blocked() &&
2871 (!self.restyle_reason().is_empty() ||
2872 self.window().layout().needs_new_display_list() ||
2873 self.window().layout().needs_accessibility_update())
2874 {
2875 return true;
2876 }
2877 if !self.rendering_update_reasons.get().is_empty() {
2878 return true;
2879 }
2880 if self.event_handler.has_pending_input_events() {
2881 return true;
2882 }
2883 if self.has_pending_scroll_events() {
2884 return true;
2885 }
2886 if self.window().has_unhandled_resize_event() {
2887 return true;
2888 }
2889 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
2890 {
2891 return true;
2892 }
2893 if self.window().has_pending_media_query_evaluation() {
2894 return true;
2895 }
2896
2897 false
2898 }
2899
2900 pub(crate) fn update_the_rendering(
2908 &self,
2909 cx: &mut JSContext,
2910 ) -> (ReflowPhasesRun, ReflowStatistics) {
2911 assert!(!self.is_render_blocked());
2912
2913 let mut phases = ReflowPhasesRun::empty();
2914 if self.has_pending_animated_image_update.get() {
2915 self.image_animation_manager
2916 .borrow()
2917 .update_active_frames(&self.window, self.current_animation_timeline_value());
2918 self.has_pending_animated_image_update.set(false);
2919 phases.insert(ReflowPhasesRun::UpdatedImageData);
2920 }
2921
2922 self.current_rendering_epoch
2923 .set(self.current_rendering_epoch.get().next());
2924 let current_rendering_epoch = self.current_rendering_epoch.get();
2925
2926 let image_keys: Vec<_> = self
2928 .dirty_canvases
2929 .borrow_mut()
2930 .drain(..)
2931 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
2932 .collect();
2933
2934 let pipeline_id = self.window().pipeline_id();
2937 if !image_keys.is_empty() {
2938 phases.insert(ReflowPhasesRun::UpdatedImageData);
2939 self.waiting_on_canvas_image_updates.set(true);
2940 self.window().paint_api().delay_new_frame_for_canvas(
2941 self.webview_id(),
2942 self.window().pipeline_id(),
2943 current_rendering_epoch,
2944 image_keys,
2945 );
2946 }
2947
2948 let (reflow_phases, statistics) = self.window().reflow(cx, ReflowGoal::UpdateTheRendering);
2949 let phases = phases.union(reflow_phases);
2950
2951 self.window().paint_api().update_epoch(
2952 self.webview_id(),
2953 pipeline_id,
2954 current_rendering_epoch,
2955 );
2956
2957 (phases, statistics)
2958 }
2959
2960 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2961 self.waiting_on_canvas_image_updates.set(false);
2962 }
2963
2964 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2965 self.waiting_on_canvas_image_updates.get()
2966 }
2967
2968 pub(crate) fn maybe_fulfill_font_ready_promise(&self, cx: &mut JSContext) -> bool {
2978 if !self.is_fully_active() {
2979 return false;
2980 }
2981
2982 let fonts = self.Fonts(cx);
2983 if !fonts.waiting_to_fullfill_promise() {
2984 return false;
2985 }
2986 if self.window().font_context().web_fonts_still_loading() != 0 {
2987 return false;
2988 }
2989 if self.ReadyState() != DocumentReadyState::Complete {
2990 return false;
2991 }
2992 if !self.restyle_reason().is_empty() {
2993 return false;
2994 }
2995 if !self.rendering_update_reasons.get().is_empty() {
2996 return false;
2997 }
2998
2999 let result = fonts.fulfill_ready_promise_if_needed(cx);
3000
3001 if result {
3005 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3006 }
3007
3008 result
3009 }
3010
3011 pub(crate) fn id_map(&self) -> &TreeOrderedIndexMap {
3012 &self.id_map
3013 }
3014
3015 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3017 self.resize_observers
3018 .borrow_mut()
3019 .push(Dom::from_ref(resize_observer));
3020 }
3021
3022 pub(crate) fn has_resize_observers(&self) -> bool {
3024 !self.resize_observers.borrow().is_empty()
3025 }
3026
3027 pub(crate) fn gather_active_resize_observations_at_depth(
3030 &self,
3031 depth: &ResizeObservationDepth,
3032 ) -> bool {
3033 let mut has_active_resize_observations = false;
3034 for observer in self.resize_observers.borrow_mut().iter_mut() {
3035 observer.gather_active_resize_observations_at_depth(
3036 depth,
3037 &mut has_active_resize_observations,
3038 );
3039 }
3040 has_active_resize_observations
3041 }
3042
3043 #[expect(clippy::redundant_iter_cloned)]
3045 pub(crate) fn broadcast_active_resize_observations(
3046 &self,
3047 cx: &mut JSContext,
3048 ) -> ResizeObservationDepth {
3049 let mut shallowest = ResizeObservationDepth::max();
3050 let iterator: Vec<DomRoot<ResizeObserver>> = self
3054 .resize_observers
3055 .borrow()
3056 .iter()
3057 .cloned()
3058 .map(|obs| DomRoot::from_ref(&*obs))
3059 .collect();
3060 for observer in iterator {
3061 observer.broadcast_active_resize_observations(cx, &mut shallowest);
3062 }
3063 shallowest
3064 }
3065
3066 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3068 self.resize_observers
3069 .borrow()
3070 .iter()
3071 .any(|observer| observer.has_skipped_resize_observations())
3072 }
3073
3074 pub(crate) fn deliver_resize_loop_error_notification(&self, cx: &mut JSContext) {
3076 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3077 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3078 ..Default::default()
3079 };
3080 self.window
3081 .as_global_scope()
3082 .report_an_error(cx, error_info, HandleValue::null());
3083 }
3084
3085 pub(crate) fn status_code(&self) -> Option<u16> {
3086 self.status_code
3087 }
3088
3089 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3091 let encoding = self.encoding.get();
3097
3098 let base_url = self.base_url();
3104
3105 url::Url::options()
3107 .base_url(Some(base_url.as_url()))
3108 .encoding_override(Some(&|input| {
3109 servo_url::encoding::encode_as_url_query_string(input, encoding)
3110 }))
3111 .parse(url)
3112 .map(ServoUrl::from)
3113 }
3114
3115 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3117 if !self.has_browsing_context {
3119 return false;
3120 }
3121
3122 if !self.is_fully_active() {
3124 return false;
3125 }
3126
3127 true
3133 }
3134
3135 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3138 self.intersection_observers
3139 .borrow_mut()
3140 .push(Dom::from_ref(intersection_observer));
3141 }
3142
3143 pub(crate) fn remove_intersection_observer(
3147 &self,
3148 intersection_observer: &IntersectionObserver,
3149 ) {
3150 self.intersection_observers
3151 .borrow_mut()
3152 .retain(|observer| *observer != intersection_observer)
3153 }
3154
3155 pub(crate) fn update_intersection_observer_steps(
3157 &self,
3158 cx: &mut JSContext,
3159 time: CrossProcessInstant,
3160 ) {
3161 if self.intersection_observers.borrow().is_empty() {
3162 return;
3163 }
3164 self.window()
3166 .reflow_for_non_flushing_update_the_rendering_queries(cx);
3167
3168 for intersection_observer in &*self.intersection_observers.borrow() {
3170 self.update_single_intersection_observer_steps(cx, intersection_observer, time);
3171 }
3172 }
3173
3174 fn update_single_intersection_observer_steps(
3176 &self,
3177 cx: &mut JSContext,
3178 intersection_observer: &IntersectionObserver,
3179 time: CrossProcessInstant,
3180 ) {
3181 let root_bounds = intersection_observer.root_intersection_rectangle();
3184
3185 intersection_observer.update_intersection_observations_steps(cx, self, time, root_bounds);
3189 }
3190
3191 pub(crate) fn notify_intersection_observers(&self, cx: &mut JSContext) {
3193 self.intersection_observer_task_queued.set(false);
3196
3197 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3202
3203 for intersection_observer in notify_list.iter() {
3206 intersection_observer.invoke_callback_if_necessary(cx);
3208 }
3209 }
3210
3211 pub(crate) fn queue_an_intersection_observer_task(&self) {
3213 if self.intersection_observer_task_queued.get() {
3216 return;
3217 }
3218
3219 self.intersection_observer_task_queued.set(true);
3222
3223 let document = Trusted::new(self);
3227 self.owner_global()
3228 .task_manager()
3229 .intersection_observer_task_source()
3230 .queue(task!(notify_intersection_observers: move |cx| {
3231 document.root().notify_intersection_observers(cx);
3232 }));
3233 }
3234
3235 pub(crate) fn handle_paint_metric(
3236 &self,
3237 metric_type: ProgressiveWebMetricType,
3238 metric_value: CrossProcessInstant,
3239 first_reflow: bool,
3240 can_gc: CanGc,
3241 ) {
3242 let metrics = self.interactive_time.borrow();
3243 match metric_type {
3244 ProgressiveWebMetricType::FirstPaint |
3245 ProgressiveWebMetricType::FirstContentfulPaint => {
3246 let binding = PerformancePaintTiming::new(
3247 self.window.as_global_scope(),
3248 metric_type.clone(),
3249 metric_value,
3250 can_gc,
3251 );
3252 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3253 let entry = binding.upcast::<PerformanceEntry>();
3254 self.window.Performance().queue_entry(entry);
3255 },
3256 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3257 let binding = LargestContentfulPaint::new(
3258 self.window.as_global_scope(),
3259 metric_value,
3260 area,
3261 url,
3262 can_gc,
3263 );
3264 metrics.set_largest_contentful_paint(metric_value, area);
3265 let entry = binding.upcast::<PerformanceEntry>();
3266 self.window.Performance().queue_entry(entry);
3267 },
3268 ProgressiveWebMetricType::TimeToInteractive => {
3269 unreachable!("Unexpected non-paint metric.")
3270 },
3271 }
3272 }
3273
3274 fn write(
3276 &self,
3277 cx: &mut JSContext,
3278 text: Vec<TrustedHTMLOrString>,
3279 line_feed: bool,
3280 containing_class: &str,
3281 field: &str,
3282 ) -> ErrorResult {
3283 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3285 let mut is_trusted = true;
3287 for value in text {
3289 match value {
3290 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3292 strings.push(trusted_html.to_string());
3293 },
3294 TrustedHTMLOrString::String(str_) => {
3295 is_trusted = false;
3297 strings.push(str_.into());
3299 },
3300 };
3301 }
3302 let mut string = itertools::join(strings, "");
3303 if !is_trusted {
3307 string = TrustedHTML::get_trusted_type_compliant_string(
3308 cx,
3309 &self.global(),
3310 TrustedHTMLOrString::String(string.into()),
3311 &format!("{} {}", containing_class, field),
3312 )?
3313 .str()
3314 .to_owned();
3315 }
3316 if line_feed {
3318 string.push('\n');
3319 }
3320 if !self.is_html_document() {
3322 return Err(Error::InvalidState(None));
3323 }
3324
3325 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3328 return Err(Error::InvalidState(None));
3329 }
3330
3331 if self.active_parser_was_aborted.get() {
3333 return Ok(());
3334 }
3335
3336 let parser = match self.get_current_parser() {
3337 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3338 _ => {
3340 if self.is_prompting_or_unloading() ||
3343 self.ignore_destructive_writes_counter.get() > 0
3344 {
3345 return Ok(());
3346 }
3347 self.Open(cx, None, None)?;
3349 self.get_current_parser().unwrap()
3350 },
3351 };
3352
3353 parser.write(cx, string.into());
3355
3356 Ok(())
3357 }
3358
3359 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3360 RefMut::map(
3361 self.details_name_groups.borrow_mut(),
3362 |details_name_groups| details_name_groups.get_or_insert_default(),
3363 )
3364 }
3365
3366 pub(crate) fn accessibility_data_mut(&self) -> RefMut<'_, AccessibilityData> {
3367 self.accessibility_data.borrow_mut()
3368 }
3369
3370 pub(crate) fn accessibility_active(&self) -> bool {
3371 self.window().layout().accessibility_active()
3372 }
3373
3374 pub(crate) fn rooted_nodes_for_accessibility_integrity_check(
3375 &self,
3376 ) -> Option<FxHashSet<OpaqueNode>> {
3377 if !self.accessibility_active() {
3378 return None;
3379 }
3380
3381 let mut accessibility_data = self.accessibility_data_mut();
3382
3383 if pref!(expensive_accessibility_test_assertions_enabled) {
3384 return Some(accessibility_data.unroot_and_drain_all_removed_nodes());
3385 }
3386
3387 accessibility_data.unroot_all_removed_nodes();
3388 None
3389 }
3390}
3391
3392#[derive(MallocSizeOf, PartialEq)]
3393pub(crate) enum DocumentSource {
3394 FromParser,
3395 NotFromParser,
3396}
3397
3398impl<'dom> LayoutDom<'dom, Document> {
3399 #[inline]
3400 pub(crate) fn is_html_document_for_layout(&self) -> bool {
3401 self.unsafe_get().is_html_document
3402 }
3403
3404 #[inline]
3405 pub(crate) fn quirks_mode(self) -> QuirksMode {
3406 self.unsafe_get().quirks_mode.get()
3407 }
3408
3409 #[inline]
3410 pub(crate) fn shared_style_locks(self) -> &'dom SharedRwLocks {
3411 self.unsafe_get().shared_style_locks()
3412 }
3413
3414 #[inline]
3415 pub(crate) fn flush_shadow_root_stylesheets_if_necessary(
3416 self,
3417 stylist: &mut Stylist,
3418 guard: &SharedRwLockReadGuard,
3419 ) {
3420 (*self.unsafe_get()).flush_shadow_root_stylesheets_if_necessary_for_layout(stylist, guard)
3421 }
3422
3423 #[inline]
3424 pub(crate) fn shadow_roots_styles_changed(self) -> bool {
3425 self.unsafe_get().shadow_roots_styles_changed.get()
3426 }
3427
3428 pub(crate) fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3429 self.unsafe_get().id_map.get_all_for_layout(id)
3430 }
3431}
3432
3433pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3437 host_suffix_string: &str,
3438 original_host: Host,
3439) -> Option<Host> {
3440 if host_suffix_string.is_empty() {
3442 return None;
3443 }
3444
3445 let host = match Host::parse(host_suffix_string) {
3447 Ok(host) => host,
3448 Err(_) => return None,
3449 };
3450
3451 if host != original_host {
3453 let host = match host {
3455 Host::Domain(ref host) => host,
3456 _ => return None,
3457 };
3458 let original_host = match original_host {
3459 Host::Domain(ref original_host) => original_host,
3460 _ => return None,
3461 };
3462
3463 let index = original_host.len().checked_sub(host.len())?;
3465 let (prefix, suffix) = original_host.split_at(index);
3466
3467 if !prefix.ends_with('.') {
3468 return None;
3469 }
3470 if suffix != host {
3471 return None;
3472 }
3473
3474 if is_pub_domain(host) {
3476 return None;
3477 }
3478 }
3479
3480 Some(host)
3482}
3483
3484fn url_has_network_scheme(url: &ServoUrl) -> bool {
3486 matches!(url.scheme(), "ftp" | "http" | "https")
3487}
3488
3489#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3490pub(crate) enum HasBrowsingContext {
3491 No,
3492 Yes,
3493}
3494
3495impl Document {
3496 #[allow(clippy::too_many_arguments)]
3497 pub(crate) fn new_inherited(
3498 window: &Window,
3499 has_browsing_context: HasBrowsingContext,
3500 url: Option<ServoUrl>,
3501 about_base_url: Option<ServoUrl>,
3502 origin: MutableOrigin,
3503 is_html_document: IsHTMLDocument,
3504 content_type: Option<Mime>,
3505 last_modified: Option<String>,
3506 activity: DocumentActivity,
3507 source: DocumentSource,
3508 doc_loader: DocumentLoader,
3509 referrer: Option<String>,
3510 status_code: Option<u16>,
3511 canceller: FetchCanceller,
3512 is_initial_about_blank: bool,
3513 allow_declarative_shadow_roots: bool,
3514 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3515 has_trustworthy_ancestor_origin: bool,
3516 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3517 creation_sandboxing_flag_set: SandboxingFlagSet,
3518 timeline: &DocumentTimeline,
3519 ) -> Document {
3520 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3521
3522 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3523 (DocumentReadyState::Loading, false)
3524 } else {
3525 (DocumentReadyState::Complete, true)
3526 };
3527
3528 let frame_type = match window.is_top_level() {
3529 true => TimerMetadataFrameType::RootWindow,
3530 false => TimerMetadataFrameType::IFrame,
3531 };
3532 let interactive_time = ProgressiveWebMetrics::new(
3533 window.time_profiler_chan().clone(),
3534 url.clone(),
3535 frame_type,
3536 );
3537
3538 let content_type = content_type.unwrap_or_else(|| {
3539 match is_html_document {
3540 IsHTMLDocument::HTMLDocument => "text/html",
3542 IsHTMLDocument::NonHTMLDocument => "application/xml",
3544 }
3545 .parse()
3546 .unwrap()
3547 });
3548
3549 let encoding = content_type
3550 .get_parameter(CHARSET)
3551 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3552 .unwrap_or(UTF_8);
3553
3554 let has_focus = window.parent_info().is_none();
3555 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3556 let shared_style_locks = window.script_thread().shared_style_locks().clone();
3557
3558 Document {
3559 node: Node::new_document_node(),
3560 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3561 window: Dom::from_ref(window),
3562 has_browsing_context,
3563 implementation: Default::default(),
3564 content_type,
3565 last_modified,
3566 url: DomRefCell::new(url),
3567 about_base_url: DomRefCell::new(about_base_url),
3568 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3570 event_handler: DocumentEventHandler::new(window),
3571 focus_handler: DocumentFocusHandler::new(window, has_focus),
3572 embedder_controls: DocumentEmbedderControls::new(window),
3573 id_map: TreeOrderedIndexMap::id(),
3574 name_map: TreeOrderedIndexMap::name(),
3575 encoding: Cell::new(encoding),
3577 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3578 activity: Cell::new(activity),
3579 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3580 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3581 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3582 images: Default::default(),
3583 embeds: Default::default(),
3584 links: Default::default(),
3585 forms: Default::default(),
3586 scripts: Default::default(),
3587 anchors: Default::default(),
3588 applets: Default::default(),
3589 iframes: RefCell::new(IFrameCollection::new()),
3590 shared_style_locks,
3591 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3592 stylesheet_list: MutNullableDom::new(None),
3593 ready_state: Cell::new(ready_state),
3594 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3595
3596 current_script: Default::default(),
3597 pending_parsing_blocking_script: Default::default(),
3598 script_blocking_stylesheets_count: Default::default(),
3599 render_blocking_element_count: Default::default(),
3600 deferred_scripts: Default::default(),
3601 asap_in_order_scripts_list: Default::default(),
3602 asap_scripts_set: Default::default(),
3603 animation_frame_ident: Cell::new(0),
3604 animation_frame_list: DomRefCell::new(VecDeque::new()),
3605 running_animation_callbacks: Cell::new(false),
3606 loader: DomRefCell::new(doc_loader),
3607 current_parser: Default::default(),
3608 base_element: Default::default(),
3609 target_base_element: Default::default(),
3610 appropriate_template_contents_owner_document: Default::default(),
3611 pending_restyles: DomRefCell::new(FxHashMap::default()),
3612 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3613 origin: DomRefCell::new(origin),
3614 referrer,
3615 target_element: MutNullableDom::new(None),
3616 policy_container: DomRefCell::new(PolicyContainer::default()),
3617 preloaded_resources: Default::default(),
3618 ignore_destructive_writes_counter: Default::default(),
3619 ignore_opens_during_unload_counter: Default::default(),
3620 spurious_animation_frames: Cell::new(0),
3621 fullscreen_element: MutNullableDom::new(None),
3622 form_id_listener_map: Default::default(),
3623 interactive_time: DomRefCell::new(interactive_time),
3624 tti_window: DomRefCell::new(InteractiveWindow::default()),
3625 canceller,
3626 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3627 page_showing: Cell::new(false),
3628 salvageable: Cell::new(true),
3629 active_parser_was_aborted: Cell::new(false),
3630 fired_unload: Cell::new(false),
3631 responsive_images: Default::default(),
3632 navigation_timing: Default::default(),
3633 resource_fetch_timing: RefCell::new(None),
3634 completely_loaded: Cell::new(false),
3635 script_and_layout_blockers: Cell::new(0),
3636 delayed_tasks: Default::default(),
3637 shadow_roots: DomRefCell::new(HashSet::new()),
3638 shadow_roots_styles_changed: Cell::new(false),
3639 media_controls: DomRefCell::new(HashMap::new()),
3640 dirty_canvases: DomRefCell::new(Default::default()),
3641 has_pending_animated_image_update: Cell::new(false),
3642 selection: MutNullableDom::new(None),
3643 timeline: Dom::from_ref(timeline),
3644 animations: Animations::new(),
3645 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3646 dirty_root: Default::default(),
3647 declarative_refresh: Default::default(),
3648 resize_observers: Default::default(),
3649 fonts: Default::default(),
3650 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3651 status_code,
3652 is_initial_about_blank: Cell::new(is_initial_about_blank),
3653 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3654 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3655 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3656 intersection_observer_task_queued: Cell::new(false),
3657 intersection_observers: Default::default(),
3658 highlighted_dom_node: Default::default(),
3659 adopted_stylesheets: Default::default(),
3660 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3661 pending_scroll_events: Default::default(),
3662 rendering_update_reasons: Default::default(),
3663 waiting_on_canvas_image_updates: Cell::new(false),
3664 root_removal_noted: Cell::new(true),
3665 current_rendering_epoch: Default::default(),
3666 custom_element_reaction_stack,
3667 active_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3668 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3669 favicon: RefCell::new(None),
3670 websockets: DOMTracker::new(),
3671 details_name_groups: Default::default(),
3672 protocol_handler_automation_mode: Default::default(),
3673 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3674 state_override: Default::default(),
3675 value_override: Default::default(),
3676 default_single_line_container_name: Default::default(),
3677 css_styling_flag: Default::default(),
3678 accessibility_data: Default::default(),
3679 }
3680 }
3681
3682 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3684 if let Some(csp_list) = self.get_csp_list().as_ref() {
3685 for policy in &csp_list.0 {
3686 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3687 policy.disposition == PolicyDisposition::Enforce
3688 {
3689 return InsecureRequestsPolicy::Upgrade;
3690 }
3691 }
3692 }
3693
3694 self.inherited_insecure_requests_policy
3695 .get()
3696 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3697 }
3698
3699 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3701 &self.event_handler
3702 }
3703
3704 pub(crate) fn focus_handler(&self) -> &DocumentFocusHandler {
3706 &self.focus_handler
3707 }
3708
3709 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3711 &self.embedder_controls
3712 }
3713
3714 fn has_pending_scroll_events(&self) -> bool {
3717 !self.pending_scroll_events.borrow().is_empty()
3718 }
3719
3720 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3723 self.rendering_update_reasons
3724 .set(self.rendering_update_reasons.get().union(reason));
3725 }
3726
3727 pub(crate) fn clear_rendering_update_reasons(&self) {
3729 self.rendering_update_reasons
3730 .set(RenderingUpdateReason::empty())
3731 }
3732
3733 pub(crate) fn add_script_and_layout_blocker(&self) {
3740 self.script_and_layout_blockers
3741 .set(self.script_and_layout_blockers.get() + 1);
3742 }
3743
3744 pub(crate) fn remove_script_and_layout_blocker(&self, cx: &mut JSContext) {
3748 assert!(self.script_and_layout_blockers.get() > 0);
3749 self.script_and_layout_blockers
3750 .set(self.script_and_layout_blockers.get() - 1);
3751 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3752 {
3753 let task = self.delayed_tasks.borrow_mut().remove(0);
3754 task.run_box(cx);
3755 }
3756 }
3757
3758 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3760 self.delayed_tasks.borrow_mut().push(Box::new(task));
3761 }
3762
3763 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3766 assert_eq!(
3767 self.script_and_layout_blockers.get(),
3768 0,
3769 "Attempt to use script or layout while DOM not in a stable state"
3770 );
3771 }
3772
3773 #[allow(clippy::too_many_arguments)]
3774 pub(crate) fn new(
3775 window: &Window,
3776 has_browsing_context: HasBrowsingContext,
3777 url: Option<ServoUrl>,
3778 about_base_url: Option<ServoUrl>,
3779 origin: MutableOrigin,
3780 doctype: IsHTMLDocument,
3781 content_type: Option<Mime>,
3782 last_modified: Option<String>,
3783 activity: DocumentActivity,
3784 source: DocumentSource,
3785 doc_loader: DocumentLoader,
3786 referrer: Option<String>,
3787 status_code: Option<u16>,
3788 canceller: FetchCanceller,
3789 is_initial_about_blank: bool,
3790 allow_declarative_shadow_roots: bool,
3791 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3792 has_trustworthy_ancestor_origin: bool,
3793 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3794 creation_sandboxing_flag_set: SandboxingFlagSet,
3795 can_gc: CanGc,
3796 ) -> DomRoot<Document> {
3797 Self::new_with_proto(
3798 window,
3799 None,
3800 has_browsing_context,
3801 url,
3802 about_base_url,
3803 origin,
3804 doctype,
3805 content_type,
3806 last_modified,
3807 activity,
3808 source,
3809 doc_loader,
3810 referrer,
3811 status_code,
3812 canceller,
3813 is_initial_about_blank,
3814 allow_declarative_shadow_roots,
3815 inherited_insecure_requests_policy,
3816 has_trustworthy_ancestor_origin,
3817 custom_element_reaction_stack,
3818 creation_sandboxing_flag_set,
3819 can_gc,
3820 )
3821 }
3822
3823 #[allow(clippy::too_many_arguments)]
3824 fn new_with_proto(
3825 window: &Window,
3826 proto: Option<HandleObject>,
3827 has_browsing_context: HasBrowsingContext,
3828 url: Option<ServoUrl>,
3829 about_base_url: Option<ServoUrl>,
3830 origin: MutableOrigin,
3831 doctype: IsHTMLDocument,
3832 content_type: Option<Mime>,
3833 last_modified: Option<String>,
3834 activity: DocumentActivity,
3835 source: DocumentSource,
3836 doc_loader: DocumentLoader,
3837 referrer: Option<String>,
3838 status_code: Option<u16>,
3839 canceller: FetchCanceller,
3840 is_initial_about_blank: bool,
3841 allow_declarative_shadow_roots: bool,
3842 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3843 has_trustworthy_ancestor_origin: bool,
3844 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3845 creation_sandboxing_flag_set: SandboxingFlagSet,
3846 can_gc: CanGc,
3847 ) -> DomRoot<Document> {
3848 let timeline = DocumentTimeline::new(window, can_gc);
3849 let document = reflect_dom_object_with_proto(
3850 Box::new(Document::new_inherited(
3851 window,
3852 has_browsing_context,
3853 url,
3854 about_base_url,
3855 origin,
3856 doctype,
3857 content_type,
3858 last_modified,
3859 activity,
3860 source,
3861 doc_loader,
3862 referrer,
3863 status_code,
3864 canceller,
3865 is_initial_about_blank,
3866 allow_declarative_shadow_roots,
3867 inherited_insecure_requests_policy,
3868 has_trustworthy_ancestor_origin,
3869 custom_element_reaction_stack,
3870 creation_sandboxing_flag_set,
3871 &timeline,
3872 )),
3873 window,
3874 proto,
3875 can_gc,
3876 );
3877 {
3878 let node = document.upcast::<Node>();
3879 node.set_owner_doc(&document);
3880 }
3881 document
3882 }
3883
3884 pub(crate) fn get_redirect_count(&self) -> u16 {
3885 self.resource_fetch_timing()
3886 .as_ref()
3887 .map_or(0, |resource_fetch_timing| {
3888 resource_fetch_timing.redirect_count
3889 })
3890 }
3891
3892 pub(crate) fn set_resource_fetch_timing(&self, timing: ResourceFetchTiming) {
3893 self.resource_fetch_timing.replace(Some(timing));
3894 }
3895
3896 pub(crate) fn resource_fetch_timing(&self) -> Ref<'_, Option<ResourceFetchTiming>> {
3897 self.resource_fetch_timing.borrow()
3898 }
3899
3900 pub(crate) fn navigation_timing(&self) -> &NavigationTiming {
3901 &self.navigation_timing
3902 }
3903
3904 pub(crate) fn performance_timing_attribute(
3905 &self,
3906 name: &str,
3907 ) -> Fallible<Option<CrossProcessInstant>> {
3908 Ok(match name {
3909 "unloadEventStart" => self.navigation_timing().unload_event_start.get(),
3910 "unloadEventEnd" => self.navigation_timing().unload_event_end.get(),
3911 "domInteractive" => self.navigation_timing().dom_interactive.get(),
3912 "domContentLoadedEventStart" => self
3913 .navigation_timing()
3914 .dom_content_loaded_event_start
3915 .get(),
3916 "domContentLoadedEventEnd" => {
3917 self.navigation_timing().dom_content_loaded_event_end.get()
3918 },
3919 "domComplete" => self.navigation_timing().dom_complete.get(),
3920 "loadEventStart" => self.navigation_timing().load_event_start.get(),
3921 "loadEventEnd" => self.navigation_timing().load_event_end.get(),
3922 "redirectStart" | "redirectEnd" | "secureConnectionStart" | "responseEnd" => self
3923 .resource_fetch_timing()
3924 .as_ref()
3925 .and_then(|resource_fetch_timing| match name {
3926 "redirectStart" => resource_fetch_timing.redirect_start,
3927 "redirectEnd" => resource_fetch_timing.redirect_end,
3928 "secureConnectionStart" => resource_fetch_timing.secure_connection_start,
3929 "responseEnd" => resource_fetch_timing.response_end,
3930 _ => None,
3931 }),
3932 _ => {
3933 return Err(Error::Operation(Some(format!(
3934 "{name} hasn't been implemented."
3935 ))));
3936 },
3937 })
3938 }
3939
3940 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3941 if name.is_empty() {
3942 return 0;
3943 }
3944 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3945 }
3946
3947 pub(crate) fn nth_element_by_name(
3948 &self,
3949 index: u32,
3950 name: &DOMString,
3951 ) -> Option<DomRoot<Node>> {
3952 if name.is_empty() {
3953 return None;
3954 }
3955 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3956 }
3957
3958 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3961 let element = match node.downcast::<Element>() {
3962 Some(element) => element,
3963 None => return false,
3964 };
3965 if element.namespace() != &ns!(html) {
3966 return false;
3967 }
3968 element.get_name().is_some_and(|n| &*n == name)
3969 }
3970
3971 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3972 let doc = self.GetDocumentElement();
3973 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3974 maybe_node
3975 .iter()
3976 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3977 .filter(|node| callback(node))
3978 .count() as u32
3979 }
3980
3981 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3982 &self,
3983 index: u32,
3984 callback: F,
3985 ) -> Option<DomRoot<Node>> {
3986 let doc = self.GetDocumentElement();
3987 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3988 maybe_node
3989 .iter()
3990 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3991 .filter(|node| callback(node))
3992 .nth(index as usize)
3993 .map(|n| DomRoot::from_ref(&*n))
3994 }
3995
3996 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3997 self.GetDocumentElement().and_then(DomRoot::downcast)
3998 }
3999
4000 pub(crate) fn shared_style_locks(&self) -> &SharedRwLocks {
4002 &self.shared_style_locks
4003 }
4004
4005 pub(crate) fn style_shared_author_lock(&self) -> &SharedRwLock {
4007 &self.shared_style_locks.author
4008 }
4009
4010 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4012 let mut stylesheets = self.stylesheets.borrow_mut();
4019 let have_changed = stylesheets.has_changed();
4020 stylesheets.flush_without_invalidation();
4021 have_changed
4022 }
4023
4024 pub(crate) fn salvageable(&self) -> bool {
4025 self.salvageable.get()
4026 }
4027
4028 pub(crate) fn make_document_unsalvageable(&self) {
4030 self.salvageable.set(false);
4036 }
4037
4038 pub(crate) fn appropriate_template_contents_owner_document(
4040 &self,
4041 can_gc: CanGc,
4042 ) -> DomRoot<Document> {
4043 self.appropriate_template_contents_owner_document
4044 .or_init(|| {
4045 let doctype = if self.is_html_document {
4046 IsHTMLDocument::HTMLDocument
4047 } else {
4048 IsHTMLDocument::NonHTMLDocument
4049 };
4050 let new_doc = Document::new(
4051 self.window(),
4052 HasBrowsingContext::No,
4053 None,
4054 None,
4055 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4057 doctype,
4058 None,
4059 None,
4060 DocumentActivity::Inactive,
4061 DocumentSource::NotFromParser,
4062 DocumentLoader::new(&self.loader()),
4063 None,
4064 None,
4065 Default::default(),
4066 false,
4067 self.allow_declarative_shadow_roots(),
4068 Some(self.insecure_requests_policy()),
4069 self.has_trustworthy_ancestor_or_current_origin(),
4070 self.custom_element_reaction_stack.clone(),
4071 self.creation_sandboxing_flag_set(),
4072 can_gc,
4073 );
4074 new_doc
4075 .appropriate_template_contents_owner_document
4076 .set(Some(&new_doc));
4077 new_doc
4078 })
4079 }
4080
4081 pub(crate) fn get_element_by_id(&self, no_gc: &NoGC, id: &Atom) -> Option<DomRoot<Element>> {
4082 self.id_map.get(no_gc, self.upcast(), id)
4083 }
4084
4085 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4086 let map = self.pending_restyles.borrow_mut();
4087 RefMut::map(map, |m| {
4088 &mut m
4089 .entry(Dom::from_ref(el))
4090 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4091 .0
4092 })
4093 }
4094
4095 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: AttrRef<'_>) {
4096 let mut entry = self.ensure_pending_restyle(el);
4102 if entry.snapshot.is_none() {
4103 entry.snapshot = Some(Snapshot::new());
4104 }
4105 if attr.local_name() == &local_name!("style") {
4106 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4107 }
4108
4109 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) ||
4110 el.check_style_on_self_or_eager_pseudos(|style| {
4111 if let Some(ref attribute_references) = style.attribute_references {
4112 return attribute_references.contains_key(attr.local_name());
4113 }
4114 false
4115 })
4116 {
4117 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4118 }
4119
4120 let snapshot = entry.snapshot.as_mut().unwrap();
4121 if attr.local_name() == &local_name!("id") {
4122 if snapshot.id_changed {
4123 return;
4124 }
4125 snapshot.id_changed = true;
4126 } else if attr.local_name() == &local_name!("class") {
4127 if snapshot.class_changed {
4128 return;
4129 }
4130 snapshot.class_changed = true;
4131 } else {
4132 snapshot.other_attributes_changed = true;
4133 }
4134 let local_name = style::LocalName::cast(attr.local_name());
4135 if !snapshot.changed_attrs.contains(local_name) {
4136 snapshot.changed_attrs.push(local_name.clone());
4137 }
4138 if snapshot.attrs.is_none() {
4139 let attrs = el
4140 .attrs()
4141 .borrow()
4142 .iter()
4143 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4144 .collect();
4145 snapshot.attrs = Some(attrs);
4146 }
4147 }
4148
4149 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4150 self.policy_container
4151 .borrow_mut()
4152 .set_referrer_policy(policy);
4153 }
4154
4155 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4156 self.policy_container.borrow().get_referrer_policy()
4157 }
4158
4159 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4160 if let Some(ref element) = self.target_element.get() {
4161 element.set_target_state(false);
4162 }
4163
4164 self.target_element.set(node);
4165
4166 if let Some(ref element) = self.target_element.get() {
4167 element.set_target_state(true);
4168 }
4169 }
4170
4171 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4172 self.ignore_destructive_writes_counter
4173 .set(self.ignore_destructive_writes_counter.get() + 1);
4174 }
4175
4176 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4177 self.ignore_destructive_writes_counter
4178 .set(self.ignore_destructive_writes_counter.get() - 1);
4179 }
4180
4181 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4182 self.ignore_opens_during_unload_counter.get() > 0
4183 }
4184
4185 fn incr_ignore_opens_during_unload_counter(&self) {
4186 self.ignore_opens_during_unload_counter
4187 .set(self.ignore_opens_during_unload_counter.get() + 1);
4188 }
4189
4190 fn decr_ignore_opens_during_unload_counter(&self) {
4191 self.ignore_opens_during_unload_counter
4192 .set(self.ignore_opens_during_unload_counter.get() - 1);
4193 }
4194
4195 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4196 self.fullscreen_element.set(element);
4197 }
4198
4199 fn reset_form_owner_for_listeners(&self, cx: &mut JSContext, id: &Atom) {
4200 let map = self.form_id_listener_map.borrow();
4201 if let Some(listeners) = map.get(id) {
4202 for listener in listeners {
4203 listener
4204 .as_maybe_form_control()
4205 .expect("Element must be a form control")
4206 .reset_form_owner(cx);
4207 }
4208 }
4209 }
4210
4211 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4212 self.shadow_roots
4213 .borrow_mut()
4214 .insert(Dom::from_ref(shadow_root));
4215 self.invalidate_shadow_roots_stylesheets();
4216 }
4217
4218 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4219 let mut shadow_roots = self.shadow_roots.borrow_mut();
4220 shadow_roots.remove(&Dom::from_ref(shadow_root));
4221 }
4222
4223 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4224 self.shadow_roots_styles_changed.set(true);
4225 }
4226
4227 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4228 self.shadow_roots_styles_changed.get()
4229 }
4230
4231 pub(crate) fn flush_shadow_root_stylesheets_if_necessary_for_layout(
4232 &self,
4233 stylist: &mut Stylist,
4234 guard: &SharedRwLockReadGuard,
4235 ) {
4236 if !self.shadow_roots_styles_changed.get() {
4237 return;
4238 }
4239 #[expect(unsafe_code)]
4240 unsafe {
4241 for shadow_root in self.shadow_roots.borrow_for_layout().iter() {
4242 let layout: LayoutDom<'_, _> = shadow_root.to_layout();
4243 layout.flush_stylesheets_for_layout(stylist, guard);
4244 }
4245 }
4246 self.shadow_roots_styles_changed.set(false);
4247 }
4248
4249 pub(crate) fn stylesheet_count(&self) -> usize {
4250 self.stylesheets.borrow().len()
4251 }
4252
4253 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4254 let stylesheets = self.stylesheets.borrow();
4255
4256 stylesheets
4257 .get(Origin::Author, index)
4258 .and_then(|s| s.owner.get_cssom_object())
4259 }
4260
4261 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(
4268 &self,
4269 cx: &mut JSContext,
4270 owner_node: &Element,
4271 sheet: Arc<Stylesheet>,
4272 ) {
4273 let stylesheets = &mut *self.stylesheets.borrow_mut();
4274
4275 let insertion_point = stylesheets
4277 .iter()
4278 .map(|(sheet, _origin)| sheet)
4279 .find(|sheet_in_doc| {
4280 match &sheet_in_doc.owner {
4281 StylesheetSource::Element(other_node) => {
4282 owner_node.upcast::<Node>().is_before(other_node.upcast())
4283 },
4284 StylesheetSource::Constructed(_) => true,
4287 }
4288 })
4289 .cloned();
4290
4291 if self.has_browsing_context() {
4292 self.add_stylesheet_to_stylist(
4293 cx,
4294 sheet.clone(),
4295 insertion_point.as_ref().map(|s| s.sheet.clone()),
4296 );
4297 }
4298
4299 DocumentOrShadowRoot::add_stylesheet(
4300 StylesheetSource::Element(Dom::from_ref(owner_node)),
4301 StylesheetSetRef::Document(stylesheets),
4302 sheet,
4303 insertion_point,
4304 self.style_shared_author_lock(),
4305 );
4306 }
4307
4308 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4313 pub(crate) fn append_constructed_stylesheet(
4314 &self,
4315 cx: &mut JSContext,
4316 cssom_stylesheet: &CSSStyleSheet,
4317 ) {
4318 debug_assert!(cssom_stylesheet.is_constructed());
4319
4320 let stylesheets = &mut *self.stylesheets.borrow_mut();
4321 let sheet = cssom_stylesheet.style_stylesheet().clone();
4322
4323 let insertion_point = stylesheets
4324 .iter()
4325 .last()
4326 .map(|(sheet, _origin)| sheet)
4327 .cloned();
4328
4329 if self.has_browsing_context() {
4330 self.add_stylesheet_to_stylist(
4331 cx,
4332 sheet.clone(),
4333 insertion_point.as_ref().map(|s| s.sheet.clone()),
4334 );
4335 }
4336
4337 DocumentOrShadowRoot::add_stylesheet(
4338 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4339 StylesheetSetRef::Document(stylesheets),
4340 sheet,
4341 insertion_point,
4342 self.style_shared_author_lock(),
4343 );
4344 }
4345
4346 fn switch_font_face_set_to_loading_if_needed(&self, cx: &mut JSContext) {
4347 if self.window.font_context().web_fonts_still_loading() != 0 &&
4348 let Some(font_face_set) = self.fonts.get()
4349 {
4350 font_face_set.switch_to_loading(cx);
4351 }
4352 }
4353
4354 pub(crate) fn load_web_fonts_from_stylesheet(
4356 &self,
4357 cx: &mut JSContext,
4358 stylesheet: &Arc<Stylesheet>,
4359 ) {
4360 self.window
4361 .layout()
4362 .load_web_fonts_from_stylesheet(stylesheet, &self.window.web_font_context());
4363 self.switch_font_face_set_to_loading_if_needed(cx);
4364 }
4365
4366 pub(crate) fn add_stylesheet_to_stylist(
4367 &self,
4368 cx: &mut JSContext,
4369 stylesheet: Arc<Stylesheet>,
4370 before_stylesheet: Option<Arc<Stylesheet>>,
4371 ) {
4372 self.window.layout_mut().add_stylesheet(
4373 stylesheet,
4374 before_stylesheet,
4375 &self.window.web_font_context(),
4376 );
4377 self.switch_font_face_set_to_loading_if_needed(cx);
4378 }
4379
4380 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4383 if self.has_browsing_context() {
4384 self.window
4385 .layout_mut()
4386 .remove_stylesheet(stylesheet.clone());
4387 }
4388
4389 DocumentOrShadowRoot::remove_stylesheet(
4390 owner,
4391 stylesheet,
4392 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4393 )
4394 }
4395
4396 pub(crate) fn get_elements_with_id(
4397 &self,
4398 cx: &mut JSContext,
4399 id: &Atom,
4400 ) -> Ref<'_, [Dom<Element>]> {
4401 self.id_map.get_all(cx.no_gc(), self.upcast(), id)
4402 }
4403
4404 pub(crate) fn get_elements_with_name(
4405 &self,
4406 cx: &mut JSContext,
4407 name: &Atom,
4408 ) -> Ref<'_, [Dom<Element>]> {
4409 self.name_map.get_all(cx.no_gc(), self.upcast(), name)
4410 }
4411
4412 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4413 self.pending_restyles
4414 .borrow_mut()
4415 .drain()
4416 .filter_map(|(elem, restyle)| {
4417 let node = elem.upcast::<Node>();
4418 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4419 return None;
4420 }
4421 node.note_dirty_descendants();
4422 Some((node.to_trusted_node_address(), restyle.0))
4423 })
4424 .collect()
4425 }
4426
4427 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: TimeDuration) {
4428 self.timeline.advance_specific(delta);
4429 let current_timeline_value = self.current_animation_timeline_value();
4430 self.animations
4431 .update_for_new_timeline_value(&self.window, current_timeline_value);
4432 }
4433
4434 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4435 let current_timeline_value = self.current_animation_timeline_value();
4436 self.animations
4437 .mark_animating_nodes_as_dirty(current_timeline_value);
4438 }
4439
4440 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4441 self.timeline
4442 .upcast::<AnimationTimeline>()
4443 .current_time_in_seconds()
4444 }
4445
4446 pub(crate) fn animations(&self) -> &Animations {
4447 &self.animations
4448 }
4449
4450 pub(crate) fn update_animations_post_reflow(&self) {
4451 let current_timeline_value = self.current_animation_timeline_value();
4452 self.animations
4453 .do_post_reflow_update(&self.window, current_timeline_value);
4454 self.image_animation_manager
4455 .borrow_mut()
4456 .do_post_reflow_update(&self.window, current_timeline_value);
4457 }
4458
4459 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4460 self.animations.cancel_animations_for_node(node);
4461 self.image_animation_manager
4462 .borrow_mut()
4463 .cancel_animations_for_node(node);
4464 }
4465
4466 pub(crate) fn update_animations_and_send_events(&self, cx: &mut CurrentRealm) {
4468 if !self.layout_animations_test_enabled {
4470 self.timeline.update(self.window());
4471 }
4472
4473 let current_timeline_value = self.current_animation_timeline_value();
4480 self.animations
4481 .update_for_new_timeline_value(&self.window, current_timeline_value);
4482 self.maybe_mark_animating_nodes_as_dirty();
4483
4484 self.window().perform_a_microtask_checkpoint(cx);
4486
4487 self.animations().send_pending_events(self.window(), cx);
4489 }
4490
4491 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4492 self.image_animation_manager.borrow()
4493 }
4494
4495 pub(crate) fn set_has_pending_animated_image_update(&self) {
4496 self.has_pending_animated_image_update.set(true);
4497 }
4498
4499 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8], from_meta_element: bool) {
4501 if self.will_declaratively_refresh() {
4503 return;
4504 }
4505
4506 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4508 Regex::new(
4512 r#"(?xs)
4513 ^
4514 \s* # 3
4515 ((?<time>[0-9]+)|\.) # 5-6
4516 [0-9.]* # 8
4517 (
4518 (
4519 (\s*;|\s*,|\s) # 10.3
4520 \s* # 10.4
4521 )
4522 (
4523 (
4524 (U|u)(R|r)(L|l) # 11.2-11.4
4525 \s*=\s* # 11.5-11.7
4526 )?
4527 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4528 |
4529 (?<url4>(?s-u:.)*)
4530 )
4531 )?
4532 $
4533 "#,
4534 )
4535 .unwrap()
4536 });
4537
4538 let mut url_record = self.url();
4540 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4541 captures
4542 } else {
4543 return;
4544 };
4545 let time = if let Some(time_string) = captures.name("time") {
4546 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4547 } else {
4548 0
4549 };
4550 let captured_url = captures.name("url1").or(captures
4551 .name("url2")
4552 .or(captures.name("url3").or(captures.name("url4"))));
4553
4554 if let Some(url_match) = captured_url {
4556 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4557 Some(&url_record),
4558 &String::from_utf8_lossy(url_match.as_bytes()),
4559 ) {
4560 info!("Refresh to {}", url.debug_compact());
4561 url
4562 } else {
4563 return;
4565 };
4566 if url_record.scheme() == "javascript" {
4568 return;
4569 }
4570 }
4571 if self.completely_loaded() {
4573 self.window.as_global_scope().schedule_callback(
4574 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4575 window: DomRoot::from_ref(self.window()),
4576 url: url_record,
4577 from_meta_element,
4578 }),
4579 Duration::from_secs(time),
4580 );
4581 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4582 } else {
4583 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4584 url: url_record,
4585 time,
4586 from_meta_element,
4587 });
4588 }
4589 }
4590
4591 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4592 self.declarative_refresh.borrow().is_some()
4593 }
4594 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4595 *self.declarative_refresh.borrow_mut() = Some(refresh);
4596 }
4597
4598 fn update_visibility_state(
4600 &self,
4601 cx: &mut JSContext,
4602 visibility_state: DocumentVisibilityState,
4603 ) {
4604 if self.visibility_state.get() == visibility_state {
4606 return;
4607 }
4608 self.visibility_state.set(visibility_state);
4610 let entry = VisibilityStateEntry::new(
4613 &self.global(),
4614 visibility_state,
4615 CrossProcessInstant::now(),
4616 CanGc::from_cx(cx),
4617 );
4618 self.window
4619 .Performance()
4620 .queue_entry(entry.upcast::<PerformanceEntry>());
4621
4622 #[cfg(feature = "gamepad")]
4633 if visibility_state == DocumentVisibilityState::Hidden {
4634 self.window
4635 .Navigator()
4636 .GetGamepads()
4637 .unwrap_or_default()
4638 .iter_mut()
4639 .for_each(|gamepad| {
4640 if let Some(g) = gamepad {
4641 g.vibration_actuator().handle_visibility_change();
4642 }
4643 });
4644 }
4645
4646 self.upcast::<EventTarget>()
4648 .fire_bubbling_event(cx, atom!("visibilitychange"));
4649 }
4650
4651 pub(crate) fn is_initial_about_blank(&self) -> bool {
4653 self.is_initial_about_blank.get()
4654 }
4655
4656 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4658 self.allow_declarative_shadow_roots.get()
4659 }
4660
4661 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4662 self.has_trustworthy_ancestor_origin.get()
4663 }
4664
4665 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4666 self.has_trustworthy_ancestor_origin.get() ||
4667 self.origin().immutable().is_potentially_trustworthy()
4668 }
4669
4670 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4671 self.highlighted_dom_node.set(node);
4672 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4673 }
4674
4675 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4676 self.highlighted_dom_node.get()
4677 }
4678
4679 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4680 self.custom_element_reaction_stack.clone()
4681 }
4682
4683 pub(crate) fn active_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4684 self.active_sandboxing_flag_set.get()
4685 }
4686
4687 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4688 self.active_sandboxing_flag_set.get().contains(flag)
4689 }
4690
4691 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4692 self.active_sandboxing_flag_set.set(flags)
4693 }
4694
4695 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4696 self.creation_sandboxing_flag_set.get()
4697 }
4698
4699 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4700 &self,
4701 ) -> SandboxingFlagSet {
4702 self.window()
4703 .window_proxy()
4704 .frame_element()
4705 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4706 .map(HTMLIFrameElement::sandboxing_flag_set)
4707 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4708 }
4709
4710 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4711 self.window()
4712 .scrolling_box_query(None, flags)
4713 .expect("We should always have a ScrollingBox for the Viewport")
4714 }
4715
4716 pub(crate) fn notify_embedder_favicon(&self) {
4717 if let Some(ref image) = *self.favicon.borrow() {
4718 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4719 }
4720 }
4721
4722 pub(crate) fn set_favicon(&self, favicon: Image) {
4723 *self.favicon.borrow_mut() = Some(favicon);
4724 self.notify_embedder_favicon();
4725 }
4726
4727 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
4728 self.fullscreen_element.get()
4729 }
4730
4731 pub(crate) fn state_override(&self, command_name: &CommandName) -> Option<bool> {
4733 self.state_override.borrow().get(command_name).copied()
4734 }
4735
4736 pub(crate) fn set_state_override(&self, command_name: CommandName, state: Option<bool>) {
4738 if let Some(state) = state {
4739 self.state_override.borrow_mut().insert(command_name, state);
4740 } else {
4741 self.value_override.borrow_mut().remove(&command_name);
4742 }
4743 }
4744
4745 pub(crate) fn value_override(&self, command_name: &CommandName) -> Option<DOMString> {
4747 self.value_override.borrow().get(command_name).cloned()
4748 }
4749
4750 pub(crate) fn set_value_override(&self, command_name: CommandName, value: Option<DOMString>) {
4752 if let Some(value) = value {
4753 self.value_override.borrow_mut().insert(command_name, value);
4754 } else {
4755 self.value_override.borrow_mut().remove(&command_name);
4756 }
4757 }
4758
4759 pub(crate) fn clear_command_overrides(&self) {
4762 self.state_override.borrow_mut().clear();
4763 self.value_override.borrow_mut().clear();
4764 }
4765
4766 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
4768 self.default_single_line_container_name.get()
4769 }
4770
4771 pub(crate) fn set_default_single_line_container_name(
4773 &self,
4774 value: DefaultSingleLineContainerName,
4775 ) {
4776 self.default_single_line_container_name.set(value)
4777 }
4778
4779 pub(crate) fn css_styling_flag(&self) -> bool {
4781 self.css_styling_flag.get()
4782 }
4783
4784 pub(crate) fn set_css_styling_flag(&self, value: bool) {
4786 self.css_styling_flag.set(value)
4787 }
4788}
4789
4790impl DocumentMethods<crate::DomTypeHolder> for Document {
4791 fn Constructor(
4793 window: &Window,
4794 proto: Option<HandleObject>,
4795 can_gc: CanGc,
4796 ) -> Fallible<DomRoot<Document>> {
4797 let doc = window.Document();
4799 let docloader = DocumentLoader::new(&doc.loader());
4800 Ok(Document::new_with_proto(
4801 window,
4802 proto,
4803 HasBrowsingContext::No,
4804 None,
4805 None,
4806 doc.origin().clone(),
4807 IsHTMLDocument::NonHTMLDocument,
4808 None,
4809 None,
4810 DocumentActivity::Inactive,
4811 DocumentSource::NotFromParser,
4812 docloader,
4813 None,
4814 None,
4815 Default::default(),
4816 false,
4817 doc.allow_declarative_shadow_roots(),
4818 Some(doc.insecure_requests_policy()),
4819 doc.has_trustworthy_ancestor_or_current_origin(),
4820 doc.custom_element_reaction_stack(),
4821 doc.active_sandboxing_flag_set.get(),
4822 can_gc,
4823 ))
4824 }
4825
4826 fn ParseHTMLUnsafe(
4828 cx: &mut JSContext,
4829 window: &Window,
4830 s: TrustedHTMLOrString,
4831 options: &SetHTMLUnsafeOptions,
4832 ) -> Fallible<DomRoot<Self>> {
4833 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
4837 cx,
4838 window.as_global_scope(),
4839 s,
4840 "Document parseHTMLUnsafe",
4841 )?;
4842
4843 let url = window.get_url();
4844 let doc = window.Document();
4845 let loader = DocumentLoader::new(&doc.loader());
4846
4847 let content_type = "text/html"
4848 .parse()
4849 .expect("Supported type is not a MIME type");
4850 let document = Document::new(
4853 window,
4854 HasBrowsingContext::No,
4855 Some(ServoUrl::parse("about:blank").unwrap()),
4856 None,
4857 doc.origin().clone(),
4858 IsHTMLDocument::HTMLDocument,
4859 Some(content_type),
4860 None,
4861 DocumentActivity::Inactive,
4862 DocumentSource::FromParser,
4863 loader,
4864 None,
4865 None,
4866 Default::default(),
4867 false,
4868 true,
4869 Some(doc.insecure_requests_policy()),
4870 doc.has_trustworthy_ancestor_or_current_origin(),
4871 doc.custom_element_reaction_stack(),
4872 doc.creation_sandboxing_flag_set(),
4873 CanGc::from_cx(cx),
4874 );
4875 ServoParser::parse_html_document(cx, &document, Some(compliant_html), url, None, None);
4877
4878 let sanitizer = Sanitizer::get_sanitizer_instance_from_options(cx, window, options, false)?;
4881
4882 sanitizer.sanitize(cx, document.upcast(), false)?;
4884
4885 document.set_ready_state(cx, DocumentReadyState::Complete);
4887 Ok(document)
4888 }
4889
4890 fn ParseHTML(
4892 cx: &mut JSContext,
4893 window: &Window,
4894 html: DOMString,
4895 options: &SetHTMLOptions,
4896 ) -> Fallible<DomRoot<Document>> {
4897 let url = window.get_url();
4900 let doc = window.Document();
4901 let loader = DocumentLoader::new(&doc.loader());
4902 let content_type = "text/html"
4903 .parse()
4904 .expect("Supported type is not a MIME type");
4905 let document = Document::new(
4906 window,
4907 HasBrowsingContext::No,
4908 Some(ServoUrl::parse("about:blank").unwrap()),
4909 None,
4910 doc.origin().clone(),
4911 IsHTMLDocument::HTMLDocument,
4912 Some(content_type),
4913 None,
4914 DocumentActivity::Inactive,
4915 DocumentSource::FromParser,
4916 loader,
4917 None,
4918 None,
4919 Default::default(),
4920 false,
4921 true,
4922 Some(doc.insecure_requests_policy()),
4923 doc.has_trustworthy_ancestor_or_current_origin(),
4924 doc.custom_element_reaction_stack(),
4925 doc.creation_sandboxing_flag_set(),
4926 CanGc::from_cx(cx),
4927 );
4928
4929 ServoParser::parse_html_document(cx, &document, Some(html), url, None, None);
4931
4932 let sanitizer = Sanitizer::get_sanitizer_instance_from_options(cx, window, options, true)?;
4935
4936 sanitizer.sanitize(cx, document.upcast(), true)?;
4938
4939 Ok(document)
4941 }
4942
4943 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4945 self.stylesheet_list.or_init(|| {
4946 StyleSheetList::new(
4947 &self.window,
4948 StyleSheetListOwner::Document(Dom::from_ref(self)),
4949 can_gc,
4950 )
4951 })
4952 }
4953
4954 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4956 self.implementation
4957 .or_init(|| DOMImplementation::new(self, can_gc))
4958 }
4959
4960 fn URL(&self) -> USVString {
4962 USVString(String::from(self.url().as_str()))
4963 }
4964
4965 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4967 self.document_or_shadow_root.active_element(self.upcast())
4968 }
4969
4970 fn HasFocus(&self) -> bool {
4972 if self.window().parent_info().is_none() {
4994 self.is_fully_active()
4996 } else {
4997 self.is_fully_active() && self.focus_handler.has_focus()
4999 }
5000 }
5001
5002 fn Domain(&self) -> DOMString {
5004 match self.origin().effective_domain() {
5006 None => DOMString::new(),
5008 Some(Host::Domain(domain)) => DOMString::from(domain),
5010 Some(host) => DOMString::from(host.to_string()),
5011 }
5012 }
5013
5014 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5016 if !self.has_browsing_context {
5018 return Err(Error::Security(None));
5019 }
5020
5021 if self.has_active_sandboxing_flag(
5024 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5025 ) {
5026 return Err(Error::Security(None));
5027 }
5028
5029 let effective_domain = match self.origin().effective_domain() {
5031 Some(effective_domain) => effective_domain,
5032 None => return Err(Error::Security(None)),
5034 };
5035
5036 let host =
5038 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
5039 None => return Err(Error::Security(None)),
5040 Some(host) => host,
5041 };
5042
5043 self.origin().set_domain(host);
5048
5049 Ok(())
5050 }
5051
5052 fn Referrer(&self) -> DOMString {
5054 match self.referrer {
5055 Some(ref referrer) => DOMString::from(referrer.to_string()),
5056 None => DOMString::new(),
5057 }
5058 }
5059
5060 fn DocumentURI(&self) -> USVString {
5062 self.URL()
5063 }
5064
5065 fn CompatMode(&self) -> DOMString {
5067 DOMString::from(match self.quirks_mode.get() {
5068 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5069 QuirksMode::Quirks => "BackCompat",
5070 })
5071 }
5072
5073 fn CharacterSet(&self) -> DOMString {
5075 DOMString::from(self.encoding.get().name())
5076 }
5077
5078 fn Charset(&self) -> DOMString {
5080 self.CharacterSet()
5081 }
5082
5083 fn InputEncoding(&self) -> DOMString {
5085 self.CharacterSet()
5086 }
5087
5088 fn ContentType(&self) -> DOMString {
5090 DOMString::from(self.content_type.to_string())
5091 }
5092
5093 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5095 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5096 }
5097
5098 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5100 self.upcast::<Node>().child_elements().next()
5101 }
5102
5103 fn GetElementsByTagName(
5105 &self,
5106 cx: &mut JSContext,
5107 qualified_name: DOMString,
5108 ) -> DomRoot<HTMLCollection> {
5109 let qualified_name = LocalName::from(qualified_name);
5110 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5111 return DomRoot::from_ref(entry);
5112 }
5113 let result = HTMLCollection::by_qualified_name(
5114 cx,
5115 &self.window,
5116 self.upcast(),
5117 qualified_name.clone(),
5118 );
5119 self.tag_map
5120 .borrow_mut()
5121 .insert(qualified_name, Dom::from_ref(&*result));
5122 result
5123 }
5124
5125 fn GetElementsByTagNameNS(
5127 &self,
5128 cx: &mut JSContext,
5129 maybe_ns: Option<DOMString>,
5130 tag_name: DOMString,
5131 ) -> DomRoot<HTMLCollection> {
5132 let ns = namespace_from_domstring(maybe_ns);
5133 let local = LocalName::from(tag_name);
5134 let qname = QualName::new(None, ns, local);
5135 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5136 return DomRoot::from_ref(collection);
5137 }
5138 let result =
5139 HTMLCollection::by_qual_tag_name(cx, &self.window, self.upcast(), qname.clone());
5140 self.tagns_map
5141 .borrow_mut()
5142 .insert(qname, Dom::from_ref(&*result));
5143 result
5144 }
5145
5146 fn GetElementsByClassName(
5148 &self,
5149 cx: &mut JSContext,
5150 classes: DOMString,
5151 ) -> DomRoot<HTMLCollection> {
5152 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5153 .map(Atom::from)
5154 .collect();
5155 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5156 return DomRoot::from_ref(collection);
5157 }
5158 let result = HTMLCollection::by_atomic_class_name(
5159 cx,
5160 &self.window,
5161 self.upcast(),
5162 class_atoms.clone(),
5163 );
5164 self.classes_map
5165 .borrow_mut()
5166 .insert(class_atoms, Dom::from_ref(&*result));
5167 result
5168 }
5169
5170 fn GetElementById(
5172 &self,
5173 cx: &js::context::JSContext,
5174 id: DOMString,
5175 ) -> Option<DomRoot<Element>> {
5176 self.get_element_by_id(cx, &Atom::from(id))
5177 }
5178
5179 fn CreateElement(
5181 &self,
5182 cx: &mut JSContext,
5183 mut local_name: DOMString,
5184 options: StringOrElementCreationOptions,
5185 ) -> Fallible<DomRoot<Element>> {
5186 if !is_valid_element_local_name(&local_name.str()) {
5189 debug!("Not a valid element name");
5190 return Err(Error::InvalidCharacter(None));
5191 }
5192
5193 if self.is_html_document {
5194 local_name.make_ascii_lowercase();
5195 }
5196
5197 let ns = if self.is_html_document || self.is_xhtml_document() {
5198 ns!(html)
5199 } else {
5200 ns!()
5201 };
5202
5203 let name = QualName::new(None, ns, LocalName::from(local_name));
5204 let is = match options {
5205 StringOrElementCreationOptions::String(_) => None,
5206 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5207 options.is.as_ref().map(LocalName::from)
5208 },
5209 };
5210 Ok(Element::create(
5211 cx,
5212 name,
5213 is,
5214 self,
5215 ElementCreator::ScriptCreated,
5216 CustomElementCreationMode::Synchronous,
5217 None,
5218 ))
5219 }
5220
5221 fn CreateElementNS(
5223 &self,
5224 cx: &mut JSContext,
5225 namespace: Option<DOMString>,
5226 qualified_name: DOMString,
5227 options: StringOrElementCreationOptions,
5228 ) -> Fallible<DomRoot<Element>> {
5229 let context = domname::Context::Element;
5232 let (namespace, prefix, local_name) =
5233 domname::validate_and_extract(namespace, &qualified_name, context)?;
5234
5235 let name = QualName::new(prefix, namespace, local_name);
5238 let is = match options {
5239 StringOrElementCreationOptions::String(_) => None,
5240 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5241 options.is.as_ref().map(LocalName::from)
5242 },
5243 };
5244
5245 Ok(Element::create(
5247 cx,
5248 name,
5249 is,
5250 self,
5251 ElementCreator::ScriptCreated,
5252 CustomElementCreationMode::Synchronous,
5253 None,
5254 ))
5255 }
5256
5257 fn CreateAttribute(
5259 &self,
5260 cx: &mut JSContext,
5261 mut local_name: DOMString,
5262 ) -> Fallible<DomRoot<Attr>> {
5263 if !is_valid_attribute_local_name(&local_name.str()) {
5266 debug!("Not a valid attribute name");
5267 return Err(Error::InvalidCharacter(None));
5268 }
5269 if self.is_html_document {
5270 local_name.make_ascii_lowercase();
5271 }
5272 let name = LocalName::from(local_name);
5273 let value = AttrValue::String("".to_owned());
5274
5275 Ok(Attr::new(
5276 cx,
5277 self,
5278 name.clone(),
5279 value,
5280 name,
5281 ns!(),
5282 None,
5283 None,
5284 ))
5285 }
5286
5287 fn CreateAttributeNS(
5289 &self,
5290 cx: &mut JSContext,
5291 namespace: Option<DOMString>,
5292 qualified_name: DOMString,
5293 ) -> Fallible<DomRoot<Attr>> {
5294 let context = domname::Context::Attribute;
5297 let (namespace, prefix, local_name) =
5298 domname::validate_and_extract(namespace, &qualified_name, context)?;
5299 let value = AttrValue::String("".to_owned());
5300 let qualified_name = LocalName::from(qualified_name);
5301 Ok(Attr::new(
5302 cx,
5303 self,
5304 local_name,
5305 value,
5306 qualified_name,
5307 namespace,
5308 prefix,
5309 None,
5310 ))
5311 }
5312
5313 fn CreateDocumentFragment(&self, cx: &mut JSContext) -> DomRoot<DocumentFragment> {
5315 DocumentFragment::new(cx, self)
5316 }
5317
5318 fn CreateTextNode(&self, cx: &mut JSContext, data: DOMString) -> DomRoot<Text> {
5320 Text::new(cx, data, self)
5321 }
5322
5323 fn CreateCDATASection(
5325 &self,
5326 cx: &mut JSContext,
5327 data: DOMString,
5328 ) -> Fallible<DomRoot<CDATASection>> {
5329 if self.is_html_document {
5331 return Err(Error::NotSupported(None));
5332 }
5333
5334 if data.contains("]]>") {
5336 return Err(Error::InvalidCharacter(None));
5337 }
5338
5339 Ok(CDATASection::new(cx, data, self))
5341 }
5342
5343 fn CreateComment(&self, cx: &mut JSContext, data: DOMString) -> DomRoot<Comment> {
5345 Comment::new(cx, data, self, None)
5346 }
5347
5348 fn CreateProcessingInstruction(
5350 &self,
5351 cx: &mut JSContext,
5352 target: DOMString,
5353 data: DOMString,
5354 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5355 if !matches_name_production(&target.str()) {
5357 return Err(Error::InvalidCharacter(None));
5358 }
5359
5360 if data.contains("?>") {
5362 return Err(Error::InvalidCharacter(None));
5363 }
5364
5365 Ok(ProcessingInstruction::new(cx, target, data, self))
5367 }
5368
5369 fn ImportNode(
5371 &self,
5372 cx: &mut JSContext,
5373 node: &Node,
5374 options: BooleanOrImportNodeOptions,
5375 ) -> Fallible<DomRoot<Node>> {
5376 if node.is::<Document>() || node.is::<ShadowRoot>() {
5378 return Err(Error::NotSupported(None));
5379 }
5380 let (subtree, registry) = match options {
5382 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5385 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5387 let subtree = (!options.selfOnly).into();
5389 let registry = if let Some(registry) = options.customElementRegistry {
5391 let this_registry = self.custom_element_registry(cx);
5394 if !registry.is_scoped() && registry != this_registry {
5395 return Err(Error::NotSupported(Some(
5396 "Imported customElementRegistry is not scoped and does not match existing registry.".into()
5397 )));
5398 }
5399 Some(registry)
5400 } else {
5401 None
5402 };
5403 (subtree, registry)
5404 },
5405 };
5406 let registry = registry
5409 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(cx, self.upcast()));
5410
5411 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5414 }
5415
5416 fn AdoptNode(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5418 if node.is::<Document>() {
5420 return Err(Error::NotSupported(None));
5421 }
5422
5423 if node.is::<ShadowRoot>() {
5425 return Err(Error::HierarchyRequest(None));
5426 }
5427
5428 Node::adopt(cx, node, self);
5430
5431 Ok(DomRoot::from_ref(node))
5433 }
5434
5435 fn CreateEvent(
5437 &self,
5438 cx: &mut JSContext,
5439 mut interface: DOMString,
5440 ) -> Fallible<DomRoot<Event>> {
5441 interface.make_ascii_lowercase();
5442 match &*interface.str() {
5443 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5444 cx,
5445 &self.window,
5446 ))),
5447 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5448 CompositionEvent::new_uninitialized(cx, &self.window),
5449 )),
5450 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5451 cx,
5452 self.window.upcast(),
5453 ))),
5454 "events" | "event" | "htmlevents" | "svgevents" => {
5457 Ok(Event::new_uninitialized(cx, self.window.upcast()))
5458 },
5459 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5460 cx,
5461 &self.window,
5462 ))),
5463 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5464 cx,
5465 &self.window,
5466 ))),
5467 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5468 cx,
5469 &self.window,
5470 ))),
5471 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5472 cx,
5473 self.window.upcast(),
5474 ))),
5475 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5476 cx,
5477 &self.window,
5478 ))),
5479 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5480 cx,
5481 &self.window,
5482 "".into(),
5483 ))),
5484 "touchevent" => {
5485 let touches = TouchList::new(cx, &self.window, &[]);
5486 let changed_touches = TouchList::new(cx, &self.window, &[]);
5487 let target_touches = TouchList::new(cx, &self.window, &[]);
5488
5489 Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5490 cx,
5491 &self.window,
5492 &touches,
5493 &changed_touches,
5494 &target_touches,
5495 )))
5496 },
5497 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5498 cx,
5499 &self.window,
5500 ))),
5501 _ => Err(Error::NotSupported(None)),
5502 }
5503 }
5504
5505 fn LastModified(&self) -> DOMString {
5507 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5508 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5514 }))
5515 }
5516
5517 fn CreateRange(&self, cx: &mut JSContext) -> DomRoot<Range> {
5519 Range::new_with_doc(cx, self, None)
5520 }
5521
5522 fn CreateNodeIterator(
5524 &self,
5525 root: &Node,
5526 what_to_show: u32,
5527 filter: Option<Rc<NodeFilter>>,
5528 can_gc: CanGc,
5529 ) -> DomRoot<NodeIterator> {
5530 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5531 }
5532
5533 fn CreateTreeWalker(
5535 &self,
5536 root: &Node,
5537 what_to_show: u32,
5538 filter: Option<Rc<NodeFilter>>,
5539 ) -> DomRoot<TreeWalker> {
5540 TreeWalker::new(self, root, what_to_show, filter)
5541 }
5542
5543 fn Title(&self) -> DOMString {
5545 self.title().unwrap_or_else(|| DOMString::from(""))
5546 }
5547
5548 fn SetTitle(&self, cx: &mut JSContext, title: DOMString) {
5550 let root = match self.GetDocumentElement() {
5551 Some(root) => root,
5552 None => return,
5553 };
5554
5555 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5556 let elem = root
5557 .upcast::<Node>()
5558 .child_elements_unrooted(cx.no_gc())
5559 .find(|node| {
5560 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5561 });
5562 match elem {
5563 Some(elem) => UnrootedDom::upcast::<Node>(elem).as_rooted(),
5564 None => {
5565 let name = QualName::new(None, ns!(svg), local_name!("title"));
5566 let elem = Element::create(
5567 cx,
5568 name,
5569 None,
5570 self,
5571 ElementCreator::ScriptCreated,
5572 CustomElementCreationMode::Synchronous,
5573 None,
5574 );
5575 let parent = root.upcast::<Node>();
5576 let child = elem.upcast::<Node>();
5577 parent
5578 .InsertBefore(cx, child, parent.GetFirstChild().as_deref())
5579 .unwrap()
5580 },
5581 }
5582 } else if root.namespace() == &ns!(html) {
5583 let elem = root
5584 .upcast::<Node>()
5585 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
5586 .find(|node| node.is::<HTMLTitleElement>());
5587 match elem {
5588 Some(elem) => elem.as_rooted(),
5589 None => match self.GetHead() {
5590 Some(head) => {
5591 let name = QualName::new(None, ns!(html), local_name!("title"));
5592 let elem = Element::create(
5593 cx,
5594 name,
5595 None,
5596 self,
5597 ElementCreator::ScriptCreated,
5598 CustomElementCreationMode::Synchronous,
5599 None,
5600 );
5601 head.upcast::<Node>()
5602 .AppendChild(cx, elem.upcast())
5603 .unwrap()
5604 },
5605 None => return,
5606 },
5607 }
5608 } else {
5609 return;
5610 };
5611
5612 node.set_text_content_for_element(cx, Some(title));
5613 }
5614
5615 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5617 self.get_html_element()
5618 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5619 }
5620
5621 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5623 self.current_script.get()
5624 }
5625
5626 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5628 self.get_html_element().and_then(|root| {
5631 let node = root.upcast::<Node>();
5632 node.children()
5633 .find(|child| {
5634 matches!(
5635 child.type_id(),
5636 NodeTypeId::Element(ElementTypeId::HTMLElement(
5637 HTMLElementTypeId::HTMLBodyElement,
5638 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5639 HTMLElementTypeId::HTMLFrameSetElement,
5640 ))
5641 )
5642 })
5643 .map(|node| DomRoot::downcast(node).unwrap())
5644 })
5645 }
5646
5647 fn SetBody(&self, cx: &mut JSContext, new_body: Option<&HTMLElement>) -> ErrorResult {
5649 let new_body = match new_body {
5651 Some(new_body) => new_body,
5652 None => return Err(Error::HierarchyRequest(None)),
5653 };
5654
5655 let node = new_body.upcast::<Node>();
5656 match node.type_id() {
5657 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5658 NodeTypeId::Element(ElementTypeId::HTMLElement(
5659 HTMLElementTypeId::HTMLFrameSetElement,
5660 )) => {},
5661 _ => return Err(Error::HierarchyRequest(None)),
5662 }
5663
5664 let old_body = self.GetBody();
5666 if old_body.as_deref() == Some(new_body) {
5667 return Ok(());
5668 }
5669
5670 match (self.GetDocumentElement(), &old_body) {
5671 (Some(ref root), Some(child)) => {
5674 let root = root.upcast::<Node>();
5675 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
5676 .map(|_| ())
5677 },
5678
5679 (None, _) => Err(Error::HierarchyRequest(None)),
5681
5682 (Some(ref root), &None) => {
5685 let root = root.upcast::<Node>();
5686 root.AppendChild(cx, new_body.upcast()).map(|_| ())
5687 },
5688 }
5689 }
5690
5691 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5693 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5694 }
5695
5696 fn Images(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5698 self.images.or_init(|| {
5699 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5700 element.is::<HTMLImageElement>()
5701 })
5702 })
5703 }
5704
5705 fn Embeds(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5707 self.embeds.or_init(|| {
5708 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5709 element.is::<HTMLEmbedElement>()
5710 })
5711 })
5712 }
5713
5714 fn Plugins(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5716 self.Embeds(cx)
5717 }
5718
5719 fn Links(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5721 self.links.or_init(|| {
5722 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5723 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5724 element.has_attribute(&local_name!("href"))
5725 })
5726 })
5727 }
5728
5729 fn Forms(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5731 self.forms.or_init(|| {
5732 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5733 element.is::<HTMLFormElement>()
5734 })
5735 })
5736 }
5737
5738 fn Scripts(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5740 self.scripts.or_init(|| {
5741 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5742 element.is::<HTMLScriptElement>()
5743 })
5744 })
5745 }
5746
5747 fn Anchors(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5749 self.anchors.or_init(|| {
5750 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5751 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5752 })
5753 })
5754 }
5755
5756 fn Applets(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5758 self.applets
5759 .or_init(|| HTMLCollection::always_empty(cx, &self.window, self.upcast()))
5760 }
5761
5762 fn GetLocation(&self, cx: &mut JSContext) -> Option<DomRoot<Location>> {
5764 if self.is_fully_active() {
5765 Some(self.window.Location(cx))
5766 } else {
5767 None
5768 }
5769 }
5770
5771 fn Children(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
5773 HTMLCollection::children(cx, &self.window, self.upcast())
5774 }
5775
5776 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5778 self.upcast::<Node>().child_elements().next()
5779 }
5780
5781 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5783 self.upcast::<Node>()
5784 .rev_children()
5785 .find_map(DomRoot::downcast)
5786 }
5787
5788 fn ChildElementCount(&self) -> u32 {
5790 self.upcast::<Node>().child_elements().count() as u32
5791 }
5792
5793 fn Prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5795 self.upcast::<Node>().prepend(cx, nodes)
5796 }
5797
5798 fn Append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5800 self.upcast::<Node>().append(cx, nodes)
5801 }
5802
5803 fn ReplaceChildren(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5805 self.upcast::<Node>().replace_children(cx, nodes)
5806 }
5807
5808 fn MoveBefore(&self, cx: &mut JSContext, node: &Node, child: Option<&Node>) -> ErrorResult {
5810 self.upcast::<Node>().move_before(cx, node, child)
5811 }
5812
5813 fn QuerySelector(
5815 &self,
5816 cx: &mut JSContext,
5817 selectors: DOMString,
5818 ) -> Fallible<Option<DomRoot<Element>>> {
5819 self.upcast::<Node>().query_selector(cx.no_gc(), selectors)
5820 }
5821
5822 fn QuerySelectorAll(
5824 &self,
5825 cx: &mut JSContext,
5826 selectors: DOMString,
5827 ) -> Fallible<DomRoot<NodeList>> {
5828 self.upcast::<Node>()
5829 .query_selector_all(cx.no_gc(), selectors)
5830 }
5831
5832 fn ReadyState(&self) -> DocumentReadyState {
5834 self.ready_state.get()
5835 }
5836
5837 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5839 if self.has_browsing_context {
5840 Some(DomRoot::from_ref(&*self.window))
5841 } else {
5842 None
5843 }
5844 }
5845
5846 fn GetCookie(&self) -> Fallible<DOMString> {
5848 if self.is_cookie_averse() {
5849 return Ok(DOMString::new());
5850 }
5851
5852 if !self.origin().is_tuple() {
5853 return Err(Error::Security(None));
5854 }
5855
5856 let url = self.url();
5857 let (tx, rx) =
5858 profile_generic_channel::channel(self.global().time_profiler_chan().clone()).unwrap();
5859 let _ = self
5860 .window
5861 .as_global_scope()
5862 .resource_threads()
5863 .send(GetCookieStringForUrl(url, tx, NonHTTP));
5864 let cookies = rx.recv().unwrap();
5865 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5866 }
5867
5868 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5870 if self.is_cookie_averse() {
5871 return Ok(());
5872 }
5873
5874 if !self.origin().is_tuple() {
5875 return Err(Error::Security(None));
5876 }
5877
5878 if !cookie.is_valid_for_cookie() {
5879 return Ok(());
5880 }
5881
5882 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5883 vec![cookie]
5884 } else {
5885 vec![]
5886 };
5887
5888 let _ = self
5889 .window
5890 .as_global_scope()
5891 .resource_threads()
5892 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5893 Ok(())
5894 }
5895
5896 fn BgColor(&self) -> DOMString {
5898 self.get_body_attribute(&local_name!("bgcolor"))
5899 }
5900
5901 fn SetBgColor(&self, cx: &mut JSContext, value: DOMString) {
5903 self.set_body_attribute(cx, &local_name!("bgcolor"), value)
5904 }
5905
5906 fn FgColor(&self) -> DOMString {
5908 self.get_body_attribute(&local_name!("text"))
5909 }
5910
5911 fn SetFgColor(&self, cx: &mut JSContext, value: DOMString) {
5913 self.set_body_attribute(cx, &local_name!("text"), value)
5914 }
5915
5916 fn NamedGetter(&self, cx: &mut JSContext, name: DOMString) -> Option<NamedPropertyValue> {
5918 if name.is_empty() {
5919 return None;
5920 }
5921 let name = Atom::from(name);
5922
5923 let elements_with_name = self.get_elements_with_name(cx, &name);
5926 let name_iter = elements_with_name
5927 .iter()
5928 .filter(|elem| is_named_element_with_name_attribute(elem));
5929 let elements_with_id = self.id_map.get_all(cx.no_gc(), self.upcast(), &name);
5930 let id_iter = elements_with_id
5931 .iter()
5932 .filter(|elem| is_named_element_with_id_attribute(elem));
5933 let mut elements = name_iter.chain(id_iter);
5934
5935 let first = elements.next()?;
5942 if elements.all(|other| first == other) {
5943 if let Some(nested_window_proxy) = first
5944 .downcast::<HTMLIFrameElement>()
5945 .and_then(|iframe| iframe.GetContentWindow())
5946 {
5947 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5948 }
5949
5950 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5952 }
5953
5954 #[derive(JSTraceable, MallocSizeOf)]
5957 struct DocumentNamedGetter {
5958 #[no_trace]
5959 name: Atom,
5960 }
5961 impl CollectionFilter for DocumentNamedGetter {
5962 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5963 let type_ = match elem.upcast::<Node>().type_id() {
5964 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5965 _ => return false,
5966 };
5967 match type_ {
5968 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5969 elem.get_name().as_ref() == Some(&self.name)
5970 },
5971 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5972 name == *self.name ||
5973 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5974 }),
5975 _ => false,
5979 }
5980 }
5981 }
5982 let collection = HTMLCollection::create(
5983 cx,
5984 self.window(),
5985 self.upcast(),
5986 Box::new(DocumentNamedGetter { name }),
5987 );
5988 Some(NamedPropertyValue::HTMLCollection(collection))
5989 }
5990
5991 fn SupportedPropertyNames(&self, no_gc: &NoGC) -> Vec<DOMString> {
5993 let mut names_with_first_named_element_map = HashMap::new();
5994 self.name_map
5995 .for_each(no_gc, self.upcast(), |name, elements| {
5996 if name.is_empty() {
5997 return;
5998 }
5999 let mut name_iter = elements
6000 .iter()
6001 .filter(|elem| is_named_element_with_name_attribute(elem));
6002 if let Some(first) = name_iter.next() {
6003 names_with_first_named_element_map.insert(name.clone(), first.as_rooted());
6004 }
6005 });
6006
6007 self.id_map.for_each(no_gc, self.upcast(), |id, elements| {
6008 if id.is_empty() {
6009 return;
6010 }
6011 let mut id_iter = elements
6012 .iter()
6013 .filter(|elem| is_named_element_with_id_attribute(elem));
6014 if let Some(first) = id_iter.next() {
6015 match names_with_first_named_element_map.entry(id.clone()) {
6016 Vacant(entry) => drop(entry.insert(first.as_rooted())),
6017 Occupied(mut entry) => {
6018 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6019 *entry.get_mut() = first.as_rooted();
6020 }
6021 },
6022 }
6023 }
6024 });
6025
6026 let mut names_with_first_named_element_vec: Vec<_> =
6027 names_with_first_named_element_map.into_iter().collect();
6028 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6029 if a.1 == b.1 {
6030 a.0.cmp(&b.0)
6033 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6034 Ordering::Less
6035 } else {
6036 Ordering::Greater
6037 }
6038 });
6039
6040 names_with_first_named_element_vec
6041 .into_iter()
6042 .map(|(k, _)| DOMString::from(&*k))
6043 .collect()
6044 }
6045
6046 fn Clear(&self) {
6048 }
6050
6051 fn CaptureEvents(&self) {
6053 }
6055
6056 fn ReleaseEvents(&self) {
6058 }
6060
6061 global_event_handlers!();
6063
6064 event_handler!(
6066 readystatechange,
6067 GetOnreadystatechange,
6068 SetOnreadystatechange
6069 );
6070
6071 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6073 self.document_or_shadow_root.element_from_point(
6074 self.upcast(),
6075 x,
6076 y,
6077 self.GetDocumentElement(),
6078 self.has_browsing_context,
6079 )
6080 }
6081
6082 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6084 self.document_or_shadow_root.elements_from_point(
6085 self.upcast(),
6086 x,
6087 y,
6088 self.GetDocumentElement(),
6089 self.has_browsing_context,
6090 )
6091 }
6092
6093 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6095 if self.quirks_mode() == QuirksMode::Quirks {
6097 if let Some(ref body) = self.GetBody() {
6099 let e = body.upcast::<Element>();
6100 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6104 return Some(DomRoot::from_ref(e));
6105 }
6106 }
6107
6108 return None;
6110 }
6111
6112 self.GetDocumentElement()
6115 }
6116
6117 fn Open(
6119 &self,
6120 cx: &mut JSContext,
6121 _unused1: Option<DOMString>,
6122 _unused2: Option<DOMString>,
6123 ) -> Fallible<DomRoot<Document>> {
6124 if !self.is_html_document() {
6126 return Err(Error::InvalidState(None));
6127 }
6128
6129 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6132 return Err(Error::InvalidState(None));
6133 }
6134
6135 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6137
6138 if !self
6141 .origin()
6142 .same_origin(&entry_responsible_document.origin())
6143 {
6144 return Err(Error::Security(None));
6145 }
6146
6147 if self
6150 .active_parser()
6151 .is_some_and(|parser| parser.script_nesting_level() > 0)
6152 {
6153 return Ok(DomRoot::from_ref(self));
6154 }
6155
6156 if self.is_prompting_or_unloading() {
6158 return Ok(DomRoot::from_ref(self));
6159 }
6160
6161 if self.active_parser_was_aborted.get() {
6163 return Ok(DomRoot::from_ref(self));
6164 }
6165
6166 self.window().set_navigation_start();
6170
6171 if self.has_browsing_context() {
6175 self.abort(cx);
6178 }
6179
6180 for node in self
6183 .upcast::<Node>()
6184 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6185 {
6186 node.upcast::<EventTarget>().remove_all_listeners();
6187 }
6188
6189 if self.window.Document() == DomRoot::from_ref(self) {
6192 self.window.upcast::<EventTarget>().remove_all_listeners();
6193 }
6194
6195 Node::replace_all(cx, None, self.upcast::<Node>());
6197
6198 if self.is_fully_active() {
6205 let mut new_url = entry_responsible_document.url();
6207
6208 if entry_responsible_document != DomRoot::from_ref(self) {
6210 new_url.set_fragment(None);
6211 }
6212
6213 self.set_url(new_url);
6216 }
6217
6218 self.is_initial_about_blank.set(false);
6220
6221 self.set_quirks_mode(QuirksMode::NoQuirks);
6227
6228 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6234 *self.loader.borrow_mut() =
6235 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6236 ServoParser::parse_html_script_input(self, self.url());
6237
6238 self.ready_state.set(DocumentReadyState::Loading);
6244
6245 Ok(DomRoot::from_ref(self))
6247 }
6248
6249 fn Open_(
6251 &self,
6252 cx: &mut JSContext,
6253 url: USVString,
6254 target: DOMString,
6255 features: DOMString,
6256 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6257 self.browsing_context()
6258 .ok_or(Error::InvalidAccess(None))?
6259 .open(cx, url, target, features)
6260 }
6261
6262 fn Write(&self, cx: &mut JSContext, text: Vec<TrustedHTMLOrString>) -> ErrorResult {
6264 self.write(cx, text, false, "Document", "write")
6267 }
6268
6269 fn Writeln(&self, cx: &mut JSContext, text: Vec<TrustedHTMLOrString>) -> ErrorResult {
6271 self.write(cx, text, true, "Document", "writeln")
6274 }
6275
6276 fn Close(&self, cx: &mut JSContext) -> ErrorResult {
6278 if !self.is_html_document() {
6279 return Err(Error::InvalidState(None));
6281 }
6282
6283 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6286 return Err(Error::InvalidState(None));
6287 }
6288
6289 let parser = match self.get_current_parser() {
6291 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6292 _ => {
6293 return Ok(());
6294 },
6295 };
6296
6297 parser.close(cx);
6299
6300 Ok(())
6301 }
6302
6303 fn ExecCommand(
6305 &self,
6306 cx: &mut JSContext,
6307 command_id: DOMString,
6308 _show_ui: bool,
6309 value: TrustedHTMLOrString,
6310 ) -> Fallible<bool> {
6311 let value = if command_id == "insertHTML" {
6312 TrustedHTML::get_trusted_type_compliant_string(
6313 cx,
6314 self.window.as_global_scope(),
6315 value,
6316 "Document execCommand",
6317 )?
6318 } else {
6319 match value {
6320 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6321 TrustedHTMLOrString::String(value) => value,
6322 }
6323 };
6324
6325 Ok(self.exec_command_for_command_id(cx, command_id, value))
6326 }
6327
6328 fn QueryCommandEnabled(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6330 self.check_support_and_enabled(cx, &command_id).is_some()
6332 }
6333
6334 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6336 self.is_command_supported(command_id)
6340 }
6341
6342 fn QueryCommandIndeterm(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6344 self.is_command_indeterminate(cx, command_id)
6345 }
6346
6347 fn QueryCommandState(&self, cx: &mut JSContext, command_id: DOMString) -> bool {
6349 self.command_state_for_command(cx, command_id)
6350 }
6351
6352 fn QueryCommandValue(&self, cx: &mut JSContext, command_id: DOMString) -> DOMString {
6354 self.command_value_for_command(cx, command_id)
6355 }
6356
6357 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6359
6360 event_handler!(
6362 fullscreenchange,
6363 GetOnfullscreenchange,
6364 SetOnfullscreenchange
6365 );
6366
6367 fn FullscreenEnabled(&self) -> bool {
6369 self.get_allow_fullscreen()
6370 }
6371
6372 fn Fullscreen(&self) -> bool {
6374 self.fullscreen_element.get().is_some()
6375 }
6376
6377 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6379 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6380 }
6381
6382 fn ExitFullscreen(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
6384 self.exit_fullscreen(cx)
6385 }
6386
6387 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6391 match self.media_controls.borrow().get(&*id.str()) {
6392 Some(m) => Ok(DomRoot::from_ref(m)),
6393 None => Err(Error::InvalidAccess(None)),
6394 }
6395 }
6396
6397 fn GetSelection(&self, cx: &mut JSContext) -> Option<DomRoot<Selection>> {
6399 if self.has_browsing_context {
6400 Some(self.selection.or_init(|| Selection::new(cx, self)))
6401 } else {
6402 None
6403 }
6404 }
6405
6406 fn Fonts(&self, cx: &mut JSContext) -> DomRoot<FontFaceSet> {
6408 self.fonts
6409 .or_init(|| FontFaceSet::new(cx, &self.global(), None))
6410 }
6411
6412 fn Hidden(&self) -> bool {
6414 self.visibility_state.get() == DocumentVisibilityState::Hidden
6415 }
6416
6417 fn VisibilityState(&self) -> DocumentVisibilityState {
6419 self.visibility_state.get()
6420 }
6421
6422 fn CreateExpression(
6423 &self,
6424 cx: &mut JSContext,
6425 expression: DOMString,
6426 resolver: Option<Rc<XPathNSResolver>>,
6427 ) -> Fallible<DomRoot<crate::dom::types::XPathExpression>> {
6428 let parsed_expression =
6429 parse_expression(cx, &expression.str(), resolver, self.is_html_document())?;
6430 Ok(XPathExpression::new(
6431 cx,
6432 &self.window,
6433 None,
6434 parsed_expression,
6435 ))
6436 }
6437
6438 fn CreateNSResolver(&self, cx: &mut JSContext, node_resolver: &Node) -> DomRoot<Node> {
6439 let global = self.global();
6440 let window = global.as_window();
6441 let evaluator = XPathEvaluator::new(cx, window, None);
6442 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6443 }
6444
6445 fn Evaluate(
6446 &self,
6447 cx: &mut JSContext,
6448 expression: DOMString,
6449 context_node: &Node,
6450 resolver: Option<Rc<XPathNSResolver>>,
6451 result_type: u16,
6452 result: Option<&crate::dom::types::XPathResult>,
6453 ) -> Fallible<DomRoot<crate::dom::types::XPathResult>> {
6454 let parsed_expression =
6455 parse_expression(cx, &expression.str(), resolver, self.is_html_document())?;
6456 XPathExpression::new(cx, &self.window, None, parsed_expression).evaluate_internal(
6457 cx,
6458 context_node,
6459 result_type,
6460 result,
6461 )
6462 }
6463
6464 fn AdoptedStyleSheets(&self, cx: &mut JSContext, retval: MutableHandleValue) {
6466 self.adopted_stylesheets_frozen_types.get_or_init(
6467 cx,
6468 || {
6469 self.adopted_stylesheets
6470 .borrow()
6471 .clone()
6472 .iter()
6473 .map(|sheet| sheet.as_rooted())
6474 .collect()
6475 },
6476 retval,
6477 );
6478 }
6479
6480 fn SetAdoptedStyleSheets(&self, cx: &mut JSContext, val: HandleValue) -> ErrorResult {
6482 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6483 cx,
6484 self.adopted_stylesheets.borrow_mut().as_mut(),
6485 val,
6486 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6487 );
6488
6489 if result.is_ok() {
6491 self.adopted_stylesheets_frozen_types.clear()
6492 }
6493
6494 result
6495 }
6496
6497 fn Timeline(&self) -> DomRoot<DocumentTimeline> {
6498 self.timeline.as_rooted()
6499 }
6500}
6501
6502fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6503 if marker.get().is_none() {
6504 marker.set(Some(CrossProcessInstant::now()))
6505 }
6506}
6507
6508#[derive(JSTraceable, MallocSizeOf)]
6509pub(crate) enum AnimationFrameCallback {
6510 DevtoolsFramerateTick {
6511 actor_name: String,
6512 },
6513 FrameRequestCallback {
6514 #[conditional_malloc_size_of]
6515 callback: Rc<FrameRequestCallback>,
6516 },
6517}
6518
6519impl AnimationFrameCallback {
6520 fn call(&self, cx: &mut JSContext, document: &Document, now: f64) {
6521 match *self {
6522 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6523 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6524 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6525 devtools_sender.send(msg).unwrap();
6526 },
6527 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6528 let _ = callback.Call__(cx, Finite::wrap(now), ExceptionHandling::Report);
6531 },
6532 }
6533 }
6534}
6535
6536#[derive(Default, JSTraceable, MallocSizeOf)]
6537#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6538struct PendingInOrderScriptVec {
6539 scripts: DomRefCell<VecDeque<PendingScript>>,
6540}
6541
6542impl PendingInOrderScriptVec {
6543 fn is_empty(&self) -> bool {
6544 self.scripts.borrow().is_empty()
6545 }
6546
6547 fn push(&self, element: &HTMLScriptElement) {
6548 self.scripts
6549 .borrow_mut()
6550 .push_back(PendingScript::new(element));
6551 }
6552
6553 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6554 let mut scripts = self.scripts.borrow_mut();
6555 let entry = scripts
6556 .iter_mut()
6557 .find(|entry| &*entry.element == element)
6558 .unwrap();
6559 entry.loaded(result);
6560 }
6561
6562 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6563 let mut scripts = self.scripts.borrow_mut();
6564 let pair = scripts.front_mut()?.take_result()?;
6565 scripts.pop_front();
6566 Some(pair)
6567 }
6568
6569 fn clear(&self) {
6570 *self.scripts.borrow_mut() = Default::default();
6571 }
6572}
6573
6574#[derive(JSTraceable, MallocSizeOf)]
6575#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6576struct PendingScript {
6577 element: Dom<HTMLScriptElement>,
6578 load: Option<ScriptResult>,
6580}
6581
6582impl PendingScript {
6583 fn new(element: &HTMLScriptElement) -> Self {
6584 Self {
6585 element: Dom::from_ref(element),
6586 load: None,
6587 }
6588 }
6589
6590 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6591 Self {
6592 element: Dom::from_ref(element),
6593 load,
6594 }
6595 }
6596
6597 fn loaded(&mut self, result: ScriptResult) {
6598 assert!(self.load.is_none());
6599 self.load = Some(result);
6600 }
6601
6602 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6603 self.load
6604 .take()
6605 .map(|result| (DomRoot::from_ref(&*self.element), result))
6606 }
6607}
6608
6609fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6610 let type_ = match elem.upcast::<Node>().type_id() {
6611 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6612 _ => return false,
6613 };
6614 match type_ {
6615 HTMLElementTypeId::HTMLFormElement |
6616 HTMLElementTypeId::HTMLIFrameElement |
6617 HTMLElementTypeId::HTMLImageElement => true,
6618 _ => false,
6622 }
6623}
6624
6625fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6626 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6630}
6631
6632impl DocumentHelpers for Document {
6633 fn ensure_safe_to_run_script_or_layout(&self) {
6634 Document::ensure_safe_to_run_script_or_layout(self)
6635 }
6636}
6637
6638pub(crate) struct SameoriginAncestorNavigablesIterator {
6642 document: DomRoot<Document>,
6643}
6644
6645impl SameoriginAncestorNavigablesIterator {
6646 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6647 Self { document }
6648 }
6649}
6650
6651impl Iterator for SameoriginAncestorNavigablesIterator {
6652 type Item = DomRoot<Document>;
6653
6654 fn next(&mut self) -> Option<Self::Item> {
6655 let window_proxy = self.document.browsing_context()?;
6656 self.document = window_proxy.parent()?.document()?;
6657 Some(self.document.clone())
6658 }
6659}
6660
6661pub(crate) struct SameOriginDescendantNavigablesIterator {
6666 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6667}
6668
6669impl SameOriginDescendantNavigablesIterator {
6670 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6671 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6672 Self {
6673 stack: vec![Box::new(iframes.into_iter())],
6674 }
6675 }
6676
6677 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6678 let mut cur_iframe = self.stack.last_mut()?.next();
6679 while cur_iframe.is_none() {
6680 self.stack.pop();
6681 cur_iframe = self.stack.last_mut()?.next();
6682 }
6683 cur_iframe
6684 }
6685}
6686
6687impl Iterator for SameOriginDescendantNavigablesIterator {
6688 type Item = DomRoot<Document>;
6689
6690 fn next(&mut self) -> Option<Self::Item> {
6691 while let Some(iframe) = self.get_next_iframe() {
6692 let Some(pipeline_id) = iframe.pipeline_id() else {
6693 continue;
6694 };
6695
6696 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6697 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6698 document.iframes().iter().collect();
6699 self.stack.push(Box::new(child_iframes.into_iter()));
6700 return Some(document);
6701 } else {
6702 continue;
6703 };
6704 }
6705 None
6706 }
6707}