1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use base::cross_process_instant::CrossProcessInstant;
17use base::generic_channel::GenericSend;
18use base::id::WebViewId;
19use base::{Epoch, generic_channel};
20use bitflags::bitflags;
21use chrono::Local;
22use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
23use content_security_policy::sandboxing_directive::SandboxingFlagSet;
24use content_security_policy::{CspList, PolicyDisposition};
25use cookie::Cookie;
26use data_url::mime::Mime;
27use devtools_traits::ScriptToDevtoolsControlMsg;
28use dom_struct::dom_struct;
29use embedder_traits::{
30 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
31 Image, LoadStatus,
32};
33use encoding_rs::{Encoding, UTF_8};
34use fonts::WebFontDocumentContext;
35use html5ever::{LocalName, Namespace, QualName, local_name, ns};
36use hyper_serde::Serde;
37use js::rust::{HandleObject, HandleValue, MutableHandleValue};
38use layout_api::{
39 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
40 TrustedNodeAddress,
41};
42use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
43use net_traits::CookieSource::NonHTTP;
44use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
45use net_traits::ReferrerPolicy;
46use net_traits::policy_container::PolicyContainer;
47use net_traits::pub_domains::is_pub_domain;
48use net_traits::request::{
49 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
50};
51use net_traits::response::HttpsState;
52use percent_encoding::percent_decode;
53use profile_traits::ipc as profile_ipc;
54use profile_traits::time::TimerMetadataFrameType;
55use regex::bytes::Regex;
56use rustc_hash::{FxBuildHasher, FxHashMap};
57use script_bindings::interfaces::DocumentHelpers;
58use script_bindings::script_runtime::JSContext;
59use script_traits::{DocumentActivity, ProgressiveWebMetricType};
60use servo_arc::Arc;
61use servo_config::pref;
62use servo_media::{ClientContextId, ServoMedia};
63use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
64use style::attr::AttrValue;
65use style::context::QuirksMode;
66use style::invalidation::element::restyle_hints::RestyleHint;
67use style::selector_parser::Snapshot;
68use style::shared_lock::SharedRwLock as StyleSharedRwLock;
69use style::str::{split_html_space_chars, str_join};
70use style::stylesheet_set::DocumentStylesheetSet;
71use style::stylesheets::{Origin, OriginSet, Stylesheet};
72use stylo_atoms::Atom;
73use url::{Host, Position};
74
75use crate::animation_timeline::AnimationTimeline;
76use crate::animations::Animations;
77use crate::document_loader::{DocumentLoader, LoadType};
78use crate::dom::attr::Attr;
79use crate::dom::beforeunloadevent::BeforeUnloadEvent;
80use crate::dom::bindings::callback::ExceptionHandling;
81use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
82use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
83use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
84 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
85};
86use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
87use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
88use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
90#[cfg(any(feature = "webxr", feature = "gamepad"))]
91use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
92use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
93use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
94use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
95use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
96use crate::dom::bindings::codegen::Bindings::WindowBinding::{
97 FrameRequestCallback, ScrollBehavior, WindowMethods,
98};
99use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
100use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
101use crate::dom::bindings::codegen::UnionTypes::{
102 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
103};
104use crate::dom::bindings::domname::{
105 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
106};
107use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
108use crate::dom::bindings::frozenarray::CachedFrozenArray;
109use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
110use crate::dom::bindings::num::Finite;
111use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
112use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
113use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
114use crate::dom::bindings::str::{DOMString, USVString};
115use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
116use crate::dom::bindings::weakref::DOMTracker;
117use crate::dom::bindings::xmlname::matches_name_production;
118use crate::dom::cdatasection::CDATASection;
119use crate::dom::comment::Comment;
120use crate::dom::compositionevent::CompositionEvent;
121use crate::dom::css::cssstylesheet::CSSStyleSheet;
122use crate::dom::css::fontfaceset::FontFaceSet;
123use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
124use crate::dom::customelementregistry::{
125 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
126};
127use crate::dom::customevent::CustomEvent;
128use crate::dom::document_embedder_controls::DocumentEmbedderControls;
129use crate::dom::document_event_handler::DocumentEventHandler;
130use crate::dom::documentfragment::DocumentFragment;
131use crate::dom::documentorshadowroot::{
132 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
133};
134use crate::dom::documenttype::DocumentType;
135use crate::dom::domimplementation::DOMImplementation;
136use crate::dom::element::{
137 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
138 ElementPerformFullscreenExit,
139};
140use crate::dom::event::{Event, EventBubbles, EventCancelable};
141use crate::dom::eventtarget::EventTarget;
142use crate::dom::focusevent::FocusEvent;
143use crate::dom::globalscope::GlobalScope;
144use crate::dom::hashchangeevent::HashChangeEvent;
145use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
146use crate::dom::html::htmlareaelement::HTMLAreaElement;
147use crate::dom::html::htmlbaseelement::HTMLBaseElement;
148use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
149use crate::dom::html::htmlelement::HTMLElement;
150use crate::dom::html::htmlembedelement::HTMLEmbedElement;
151use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
152use crate::dom::html::htmlheadelement::HTMLHeadElement;
153use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
154use crate::dom::html::htmliframeelement::HTMLIFrameElement;
155use crate::dom::html::htmlimageelement::HTMLImageElement;
156use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
157use crate::dom::html::htmltitleelement::HTMLTitleElement;
158use crate::dom::htmldetailselement::DetailsNameGroups;
159use crate::dom::intersectionobserver::IntersectionObserver;
160use crate::dom::keyboardevent::KeyboardEvent;
161use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
162use crate::dom::location::Location;
163use crate::dom::messageevent::MessageEvent;
164use crate::dom::mouseevent::MouseEvent;
165use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
166use crate::dom::nodeiterator::NodeIterator;
167use crate::dom::nodelist::NodeList;
168use crate::dom::pagetransitionevent::PageTransitionEvent;
169use crate::dom::performance::performanceentry::PerformanceEntry;
170use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
171use crate::dom::processinginstruction::ProcessingInstruction;
172use crate::dom::promise::Promise;
173use crate::dom::range::Range;
174use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
175use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
176use crate::dom::selection::Selection;
177use crate::dom::servoparser::ServoParser;
178use crate::dom::shadowroot::ShadowRoot;
179use crate::dom::storageevent::StorageEvent;
180use crate::dom::text::Text;
181use crate::dom::touchevent::TouchEvent as DomTouchEvent;
182use crate::dom::touchlist::TouchList;
183use crate::dom::treewalker::TreeWalker;
184use crate::dom::trustedhtml::TrustedHTML;
185use crate::dom::types::{HTMLCanvasElement, HTMLDialogElement, VisibilityStateEntry};
186use crate::dom::uievent::UIEvent;
187use crate::dom::virtualmethods::vtable_for;
188use crate::dom::websocket::WebSocket;
189use crate::dom::window::Window;
190use crate::dom::windowproxy::WindowProxy;
191use crate::dom::xpathevaluator::XPathEvaluator;
192use crate::dom::xpathexpression::XPathExpression;
193use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
194use crate::iframe_collection::IFrameCollection;
195use crate::image_animation::ImageAnimationManager;
196use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
197use crate::mime::{APPLICATION, CHARSET};
198use crate::network_listener::{FetchResponseListener, NetworkListener};
199use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
200use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
201use crate::script_thread::ScriptThread;
202use crate::stylesheet_set::StylesheetSetRef;
203use crate::task::NonSendTaskBox;
204use crate::task_source::TaskSourceName;
205use crate::timers::OneshotTimerCallback;
206use crate::xpath::parse_expression;
207
208#[derive(Clone, Copy, PartialEq)]
209pub(crate) enum FireMouseEventType {
210 Move,
211 Over,
212 Out,
213 Enter,
214 Leave,
215}
216
217impl FireMouseEventType {
218 pub(crate) fn as_str(&self) -> &str {
219 match *self {
220 FireMouseEventType::Move => "mousemove",
221 FireMouseEventType::Over => "mouseover",
222 FireMouseEventType::Out => "mouseout",
223 FireMouseEventType::Enter => "mouseenter",
224 FireMouseEventType::Leave => "mouseleave",
225 }
226 }
227}
228
229#[derive(JSTraceable, MallocSizeOf)]
230pub(crate) struct RefreshRedirectDue {
231 #[no_trace]
232 pub(crate) url: ServoUrl,
233 #[ignore_malloc_size_of = "non-owning"]
234 pub(crate) window: DomRoot<Window>,
235}
236impl RefreshRedirectDue {
237 pub(crate) fn invoke(self, can_gc: CanGc) {
239 let load_data = self
249 .window
250 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
251 self.window
252 .load_url(NavigationHistoryBehavior::Replace, false, load_data, can_gc);
253 }
254}
255
256#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
257pub(crate) enum IsHTMLDocument {
258 HTMLDocument,
259 NonHTMLDocument,
260}
261
262#[derive(JSTraceable, MallocSizeOf)]
263#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
264struct FocusTransaction {
265 element: Option<Dom<Element>>,
267 has_focus: bool,
269 focus_options: FocusOptions,
271}
272
273#[derive(JSTraceable, MallocSizeOf)]
275pub(crate) enum DeclarativeRefresh {
276 PendingLoad {
277 #[no_trace]
278 url: ServoUrl,
279 time: u64,
280 },
281 CreatedAfterLoad,
282}
283
284#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
287pub(crate) struct RenderingUpdateReason(u8);
288
289bitflags! {
290 impl RenderingUpdateReason: u8 {
291 const ResizeObserverStartedObservingTarget = 1 << 0;
294 const IntersectionObserverStartedObservingTarget = 1 << 1;
297 const FontReadyPromiseFulfilled = 1 << 2;
301 }
302}
303
304#[dom_struct]
306pub(crate) struct Document {
307 node: Node,
308 document_or_shadow_root: DocumentOrShadowRoot,
309 window: Dom<Window>,
310 implementation: MutNullableDom<DOMImplementation>,
311 #[ignore_malloc_size_of = "type from external crate"]
312 #[no_trace]
313 content_type: Mime,
314 last_modified: Option<String>,
315 #[no_trace]
316 encoding: Cell<&'static Encoding>,
317 has_browsing_context: bool,
318 is_html_document: bool,
319 #[no_trace]
320 activity: Cell<DocumentActivity>,
321 #[no_trace]
323 url: DomRefCell<ServoUrl>,
324 #[no_trace]
326 about_base_url: DomRefCell<Option<ServoUrl>>,
327 #[ignore_malloc_size_of = "defined in selectors"]
328 #[no_trace]
329 quirks_mode: Cell<QuirksMode>,
330 event_handler: DocumentEventHandler,
332 embedder_controls: DocumentEmbedderControls,
334 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
337 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
338 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
339 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
340 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
341 images: MutNullableDom<HTMLCollection>,
342 embeds: MutNullableDom<HTMLCollection>,
343 links: MutNullableDom<HTMLCollection>,
344 forms: MutNullableDom<HTMLCollection>,
345 scripts: MutNullableDom<HTMLCollection>,
346 anchors: MutNullableDom<HTMLCollection>,
347 applets: MutNullableDom<HTMLCollection>,
348 iframes: RefCell<IFrameCollection>,
350 #[no_trace]
353 style_shared_lock: StyleSharedRwLock,
354 #[custom_trace]
356 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
357 stylesheet_list: MutNullableDom<StyleSheetList>,
358 ready_state: Cell<DocumentReadyState>,
359 domcontentloaded_dispatched: Cell<bool>,
361 focus_transaction: DomRefCell<Option<FocusTransaction>>,
363 focused: MutNullableDom<Element>,
365 #[no_trace]
367 focus_sequence: Cell<FocusSequenceNumber>,
368 has_focus: Cell<bool>,
372 current_script: MutNullableDom<HTMLScriptElement>,
374 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
376 script_blocking_stylesheets_count: Cell<u32>,
378 render_blocking_element_count: Cell<u32>,
381 deferred_scripts: PendingInOrderScriptVec,
383 asap_in_order_scripts_list: PendingInOrderScriptVec,
385 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
387 animation_frame_ident: Cell<u32>,
390 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
393 running_animation_callbacks: Cell<bool>,
398 loader: DomRefCell<DocumentLoader>,
400 current_parser: MutNullableDom<ServoParser>,
402 base_element: MutNullableDom<HTMLBaseElement>,
404 appropriate_template_contents_owner_document: MutNullableDom<Document>,
407 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
410 #[no_trace]
414 needs_restyle: Cell<RestyleReason>,
415 #[no_trace]
418 dom_interactive: Cell<Option<CrossProcessInstant>>,
419 #[no_trace]
420 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
421 #[no_trace]
422 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
423 #[no_trace]
424 dom_complete: Cell<Option<CrossProcessInstant>>,
425 #[no_trace]
426 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
427 #[no_trace]
428 load_event_start: Cell<Option<CrossProcessInstant>>,
429 #[no_trace]
430 load_event_end: Cell<Option<CrossProcessInstant>>,
431 #[no_trace]
432 unload_event_start: Cell<Option<CrossProcessInstant>>,
433 #[no_trace]
434 unload_event_end: Cell<Option<CrossProcessInstant>>,
435 #[no_trace]
437 https_state: Cell<HttpsState>,
438 #[no_trace]
440 origin: MutableOrigin,
441 referrer: Option<String>,
443 target_element: MutNullableDom<Element>,
445 #[no_trace]
447 policy_container: DomRefCell<PolicyContainer>,
448 #[no_trace]
450 preloaded_resources: DomRefCell<PreloadedResources>,
451 ignore_destructive_writes_counter: Cell<u32>,
453 ignore_opens_during_unload_counter: Cell<u32>,
455 spurious_animation_frames: Cell<u8>,
459
460 dom_count: Cell<u32>,
466 fullscreen_element: MutNullableDom<Element>,
468 form_id_listener_map:
475 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
476 #[no_trace]
477 interactive_time: DomRefCell<ProgressiveWebMetrics>,
478 #[no_trace]
479 tti_window: DomRefCell<InteractiveWindow>,
480 canceller: FetchCanceller,
482 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
484 page_showing: Cell<bool>,
486 salvageable: Cell<bool>,
488 active_parser_was_aborted: Cell<bool>,
490 fired_unload: Cell<bool>,
492 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
494 redirect_count: Cell<u16>,
496 script_and_layout_blockers: Cell<u32>,
498 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
500 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
501 completely_loaded: Cell<bool>,
503 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
505 shadow_roots_styles_changed: Cell<bool>,
507 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
513 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
516 has_pending_animated_image_update: Cell<bool>,
518 selection: MutNullableDom<Selection>,
520 animation_timeline: DomRefCell<AnimationTimeline>,
523 animations: Animations,
525 image_animation_manager: DomRefCell<ImageAnimationManager>,
527 dirty_root: MutNullableDom<Element>,
529 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
531 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
540 fonts: MutNullableDom<FontFaceSet>,
543 visibility_state: Cell<DocumentVisibilityState>,
545 status_code: Option<u16>,
547 is_initial_about_blank: Cell<bool>,
549 allow_declarative_shadow_roots: Cell<bool>,
551 #[no_trace]
553 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
554 has_trustworthy_ancestor_origin: Cell<bool>,
556 intersection_observer_task_queued: Cell<bool>,
558 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
570 highlighted_dom_node: MutNullableDom<Node>,
572 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
575 #[ignore_malloc_size_of = "mozjs"]
577 adopted_stylesheets_frozen_types: CachedFrozenArray,
578 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
580 rendering_update_reasons: Cell<RenderingUpdateReason>,
582 waiting_on_canvas_image_updates: Cell<bool>,
586 #[no_trace]
594 current_rendering_epoch: Cell<Epoch>,
595 #[conditional_malloc_size_of]
597 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
598 #[no_trace]
599 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
601 #[no_trace]
602 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
609 #[no_trace]
611 #[ignore_malloc_size_of = "TODO: unimplemented on Image"]
612 favicon: RefCell<Option<Image>>,
613
614 websockets: DOMTracker<WebSocket>,
616
617 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
619
620 #[no_trace]
622 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
623
624 layout_animations_test_enabled: bool,
626}
627
628impl Document {
629 fn unloading_cleanup_steps(&self) {
631 if self.close_outstanding_websockets() {
634 self.salvageable.set(false);
636 }
637
638 if !self.salvageable.get() {
643 let global_scope = self.window.as_global_scope();
644
645 global_scope.close_event_sources();
647
648 let msg = ScriptToConstellationMessage::DiscardDocument;
653 let _ = global_scope.script_to_constellation_chan().send(msg);
654 }
655 }
656
657 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
658 self.websockets.track(websocket);
659 }
660
661 fn close_outstanding_websockets(&self) -> bool {
662 let mut closed_any_websocket = false;
663 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
664 if websocket.make_disappear() {
665 closed_any_websocket = true;
666 }
667 });
668 closed_any_websocket
669 }
670
671 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
672 debug_assert!(*node.owner_doc() == *self);
673 if !node.is_connected() {
674 return;
675 }
676
677 let parent = match node.parent_in_flat_tree() {
678 Some(parent) => parent,
679 None => {
680 let document_element = match self.GetDocumentElement() {
683 Some(element) => element,
684 None => return,
685 };
686 if let Some(dirty_root) = self.dirty_root.get() {
687 for ancestor in dirty_root
690 .upcast::<Node>()
691 .inclusive_ancestors_in_flat_tree()
692 {
693 if ancestor.is::<Element>() {
694 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
695 }
696 }
697 }
698 self.dirty_root.set(Some(&document_element));
699 return;
700 },
701 };
702
703 if parent.is::<Element>() {
704 if !parent.is_styled() {
705 return;
706 }
707
708 if parent.is_display_none() {
709 return;
710 }
711 }
712
713 let element_parent: DomRoot<Element>;
714 let element = match node.downcast::<Element>() {
715 Some(element) => element,
716 None => {
717 match DomRoot::downcast::<Element>(parent) {
720 Some(parent) => {
721 element_parent = parent;
722 &element_parent
723 },
724 None => {
725 return;
729 },
730 }
731 },
732 };
733
734 let dirty_root = match self.dirty_root.get() {
735 Some(root) if root.is_connected() => root,
736 _ => {
737 element
738 .upcast::<Node>()
739 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
740 self.dirty_root.set(Some(element));
741 return;
742 },
743 };
744
745 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
746 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
747 return;
748 }
749
750 if ancestor.is::<Element>() {
751 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
752 }
753 }
754
755 let new_dirty_root = element
756 .upcast::<Node>()
757 .common_ancestor_in_flat_tree(dirty_root.upcast())
758 .expect("Couldn't find common ancestor");
759
760 let mut has_dirty_descendants = true;
761 for ancestor in dirty_root
762 .upcast::<Node>()
763 .inclusive_ancestors_in_flat_tree()
764 {
765 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
766 has_dirty_descendants &= *ancestor != *new_dirty_root;
767 }
768
769 self.dirty_root
770 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
771 }
772
773 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
774 self.dirty_root.take()
775 }
776
777 #[inline]
778 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
779 self.loader.borrow()
780 }
781
782 #[inline]
783 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
784 self.loader.borrow_mut()
785 }
786
787 #[inline]
788 pub(crate) fn has_browsing_context(&self) -> bool {
789 self.has_browsing_context
790 }
791
792 #[inline]
794 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
795 if self.has_browsing_context {
796 self.window.undiscarded_window_proxy()
797 } else {
798 None
799 }
800 }
801
802 pub(crate) fn webview_id(&self) -> WebViewId {
803 self.window.webview_id()
804 }
805
806 #[inline]
807 pub(crate) fn window(&self) -> &Window {
808 &self.window
809 }
810
811 #[inline]
812 pub(crate) fn is_html_document(&self) -> bool {
813 self.is_html_document
814 }
815
816 pub(crate) fn is_xhtml_document(&self) -> bool {
817 self.content_type.matches(APPLICATION, "xhtml+xml")
818 }
819
820 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
821 self.https_state.set(https_state);
822 }
823
824 pub(crate) fn is_fully_active(&self) -> bool {
825 self.activity.get() == DocumentActivity::FullyActive
826 }
827
828 pub(crate) fn is_active(&self) -> bool {
829 self.activity.get() != DocumentActivity::Inactive
830 }
831
832 #[inline]
833 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
834 self.current_rendering_epoch.get()
835 }
836
837 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
838 assert!(self.has_browsing_context);
840 if activity == self.activity.get() {
841 return;
842 }
843
844 self.activity.set(activity);
846 let media = ServoMedia::get();
847 let pipeline_id = self.window().pipeline_id();
848 let client_context_id =
849 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
850
851 if activity != DocumentActivity::FullyActive {
852 self.window().suspend(can_gc);
853 media.suspend(&client_context_id);
854 return;
855 }
856
857 self.title_changed();
858 self.notify_embedder_favicon();
859 self.dirty_all_nodes();
860 self.window().resume(can_gc);
861 media.resume(&client_context_id);
862
863 if self.ready_state.get() != DocumentReadyState::Complete {
864 return;
865 }
866
867 let document = Trusted::new(self);
871 self.owner_global()
872 .task_manager()
873 .dom_manipulation_task_source()
874 .queue(task!(fire_pageshow_event: move || {
875 let document = document.root();
876 let window = document.window();
877 if document.page_showing.get() {
879 return;
880 }
881 document.page_showing.set(true);
883 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
885 let event = PageTransitionEvent::new(
888 window,
889 atom!("pageshow"),
890 false, false, true, CanGc::note(),
894 );
895 let event = event.upcast::<Event>();
896 event.set_trusted(true);
897 window.dispatch_event_with_target_override(event, CanGc::note());
898 }))
899 }
900
901 pub(crate) fn origin(&self) -> &MutableOrigin {
902 &self.origin
903 }
904
905 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
906 *self.protocol_handler_automation_mode.borrow_mut() = mode;
907 }
908
909 pub(crate) fn url(&self) -> ServoUrl {
911 self.url.borrow().clone()
912 }
913
914 pub(crate) fn set_url(&self, url: ServoUrl) {
915 *self.url.borrow_mut() = url;
916 }
917
918 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
919 self.about_base_url.borrow().clone()
920 }
921
922 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
923 *self.about_base_url.borrow_mut() = about_base_url;
924 }
925
926 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
928 let document_url = self.url();
929 if document_url.as_str() == "about:srcdoc" {
931 return self
934 .about_base_url()
935 .expect("about:srcdoc page should always have an about base URL");
936 }
937
938 if document_url.matches_about_blank() {
941 if let Some(about_base_url) = self.about_base_url() {
942 return about_base_url;
943 }
944 }
945
946 document_url
948 }
949
950 pub(crate) fn base_url(&self) -> ServoUrl {
952 match self.base_element() {
953 None => self.fallback_base_url(),
955 Some(base) => base.frozen_base_url(),
957 }
958 }
959
960 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
961 self.needs_restyle.set(self.needs_restyle.get() | reason)
962 }
963
964 pub(crate) fn clear_restyle_reasons(&self) {
965 self.needs_restyle.set(RestyleReason::empty());
966 }
967
968 pub(crate) fn restyle_reason(&self) -> RestyleReason {
969 let mut condition = self.needs_restyle.get();
970 if self.stylesheets.borrow().has_changed() {
971 condition.insert(RestyleReason::StylesheetsChanged);
972 }
973
974 if let Some(root) = self.GetDocumentElement() {
978 if root.upcast::<Node>().has_dirty_descendants() {
979 condition.insert(RestyleReason::DOMChanged);
980 }
981 }
982
983 if !self.pending_restyles.borrow().is_empty() {
984 condition.insert(RestyleReason::PendingRestyles);
985 }
986
987 condition
988 }
989
990 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
992 self.base_element.get()
993 }
994
995 pub(crate) fn refresh_base_element(&self) {
998 if let Some(base_element) = self.base_element.get() {
999 base_element.clear_frozen_base_url();
1000 }
1001 let new_base_element = self
1002 .upcast::<Node>()
1003 .traverse_preorder(ShadowIncluding::No)
1004 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1005 .find(|element| {
1006 element
1007 .upcast::<Element>()
1008 .has_attribute(&local_name!("href"))
1009 });
1010 if let Some(ref new_base_element) = new_base_element {
1011 new_base_element.set_frozen_base_url();
1012 }
1013 self.base_element.set(new_base_element.as_deref());
1014 }
1015
1016 pub(crate) fn dom_count(&self) -> u32 {
1017 self.dom_count.get()
1018 }
1019
1020 pub(crate) fn increment_dom_count(&self) {
1024 self.dom_count.set(self.dom_count.get() + 1);
1025 }
1026
1027 pub(crate) fn decrement_dom_count(&self) {
1029 self.dom_count.set(self.dom_count.get() - 1);
1030 }
1031
1032 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1033 self.quirks_mode.get()
1034 }
1035
1036 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1037 let old_mode = self.quirks_mode.replace(new_mode);
1038
1039 if old_mode != new_mode {
1040 self.window.layout_mut().set_quirks_mode(new_mode);
1041 }
1042 }
1043
1044 pub(crate) fn encoding(&self) -> &'static Encoding {
1045 self.encoding.get()
1046 }
1047
1048 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1049 self.encoding.set(encoding);
1050 }
1051
1052 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1053 if node.is_connected() {
1054 node.note_dirty_descendants();
1055 }
1056
1057 node.dirty(NodeDamage::ContentOrHeritage);
1060 }
1061
1062 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1064 self.document_or_shadow_root
1065 .unregister_named_element(&self.id_map, to_unregister, &id);
1066 self.reset_form_owner_for_listeners(&id, can_gc);
1067 }
1068
1069 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1071 let root = self.GetDocumentElement().expect(
1072 "The element is in the document, so there must be a document \
1073 element.",
1074 );
1075 self.document_or_shadow_root.register_named_element(
1076 &self.id_map,
1077 element,
1078 &id,
1079 DomRoot::from_ref(root.upcast::<Node>()),
1080 );
1081 self.reset_form_owner_for_listeners(&id, can_gc);
1082 }
1083
1084 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1086 self.document_or_shadow_root
1087 .unregister_named_element(&self.name_map, to_unregister, &name);
1088 }
1089
1090 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1092 let root = self.GetDocumentElement().expect(
1093 "The element is in the document, so there must be a document \
1094 element.",
1095 );
1096 self.document_or_shadow_root.register_named_element(
1097 &self.name_map,
1098 element,
1099 &name,
1100 DomRoot::from_ref(root.upcast::<Node>()),
1101 );
1102 }
1103
1104 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1105 &self,
1106 id: DOMString,
1107 listener: &T,
1108 ) {
1109 let mut map = self.form_id_listener_map.borrow_mut();
1110 let listener = listener.to_element();
1111 let set = map.entry(Atom::from(id)).or_default();
1112 set.insert(Dom::from_ref(listener));
1113 }
1114
1115 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1116 &self,
1117 id: DOMString,
1118 listener: &T,
1119 ) {
1120 let mut map = self.form_id_listener_map.borrow_mut();
1121 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1122 entry
1123 .get_mut()
1124 .remove(&Dom::from_ref(listener.to_element()));
1125 if entry.get().is_empty() {
1126 entry.remove();
1127 }
1128 }
1129 }
1130
1131 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1133 self.get_element_by_id(&Atom::from(fragment))
1137 .or_else(|| self.get_anchor_by_name(fragment))
1141 }
1142
1143 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1146 if fragment.is_empty() {
1156 return Some(DomRoot::from_ref(self.upcast()));
1157 }
1158 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1160 {
1161 return Some(DomRoot::upcast(potential_indicated_element));
1163 }
1164 let fragment_bytes = percent_decode(fragment.as_bytes());
1166 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1168 return None;
1169 };
1170 if let Some(potential_indicated_element) =
1172 self.find_a_potential_indicated_element(&decoded_fragment)
1173 {
1174 return Some(DomRoot::upcast(potential_indicated_element));
1176 }
1177 if decoded_fragment.eq_ignore_ascii_case("top") {
1179 return Some(DomRoot::from_ref(self.upcast()));
1180 }
1181 None
1183 }
1184
1185 pub(crate) fn scroll_to_the_fragment(&self, fragment: &str) {
1187 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1192 self.set_target_element(None);
1193 return;
1194 };
1195 if *indicated_part == *self.upcast() {
1197 self.set_target_element(None);
1199 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1204 return;
1206 }
1207 let Some(target) = indicated_part.downcast::<Element>() else {
1210 unreachable!("Indicated part should always be an element");
1212 };
1213 self.set_target_element(Some(target));
1215 target.scroll_into_view_with_options(
1219 ScrollBehavior::Auto,
1220 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1221 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1222 None,
1223 None,
1224 );
1225 }
1230
1231 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1232 let name = Atom::from(name);
1233 self.name_map.borrow().get(&name).and_then(|elements| {
1234 elements
1235 .iter()
1236 .find(|e| e.is::<HTMLAnchorElement>())
1237 .map(|e| DomRoot::from_ref(&**e))
1238 })
1239 }
1240
1241 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1243 match state {
1244 DocumentReadyState::Loading => {
1245 if self.window().is_top_level() {
1246 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1247 self.webview_id(),
1248 LoadStatus::Started,
1249 ));
1250 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1251 }
1252 },
1253 DocumentReadyState::Complete => {
1254 if self.window().is_top_level() {
1255 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1256 self.webview_id(),
1257 LoadStatus::Complete,
1258 ));
1259 }
1260 update_with_current_instant(&self.dom_complete);
1261 },
1262 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1263 };
1264
1265 self.ready_state.set(state);
1266
1267 self.upcast::<EventTarget>()
1268 .fire_event(atom!("readystatechange"), can_gc);
1269 }
1270
1271 pub(crate) fn scripting_enabled(&self) -> bool {
1274 self.has_browsing_context() &&
1277 !self.has_active_sandboxing_flag(
1281 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1282 )
1283 }
1284
1285 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1288 self.focused.get()
1289 }
1290
1291 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1296 self.focus_sequence.get()
1297 }
1298
1299 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1301 self.focus_sequence.set(FocusSequenceNumber(
1302 self.focus_sequence
1303 .get()
1304 .0
1305 .checked_add(1)
1306 .expect("too many focus messages have been sent"),
1307 ));
1308 self.focus_sequence.get()
1309 }
1310
1311 pub(crate) fn has_focus_transaction(&self) -> bool {
1312 self.focus_transaction.borrow().is_some()
1313 }
1314
1315 pub(crate) fn begin_focus_transaction(&self) {
1318 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1320 element: self.focused.get().as_deref().map(Dom::from_ref),
1321 has_focus: self.has_focus.get(),
1322 focus_options: FocusOptions {
1323 preventScroll: true,
1324 },
1325 });
1326 }
1327
1328 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1330 if Some(not_focusable) != self.focused.get().as_deref() {
1333 return;
1334 }
1335
1336 let implicit_transaction = self.focus_transaction.borrow().is_none();
1337
1338 if implicit_transaction {
1339 self.begin_focus_transaction();
1340 }
1341
1342 {
1345 let mut focus_transaction = self.focus_transaction.borrow_mut();
1346 focus_transaction.as_mut().unwrap().element = None;
1347 }
1348
1349 if implicit_transaction {
1350 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1351 }
1352 }
1353
1354 pub(crate) fn request_focus(
1357 &self,
1358 elem: Option<&Element>,
1359 focus_initiator: FocusInitiator,
1360 can_gc: CanGc,
1361 ) {
1362 self.request_focus_with_options(
1363 elem,
1364 focus_initiator,
1365 FocusOptions {
1366 preventScroll: true,
1367 },
1368 can_gc,
1369 );
1370 }
1371
1372 pub(crate) fn request_focus_with_options(
1378 &self,
1379 elem: Option<&Element>,
1380 focus_initiator: FocusInitiator,
1381 focus_options: FocusOptions,
1382 can_gc: CanGc,
1383 ) {
1384 if elem.is_some_and(|e| !e.is_focusable_area()) {
1387 return;
1388 }
1389
1390 let implicit_transaction = self.focus_transaction.borrow().is_none();
1391
1392 if implicit_transaction {
1393 self.begin_focus_transaction();
1394 }
1395
1396 {
1397 let mut focus_transaction = self.focus_transaction.borrow_mut();
1398 let focus_transaction = focus_transaction.as_mut().unwrap();
1399 focus_transaction.element = elem.map(Dom::from_ref);
1400 focus_transaction.has_focus = true;
1401 focus_transaction.focus_options = focus_options;
1402 }
1403
1404 if implicit_transaction {
1405 self.commit_focus_transaction(focus_initiator, can_gc);
1406 }
1407 }
1408
1409 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1413 if self.window().parent_info().is_none() {
1414 warn!("Top-level document cannot be unfocused");
1415 return;
1416 }
1417
1418 assert!(
1421 self.focus_transaction.borrow().is_none(),
1422 "there mustn't be an in-progress focus transaction at this point"
1423 );
1424
1425 self.begin_focus_transaction();
1427
1428 {
1430 let mut focus_transaction = self.focus_transaction.borrow_mut();
1431 focus_transaction.as_mut().unwrap().has_focus = false;
1432 }
1433
1434 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1436 }
1437
1438 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1441 let (mut new_focused, new_focus_state, prevent_scroll) = {
1442 let focus_transaction = self.focus_transaction.borrow();
1443 let focus_transaction = focus_transaction
1444 .as_ref()
1445 .expect("no focus transaction in progress");
1446 (
1447 focus_transaction
1448 .element
1449 .as_ref()
1450 .map(|e| DomRoot::from_ref(&**e)),
1451 focus_transaction.has_focus,
1452 focus_transaction.focus_options.preventScroll,
1453 )
1454 };
1455 *self.focus_transaction.borrow_mut() = None;
1456
1457 if !new_focus_state {
1458 if new_focused.take().is_some() {
1461 trace!(
1462 "Forgetting the document's focused area because the \
1463 document's container was removed from the top-level BC's \
1464 focus chain"
1465 );
1466 }
1467 }
1468
1469 let old_focused = self.focused.get();
1470 let old_focus_state = self.has_focus.get();
1471
1472 debug!(
1473 "Committing focus transaction: {:?} → {:?}",
1474 (&old_focused, old_focus_state),
1475 (&new_focused, new_focus_state),
1476 );
1477
1478 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1481 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1482
1483 let trace_focus_chain = |name, element, doc| {
1484 trace!(
1485 "{} local focus chain: {}",
1486 name,
1487 match (element, doc) {
1488 (Some(e), _) => format!("[{:?}, document]", e),
1489 (None, true) => "[document]".to_owned(),
1490 (None, false) => "[]".to_owned(),
1491 }
1492 );
1493 };
1494
1495 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1496 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1497
1498 if old_focused_filtered != new_focused_filtered {
1499 if let Some(elem) = &old_focused_filtered {
1500 let node = elem.upcast::<Node>();
1501 elem.set_focus_state(false);
1502 if node.is_connected() {
1504 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1505 }
1506 }
1507 }
1508
1509 if old_focus_state != new_focus_state && !new_focus_state {
1510 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1511 }
1512
1513 self.focused.set(new_focused.as_deref());
1514 self.has_focus.set(new_focus_state);
1515
1516 if old_focus_state != new_focus_state && new_focus_state {
1517 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1518 }
1519
1520 if old_focused_filtered != new_focused_filtered {
1521 if let Some(elem) = &new_focused_filtered {
1522 elem.set_focus_state(true);
1523 let node = elem.upcast::<Node>();
1524 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1526
1527 if !prevent_scroll {
1530 let scroll_axis = ScrollAxisState {
1533 position: ScrollLogicalPosition::Center,
1534 requirement: ScrollRequirement::IfNotVisible,
1535 };
1536
1537 elem.scroll_into_view_with_options(
1541 ScrollBehavior::Smooth,
1542 scroll_axis,
1543 scroll_axis,
1544 None,
1545 None,
1546 );
1547 }
1548 }
1549 }
1550
1551 if focus_initiator != FocusInitiator::Local {
1552 return;
1553 }
1554
1555 match (old_focus_state, new_focus_state) {
1558 (_, true) => {
1559 let child_browsing_context_id = new_focused
1580 .as_ref()
1581 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1582 .and_then(|iframe| iframe.browsing_context_id());
1583
1584 let sequence = self.increment_fetch_focus_sequence();
1585
1586 debug!(
1587 "Advertising the focus request to the constellation \
1588 with sequence number {} and child BC ID {}",
1589 sequence,
1590 child_browsing_context_id
1591 .as_ref()
1592 .map(|id| id as &dyn std::fmt::Display)
1593 .unwrap_or(&"(none)"),
1594 );
1595
1596 self.window()
1597 .send_to_constellation(ScriptToConstellationMessage::Focus(
1598 child_browsing_context_id,
1599 sequence,
1600 ));
1601 },
1602 (false, false) => {
1603 },
1606 (true, false) => {
1607 unreachable!(
1608 "Can't lose the document's focus without specifying \
1609 another one to focus"
1610 );
1611 },
1612 }
1613 }
1614
1615 pub(crate) fn title_changed(&self) {
1617 if self.browsing_context().is_some() {
1618 self.send_title_to_embedder();
1619 let title = String::from(self.Title());
1620 self.window
1621 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1622 self.window.pipeline_id(),
1623 title.clone(),
1624 ));
1625 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1626 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1627 self.window.pipeline_id(),
1628 title,
1629 ));
1630 }
1631 }
1632 }
1633
1634 fn title(&self) -> Option<DOMString> {
1638 let title = self.GetDocumentElement().and_then(|root| {
1639 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1640 root.upcast::<Node>()
1642 .child_elements()
1643 .find(|node| {
1644 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1645 })
1646 .map(DomRoot::upcast::<Node>)
1647 } else {
1648 root.upcast::<Node>()
1650 .traverse_preorder(ShadowIncluding::No)
1651 .find(|node| node.is::<HTMLTitleElement>())
1652 }
1653 });
1654
1655 title.map(|title| {
1656 let value = title.child_text_content();
1658 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1659 })
1660 }
1661
1662 pub(crate) fn send_title_to_embedder(&self) {
1664 let window = self.window();
1665 if window.is_top_level() {
1666 let title = self.title().map(String::from);
1667 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1668 }
1669 }
1670
1671 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1672 let window = self.window();
1673 window.send_to_embedder(msg);
1674 }
1675
1676 pub(crate) fn dirty_all_nodes(&self) {
1677 let root = match self.GetDocumentElement() {
1678 Some(root) => root,
1679 None => return,
1680 };
1681 for node in root
1682 .upcast::<Node>()
1683 .traverse_preorder(ShadowIncluding::Yes)
1684 {
1685 node.dirty(NodeDamage::Other)
1686 }
1687 }
1688
1689 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1691 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1703 for target in notify_list.iter() {
1704 if target.downcast::<Document>().is_some() {
1705 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1708 } else if target.downcast::<Element>().is_some() {
1709 target.fire_event(Atom::from("scroll"), can_gc);
1712 }
1713 }
1714
1715 }
1719
1720 pub(crate) fn handle_viewport_scroll_event(&self) {
1724 let target = self.upcast::<EventTarget>();
1733 if self
1734 .pending_scroll_event_targets
1735 .borrow()
1736 .iter()
1737 .any(|other_target| *other_target == target)
1738 {
1739 return;
1740 }
1741
1742 self.pending_scroll_event_targets
1745 .borrow_mut()
1746 .push(Dom::from_ref(target));
1747 }
1748
1749 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1753 let target = element.upcast::<EventTarget>();
1763 if self
1764 .pending_scroll_event_targets
1765 .borrow()
1766 .iter()
1767 .any(|other_target| *other_target == target)
1768 {
1769 return;
1770 }
1771
1772 self.pending_scroll_event_targets
1775 .borrow_mut()
1776 .push(Dom::from_ref(target));
1777 }
1778
1779 pub(crate) fn node_from_nodes_and_strings(
1781 &self,
1782 mut nodes: Vec<NodeOrString>,
1783 can_gc: CanGc,
1784 ) -> Fallible<DomRoot<Node>> {
1785 if nodes.len() == 1 {
1786 Ok(match nodes.pop().unwrap() {
1787 NodeOrString::Node(node) => node,
1788 NodeOrString::String(string) => {
1789 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1790 },
1791 })
1792 } else {
1793 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1794 for node in nodes {
1795 match node {
1796 NodeOrString::Node(node) => {
1797 fragment.AppendChild(&node, can_gc)?;
1798 },
1799 NodeOrString::String(string) => {
1800 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1801 fragment.AppendChild(&node, can_gc).unwrap();
1804 },
1805 }
1806 }
1807 Ok(fragment)
1808 }
1809 }
1810
1811 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1812 match self.GetBody() {
1813 Some(ref body) if body.is_body_element() => {
1814 body.upcast::<Element>().get_string_attribute(local_name)
1815 },
1816 _ => DOMString::new(),
1817 }
1818 }
1819
1820 pub(crate) fn set_body_attribute(
1821 &self,
1822 local_name: &LocalName,
1823 value: DOMString,
1824 can_gc: CanGc,
1825 ) {
1826 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1827 let body = body.upcast::<Element>();
1828 let value = body.parse_attribute(&ns!(), local_name, value);
1829 body.set_attribute(local_name, value, can_gc);
1830 }
1831 }
1832
1833 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1834 self.current_script.set(script);
1835 }
1836
1837 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1838 self.script_blocking_stylesheets_count.get()
1839 }
1840
1841 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1842 let count_cell = &self.script_blocking_stylesheets_count;
1843 count_cell.set(count_cell.get() + 1);
1844 }
1845
1846 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1847 let count_cell = &self.script_blocking_stylesheets_count;
1848 assert!(count_cell.get() > 0);
1849 count_cell.set(count_cell.get() - 1);
1850 }
1851
1852 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1853 self.render_blocking_element_count.get()
1854 }
1855
1856 pub(crate) fn increment_render_blocking_element_count(&self) {
1857 let count_cell = &self.render_blocking_element_count;
1858 count_cell.set(count_cell.get() + 1);
1859 }
1860
1861 pub(crate) fn decrement_render_blocking_element_count(&self) {
1862 let count_cell = &self.render_blocking_element_count;
1863 assert!(count_cell.get() > 0);
1864 count_cell.set(count_cell.get() - 1);
1865 }
1866
1867 pub(crate) fn invalidate_stylesheets(&self) {
1868 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1869
1870 if let Some(element) = self.GetDocumentElement() {
1874 element.upcast::<Node>().dirty(NodeDamage::Style);
1875 }
1876 }
1877
1878 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1881 !self.animation_frame_list.borrow().is_empty()
1882 }
1883
1884 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1886 let ident = self.animation_frame_ident.get() + 1;
1887 self.animation_frame_ident.set(ident);
1888
1889 let had_animation_frame_callbacks;
1890 {
1891 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1892 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1893 animation_frame_list.push_back((ident, Some(callback)));
1894 }
1895
1896 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1902 self.window().send_to_constellation(
1903 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1904 AnimationState::AnimationCallbacksPresent,
1905 ),
1906 );
1907 }
1908
1909 ident
1910 }
1911
1912 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1914 let mut list = self.animation_frame_list.borrow_mut();
1915 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1916 pair.1 = None;
1917 }
1918 }
1919
1920 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1922 let _realm = enter_realm(self);
1923
1924 self.running_animation_callbacks.set(true);
1925 let timing = self.global().performance().Now();
1926
1927 let num_callbacks = self.animation_frame_list.borrow().len();
1928 for _ in 0..num_callbacks {
1929 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1930 if let Some(callback) = maybe_callback {
1931 callback.call(self, *timing, can_gc);
1932 }
1933 }
1934 self.running_animation_callbacks.set(false);
1935
1936 if self.animation_frame_list.borrow().is_empty() {
1937 self.window().send_to_constellation(
1938 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1939 AnimationState::NoAnimationCallbacksPresent,
1940 ),
1941 );
1942 }
1943 }
1944
1945 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1946 self.policy_container.borrow()
1947 }
1948
1949 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1950 *self.policy_container.borrow_mut() = policy_container;
1951 }
1952
1953 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1954 self.policy_container.borrow_mut().set_csp_list(csp_list);
1955 }
1956
1957 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1958 self.policy_container.borrow().csp_list.clone()
1959 }
1960
1961 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1962 self.preloaded_resources.borrow()
1963 }
1964
1965 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1966 self.preloaded_resources
1967 .borrow_mut()
1968 .insert(key, preload_id);
1969 }
1970
1971 pub(crate) fn fetch<Listener: FetchResponseListener>(
1972 &self,
1973 load: LoadType,
1974 mut request: RequestBuilder,
1975 listener: Listener,
1976 ) {
1977 request = request
1978 .insecure_requests_policy(self.insecure_requests_policy())
1979 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1980 let callback = NetworkListener {
1981 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1982 task_source: self
1983 .owner_global()
1984 .task_manager()
1985 .networking_task_source()
1986 .into(),
1987 }
1988 .into_callback();
1989 self.loader_mut()
1990 .fetch_async_with_callback(load, request, callback);
1991 }
1992
1993 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1994 &self,
1995 mut request: RequestBuilder,
1996 listener: Listener,
1997 ) {
1998 request = request
1999 .insecure_requests_policy(self.insecure_requests_policy())
2000 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
2001 let callback = NetworkListener {
2002 context: std::sync::Arc::new(Mutex::new(Some(listener))),
2003 task_source: self
2004 .owner_global()
2005 .task_manager()
2006 .networking_task_source()
2007 .into(),
2008 }
2009 .into_callback();
2010 self.loader_mut().fetch_async_background(request, callback);
2011 }
2012
2013 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
2015 match self.window().window_proxy().frame_element() {
2016 None => DomRoot::from_ref(self),
2019 Some(container) => container.owner_document().deferred_fetch_control_document(),
2021 }
2022 }
2023
2024 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
2026 let control_document = self.deferred_fetch_control_document();
2028 let navigable = control_document.window();
2030 let is_top_level = navigable.is_top_level();
2033 let deferred_fetch_allowed = true;
2037 let deferred_fetch_minimal_allowed = true;
2041 let mut quota = match is_top_level {
2043 true if !deferred_fetch_allowed => 0,
2045 true if !deferred_fetch_minimal_allowed => 640 * 1024,
2047 true => 512 * 1024,
2049 _ if deferred_fetch_allowed => 0,
2053 _ if deferred_fetch_minimal_allowed => 8 * 1024,
2057 _ => 0,
2059 } as isize;
2060 let mut quota_for_request_origin = 64 * 1024_isize;
2062 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
2071 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
2073 continue;
2074 }
2075 let request_length = deferred_fetch.request.total_request_length();
2077 quota -= request_length as isize;
2079 if deferred_fetch.request.url().origin() == origin {
2082 quota_for_request_origin -= request_length as isize;
2083 }
2084 }
2085 if quota <= 0 {
2087 return 0;
2088 }
2089 if quota < quota_for_request_origin {
2091 return quota;
2092 }
2093 quota_for_request_origin
2095 }
2096
2097 pub(crate) fn update_document_for_history_step_application(
2099 &self,
2100 old_url: &ServoUrl,
2101 new_url: &ServoUrl,
2102 ) {
2103 if old_url.as_url()[Position::BeforeFragment..] !=
2133 new_url.as_url()[Position::BeforeFragment..]
2134 {
2135 let window = Trusted::new(self.owner_window().deref());
2136 let old_url = old_url.to_string();
2137 let new_url = new_url.to_string();
2138 self.owner_global()
2139 .task_manager()
2140 .dom_manipulation_task_source()
2141 .queue(task!(hashchange_event: move || {
2142 let window = window.root();
2143 HashChangeEvent::new(
2144 &window,
2145 atom!("hashchange"),
2146 false,
2147 false,
2148 old_url,
2149 new_url,
2150 CanGc::note(),
2151 )
2152 .upcast::<Event>()
2153 .fire(window.upcast(), CanGc::note());
2154 }));
2155 }
2156 }
2157
2158 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
2161 debug!("Document got finish_load: {:?}", load);
2163 self.loader.borrow_mut().finish_load(&load);
2164
2165 match load {
2166 LoadType::Stylesheet(_) => {
2167 self.process_pending_parsing_blocking_script(can_gc);
2170
2171 self.process_deferred_scripts(can_gc);
2173 },
2174 LoadType::PageSource(_) => {
2175 if self.has_browsing_context && self.is_fully_active() {
2178 self.window().allow_layout_if_necessary();
2179 }
2180
2181 self.process_deferred_scripts(can_gc);
2186 },
2187 _ => {},
2188 }
2189
2190 let loader = self.loader.borrow();
2197
2198 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
2200 update_with_current_instant(&self.top_level_dom_complete);
2201 }
2202
2203 if loader.is_blocked() || loader.events_inhibited() {
2204 return;
2206 }
2207
2208 ScriptThread::mark_document_with_no_blocked_loads(self);
2209 }
2210
2211 pub(crate) fn check_if_unloading_is_cancelled(
2213 &self,
2214 recursive_flag: bool,
2215 can_gc: CanGc,
2216 ) -> bool {
2217 self.incr_ignore_opens_during_unload_counter();
2220 let beforeunload_event = BeforeUnloadEvent::new(
2222 &self.window,
2223 atom!("beforeunload"),
2224 EventBubbles::Bubbles,
2225 EventCancelable::Cancelable,
2226 can_gc,
2227 );
2228 let event = beforeunload_event.upcast::<Event>();
2229 event.set_trusted(true);
2230 let event_target = self.window.upcast::<EventTarget>();
2231 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2232 self.window
2233 .dispatch_event_with_target_override(event, can_gc);
2234 if has_listeners {
2237 self.salvageable.set(false);
2238 }
2239 let mut can_unload = true;
2240 let default_prevented = event.DefaultPrevented();
2242 let return_value_not_empty = !event
2243 .downcast::<BeforeUnloadEvent>()
2244 .unwrap()
2245 .ReturnValue()
2246 .is_empty();
2247 if default_prevented || return_value_not_empty {
2248 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2249 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2250 self.send_to_embedder(msg);
2251 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2252 }
2253 if !recursive_flag {
2255 let iframes: Vec<_> = self.iframes().iter().collect();
2258 for iframe in &iframes {
2259 let document = iframe.owner_document();
2261 can_unload = document.check_if_unloading_is_cancelled(true, can_gc);
2262 if !document.salvageable() {
2263 self.salvageable.set(false);
2264 }
2265 if !can_unload {
2266 break;
2267 }
2268 }
2269 }
2270 self.decr_ignore_opens_during_unload_counter();
2272 can_unload
2273 }
2274
2275 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2277 self.incr_ignore_opens_during_unload_counter();
2280 if self.page_showing.get() {
2282 self.page_showing.set(false);
2284 let event = PageTransitionEvent::new(
2287 &self.window,
2288 atom!("pagehide"),
2289 false, false, self.salvageable.get(), can_gc,
2293 );
2294 let event = event.upcast::<Event>();
2295 event.set_trusted(true);
2296 self.window
2297 .dispatch_event_with_target_override(event, can_gc);
2298 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2300 }
2301 if !self.fired_unload.get() {
2303 let event = Event::new(
2304 self.window.upcast(),
2305 atom!("unload"),
2306 EventBubbles::Bubbles,
2307 EventCancelable::Cancelable,
2308 can_gc,
2309 );
2310 event.set_trusted(true);
2311 let event_target = self.window.upcast::<EventTarget>();
2312 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2313 self.window
2314 .dispatch_event_with_target_override(&event, can_gc);
2315 self.fired_unload.set(true);
2316 if has_listeners {
2318 self.salvageable.set(false);
2319 }
2320 }
2321 if !recursive_flag {
2325 let iframes: Vec<_> = self.iframes().iter().collect();
2328 for iframe in &iframes {
2329 let document = iframe.owner_document();
2331 document.unload(true, can_gc);
2332 if !document.salvageable() {
2333 self.salvageable.set(false);
2334 }
2335 }
2336 }
2337
2338 self.unloading_cleanup_steps();
2340
2341 self.window.as_global_scope().clean_up_all_file_resources();
2343
2344 self.decr_ignore_opens_during_unload_counter();
2346
2347 }
2350
2351 fn completely_finish_loading(&self) {
2353 self.completely_loaded.set(true);
2358 self.notify_constellation_load();
2367
2368 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2377 &*self.declarative_refresh.borrow()
2378 {
2379 self.window.as_global_scope().schedule_callback(
2380 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2381 window: DomRoot::from_ref(self.window()),
2382 url: url.clone(),
2383 }),
2384 Duration::from_secs(*time),
2385 );
2386 }
2387 }
2388
2389 pub(crate) fn maybe_queue_document_completion(&self) {
2391 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2393 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2394 None => false,
2395 };
2396
2397 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2402 !self.is_fully_active() ||
2403 is_in_delaying_load_events_mode ||
2404 self.loader.borrow().events_inhibited();
2407
2408 if not_ready_for_load {
2409 return;
2411 }
2412
2413 self.loader.borrow_mut().inhibit_events();
2414
2415 debug!("Document loads are complete.");
2420 let document = Trusted::new(self);
2421 self.owner_global()
2422 .task_manager()
2423 .dom_manipulation_task_source()
2424 .queue(task!(fire_load_event: move || {
2425 let document = document.root();
2426 let window = document.window();
2428 if !window.is_alive() {
2429 return;
2430 }
2431
2432 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2434
2435 if document.browsing_context().is_none() {
2437 return;
2438 }
2439
2440 update_with_current_instant(&document.load_event_start);
2442
2443 let load_event = Event::new(
2445 window.upcast(),
2446 atom!("load"),
2447 EventBubbles::DoesNotBubble,
2448 EventCancelable::NotCancelable,
2449 CanGc::note(),
2450 );
2451 load_event.set_trusted(true);
2452 debug!("About to dispatch load for {:?}", document.url());
2453 window.dispatch_event_with_target_override(&load_event, CanGc::note());
2454
2455 update_with_current_instant(&document.load_event_end);
2465
2466 document.page_showing.set(true);
2471
2472 let page_show_event = PageTransitionEvent::new(
2474 window,
2475 atom!("pageshow"),
2476 false, false, false, CanGc::note(),
2480 );
2481 let page_show_event = page_show_event.upcast::<Event>();
2482 page_show_event.set_trusted(true);
2483 page_show_event.fire(window.upcast(), CanGc::note());
2484
2485 document.completely_finish_loading();
2487
2488 if let Some(fragment) = document.url().fragment() {
2492 document.scroll_to_the_fragment(fragment);
2493 }
2494 }));
2495
2496 #[cfg(feature = "webxr")]
2511 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2512 self.window.Navigator().Xr().dispatch_sessionavailable();
2513 }
2514 }
2515
2516 pub(crate) fn completely_loaded(&self) -> bool {
2517 self.completely_loaded.get()
2518 }
2519
2520 pub(crate) fn set_pending_parsing_blocking_script(
2522 &self,
2523 script: &HTMLScriptElement,
2524 load: Option<ScriptResult>,
2525 ) {
2526 assert!(!self.has_pending_parsing_blocking_script());
2527 *self.pending_parsing_blocking_script.borrow_mut() =
2528 Some(PendingScript::new_with_load(script, load));
2529 }
2530
2531 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2533 self.pending_parsing_blocking_script.borrow().is_some()
2534 }
2535
2536 pub(crate) fn pending_parsing_blocking_script_loaded(
2538 &self,
2539 element: &HTMLScriptElement,
2540 result: ScriptResult,
2541 can_gc: CanGc,
2542 ) {
2543 {
2544 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2545 let entry = blocking_script.as_mut().unwrap();
2546 assert!(&*entry.element == element);
2547 entry.loaded(result);
2548 }
2549 self.process_pending_parsing_blocking_script(can_gc);
2550 }
2551
2552 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2553 if self.script_blocking_stylesheets_count.get() > 0 {
2554 return;
2555 }
2556 let pair = self
2557 .pending_parsing_blocking_script
2558 .borrow_mut()
2559 .as_mut()
2560 .and_then(PendingScript::take_result);
2561 if let Some((element, result)) = pair {
2562 *self.pending_parsing_blocking_script.borrow_mut() = None;
2563 self.get_current_parser()
2564 .unwrap()
2565 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2566 }
2567 }
2568
2569 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2571 self.asap_scripts_set
2572 .borrow_mut()
2573 .push(Dom::from_ref(script));
2574 }
2575
2576 pub(crate) fn asap_script_loaded(
2579 &self,
2580 element: &HTMLScriptElement,
2581 result: ScriptResult,
2582 can_gc: CanGc,
2583 ) {
2584 {
2585 let mut scripts = self.asap_scripts_set.borrow_mut();
2586 let idx = scripts
2587 .iter()
2588 .position(|entry| &**entry == element)
2589 .unwrap();
2590 scripts.swap_remove(idx);
2591 }
2592 element.execute(result, can_gc);
2593 }
2594
2595 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2597 self.asap_in_order_scripts_list.push(script);
2598 }
2599
2600 pub(crate) fn asap_in_order_script_loaded(
2603 &self,
2604 element: &HTMLScriptElement,
2605 result: ScriptResult,
2606 can_gc: CanGc,
2607 ) {
2608 self.asap_in_order_scripts_list.loaded(element, result);
2609 while let Some((element, result)) = self
2610 .asap_in_order_scripts_list
2611 .take_next_ready_to_be_executed()
2612 {
2613 element.execute(result, can_gc);
2614 }
2615 }
2616
2617 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2619 self.deferred_scripts.push(script);
2620 }
2621
2622 pub(crate) fn deferred_script_loaded(
2625 &self,
2626 element: &HTMLScriptElement,
2627 result: ScriptResult,
2628 can_gc: CanGc,
2629 ) {
2630 self.deferred_scripts.loaded(element, result);
2631 self.process_deferred_scripts(can_gc);
2632 }
2633
2634 fn process_deferred_scripts(&self, can_gc: CanGc) {
2636 if self.ready_state.get() != DocumentReadyState::Interactive {
2637 return;
2638 }
2639 loop {
2641 if self.script_blocking_stylesheets_count.get() > 0 {
2642 return;
2643 }
2644 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2645 {
2646 element.execute(result, can_gc);
2647 } else {
2648 break;
2649 }
2650 }
2651 if self.deferred_scripts.is_empty() {
2652 self.maybe_dispatch_dom_content_loaded();
2654 }
2655 }
2656
2657 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2659 if self.domcontentloaded_dispatched.get() {
2660 return;
2661 }
2662 self.domcontentloaded_dispatched.set(true);
2663 assert_ne!(
2664 self.ReadyState(),
2665 DocumentReadyState::Complete,
2666 "Complete before DOMContentLoaded?"
2667 );
2668
2669 update_with_current_instant(&self.dom_content_loaded_event_start);
2670
2671 let document = Trusted::new(self);
2673 self.owner_global()
2674 .task_manager()
2675 .dom_manipulation_task_source()
2676 .queue(
2677 task!(fire_dom_content_loaded_event: move || {
2678 let document = document.root();
2679 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2680 update_with_current_instant(&document.dom_content_loaded_event_end);
2681 })
2682 );
2683
2684 self.interactive_time
2686 .borrow()
2687 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2688
2689 }
2692
2693 pub(crate) fn destroy_document_and_its_descendants(&self, can_gc: CanGc) {
2695 if !self.is_fully_active() {
2697 self.salvageable.set(false);
2702 }
2706 for exited_iframe in self.iframes().iter() {
2719 debug!("Destroying nested iframe document");
2720 exited_iframe.destroy_document_and_its_descendants(can_gc);
2721 }
2722 self.destroy(can_gc);
2727 }
2730
2731 pub(crate) fn destroy(&self, can_gc: CanGc) {
2733 let exited_window = self.window();
2734 self.abort(can_gc);
2736 self.salvageable.set(false);
2738 self.unloading_cleanup_steps();
2748
2749 exited_window
2752 .as_global_scope()
2753 .task_manager()
2754 .cancel_all_tasks_and_ignore_future_tasks();
2755
2756 exited_window.discard_browsing_context();
2758
2759 }
2771
2772 fn terminate_fetch_group(&self) -> bool {
2774 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2775
2776 for canceller in &mut load_cancellers {
2780 if !canceller.keep_alive() {
2781 canceller.terminate();
2782 }
2783 }
2784 self.owner_global().process_deferred_fetches();
2786
2787 !load_cancellers.is_empty()
2788 }
2789
2790 pub(crate) fn abort(&self, can_gc: CanGc) {
2792 self.loader.borrow_mut().inhibit_events();
2794
2795 for iframe in self.iframes().iter() {
2797 if let Some(document) = iframe.GetContentDocument() {
2798 document.abort(can_gc);
2799 }
2800 }
2801
2802 self.script_blocking_stylesheets_count.set(0);
2808 *self.pending_parsing_blocking_script.borrow_mut() = None;
2809 *self.asap_scripts_set.borrow_mut() = vec![];
2810 self.asap_in_order_scripts_list.clear();
2811 self.deferred_scripts.clear();
2812 let loads_cancelled = self.terminate_fetch_group();
2813 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2814 if loads_cancelled || event_sources_canceled {
2815 self.salvageable.set(false);
2817 };
2818
2819 self.owner_global()
2824 .task_manager()
2825 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2826
2827 if let Some(parser) = self.get_current_parser() {
2832 self.active_parser_was_aborted.set(true);
2834 parser.abort(can_gc);
2836 self.salvageable.set(false);
2838 }
2839 }
2840
2841 pub(crate) fn notify_constellation_load(&self) {
2842 self.window()
2843 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2844 }
2845
2846 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2847 self.current_parser.set(script);
2848 }
2849
2850 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2851 self.current_parser.get()
2852 }
2853
2854 pub(crate) fn get_current_parser_line(&self) -> u32 {
2855 self.get_current_parser()
2856 .map(|parser| parser.get_current_line())
2857 .unwrap_or(0)
2858 }
2859
2860 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2863 self.iframes.borrow_mut().validate(self);
2864 self.iframes.borrow()
2865 }
2866
2867 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2870 self.iframes.borrow_mut().validate(self);
2871 self.iframes.borrow_mut()
2872 }
2873
2874 pub(crate) fn invalidate_iframes_collection(&self) {
2875 self.iframes.borrow_mut().invalidate();
2876 }
2877
2878 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2879 self.dom_interactive.get()
2880 }
2881
2882 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2883 self.interactive_time
2884 .borrow_mut()
2885 .set_navigation_start(navigation_start);
2886 }
2887
2888 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2889 self.interactive_time.borrow()
2890 }
2891
2892 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2893 self.get_interactive_metrics().get_tti().is_some()
2894 }
2895
2896 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2897 self.dom_content_loaded_event_start.get()
2898 }
2899
2900 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2901 self.dom_content_loaded_event_end.get()
2902 }
2903
2904 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2905 self.dom_complete.get()
2906 }
2907
2908 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2909 self.top_level_dom_complete.get()
2910 }
2911
2912 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2913 self.load_event_start.get()
2914 }
2915
2916 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2917 self.load_event_end.get()
2918 }
2919
2920 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2921 self.unload_event_start.get()
2922 }
2923
2924 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2925 self.unload_event_end.get()
2926 }
2927
2928 pub(crate) fn start_tti(&self) {
2929 if self.get_interactive_metrics().needs_tti() {
2930 self.tti_window.borrow_mut().start_window();
2931 }
2932 }
2933
2934 pub(crate) fn record_tti_if_necessary(&self) {
2938 if self.has_recorded_tti_metric() {
2939 return;
2940 }
2941 if self.tti_window.borrow().needs_check() {
2942 self.get_interactive_metrics()
2943 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2944 self.tti_window.borrow().get_start(),
2945 ));
2946 }
2947 }
2948
2949 fn fire_focus_event(
2951 &self,
2952 focus_event_type: FocusEventType,
2953 event_target: &EventTarget,
2954 related_target: Option<&EventTarget>,
2955 can_gc: CanGc,
2956 ) {
2957 let (event_name, does_bubble) = match focus_event_type {
2958 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2959 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2960 };
2961 let event = FocusEvent::new(
2962 &self.window,
2963 event_name,
2964 does_bubble,
2965 EventCancelable::NotCancelable,
2966 Some(&self.window),
2967 0i32,
2968 related_target,
2969 can_gc,
2970 );
2971 let event = event.upcast::<Event>();
2972 event.set_trusted(true);
2973 event.fire(event_target, can_gc);
2974 }
2975
2976 pub(crate) fn is_cookie_averse(&self) -> bool {
2978 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2979 }
2980
2981 pub(crate) fn lookup_custom_element_definition(
2983 &self,
2984 namespace: &Namespace,
2985 local_name: &LocalName,
2986 is: Option<&LocalName>,
2987 ) -> Option<Rc<CustomElementDefinition>> {
2988 if *namespace != ns!(html) {
2990 return None;
2991 }
2992
2993 if !self.has_browsing_context {
2995 return None;
2996 }
2997
2998 let registry = self.window.CustomElements();
3000
3001 registry.lookup_definition(local_name, is)
3002 }
3003
3004 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
3006 self.window.CustomElements()
3007 }
3008
3009 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
3010 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3011 self.throw_on_dynamic_markup_insertion_counter
3012 .set(counter + 1);
3013 }
3014
3015 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
3016 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
3017 self.throw_on_dynamic_markup_insertion_counter
3018 .set(counter - 1);
3019 }
3020
3021 pub(crate) fn react_to_environment_changes(&self) {
3022 for image in self.responsive_images.borrow().iter() {
3023 image.react_to_environment_changes();
3024 }
3025 }
3026
3027 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
3028 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
3029 }
3030
3031 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
3032 let index = self
3033 .responsive_images
3034 .borrow()
3035 .iter()
3036 .position(|x| **x == *img);
3037 if let Some(i) = index {
3038 self.responsive_images.borrow_mut().remove(i);
3039 }
3040 }
3041
3042 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
3043 let did_have_these_media_controls = self
3044 .media_controls
3045 .borrow_mut()
3046 .insert(id.to_string(), Dom::from_ref(controls))
3047 .is_some();
3048 debug_assert!(
3049 !did_have_these_media_controls,
3050 "Trying to register known media controls"
3051 );
3052 }
3053
3054 pub(crate) fn unregister_media_controls(&self, id: &str) {
3055 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
3056 debug_assert!(
3057 did_have_these_media_controls,
3058 "Trying to unregister unknown media controls"
3059 );
3060 }
3061
3062 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
3063 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
3064 if dirty_canvases
3065 .iter()
3066 .any(|dirty_canvas| dirty_canvas == canvas)
3067 {
3068 return;
3069 }
3070 dirty_canvases.push(canvas.clone());
3071 }
3072
3073 pub(crate) fn needs_rendering_update(&self) -> bool {
3077 if !self.is_fully_active() {
3078 return false;
3079 }
3080 if !self.window().layout_blocked() &&
3081 (!self.restyle_reason().is_empty() ||
3082 self.window().layout().needs_new_display_list())
3083 {
3084 return true;
3085 }
3086 if !self.rendering_update_reasons.get().is_empty() {
3087 return true;
3088 }
3089 if self.event_handler.has_pending_input_events() {
3090 return true;
3091 }
3092 if self.has_pending_scroll_events() {
3093 return true;
3094 }
3095 if self.window().has_unhandled_resize_event() {
3096 return true;
3097 }
3098 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
3099 {
3100 return true;
3101 }
3102
3103 false
3104 }
3105
3106 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
3114 if self.render_blocking_element_count() > 0 {
3115 return Default::default();
3116 }
3117
3118 let mut results = ReflowPhasesRun::empty();
3119 if self.has_pending_animated_image_update.get() {
3120 self.image_animation_manager
3121 .borrow()
3122 .update_active_frames(&self.window, self.current_animation_timeline_value());
3123 self.has_pending_animated_image_update.set(false);
3124 results.insert(ReflowPhasesRun::UpdatedImageData);
3125 }
3126
3127 self.current_rendering_epoch
3128 .set(self.current_rendering_epoch.get().next());
3129 let current_rendering_epoch = self.current_rendering_epoch.get();
3130
3131 let image_keys: Vec<_> = self
3133 .dirty_canvases
3134 .borrow_mut()
3135 .drain(..)
3136 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
3137 .collect();
3138
3139 let pipeline_id = self.window().pipeline_id();
3142 if !image_keys.is_empty() {
3143 results.insert(ReflowPhasesRun::UpdatedImageData);
3144 self.waiting_on_canvas_image_updates.set(true);
3145 self.window().paint_api().delay_new_frame_for_canvas(
3146 self.webview_id(),
3147 self.window().pipeline_id(),
3148 current_rendering_epoch,
3149 image_keys,
3150 );
3151 }
3152
3153 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
3154
3155 self.window().paint_api().update_epoch(
3156 self.webview_id(),
3157 pipeline_id,
3158 current_rendering_epoch,
3159 );
3160
3161 results
3162 }
3163
3164 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
3165 self.waiting_on_canvas_image_updates.set(false);
3166 }
3167
3168 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
3169 self.waiting_on_canvas_image_updates.get()
3170 }
3171
3172 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
3182 if !self.is_fully_active() {
3183 return false;
3184 }
3185
3186 let fonts = self.Fonts(can_gc);
3187 if !fonts.waiting_to_fullfill_promise() {
3188 return false;
3189 }
3190 if self.window().font_context().web_fonts_still_loading() != 0 {
3191 return false;
3192 }
3193 if self.ReadyState() != DocumentReadyState::Complete {
3194 return false;
3195 }
3196 if !self.restyle_reason().is_empty() {
3197 return false;
3198 }
3199 if !self.rendering_update_reasons.get().is_empty() {
3200 return false;
3201 }
3202
3203 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
3204
3205 if result {
3209 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
3210 }
3211
3212 result
3213 }
3214
3215 pub(crate) fn id_map(
3216 &self,
3217 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3218 self.id_map.borrow()
3219 }
3220
3221 pub(crate) fn name_map(
3222 &self,
3223 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
3224 self.name_map.borrow()
3225 }
3226
3227 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3229 self.resize_observers
3230 .borrow_mut()
3231 .push(Dom::from_ref(resize_observer));
3232 }
3233
3234 pub(crate) fn has_resize_observers(&self) -> bool {
3236 !self.resize_observers.borrow().is_empty()
3237 }
3238
3239 pub(crate) fn gather_active_resize_observations_at_depth(
3242 &self,
3243 depth: &ResizeObservationDepth,
3244 ) -> bool {
3245 let mut has_active_resize_observations = false;
3246 for observer in self.resize_observers.borrow_mut().iter_mut() {
3247 observer.gather_active_resize_observations_at_depth(
3248 depth,
3249 &mut has_active_resize_observations,
3250 );
3251 }
3252 has_active_resize_observations
3253 }
3254
3255 pub(crate) fn broadcast_active_resize_observations(
3257 &self,
3258 can_gc: CanGc,
3259 ) -> ResizeObservationDepth {
3260 let mut shallowest = ResizeObservationDepth::max();
3261 let iterator: Vec<DomRoot<ResizeObserver>> = self
3265 .resize_observers
3266 .borrow()
3267 .iter()
3268 .cloned()
3269 .map(|obs| DomRoot::from_ref(&*obs))
3270 .collect();
3271 for observer in iterator {
3272 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
3273 }
3274 shallowest
3275 }
3276
3277 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3279 self.resize_observers
3280 .borrow()
3281 .iter()
3282 .any(|observer| observer.has_skipped_resize_observations())
3283 }
3284
3285 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3287 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3288 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3289 ..Default::default()
3290 };
3291 self.window
3292 .as_global_scope()
3293 .report_an_error(error_info, HandleValue::null(), can_gc);
3294 }
3295
3296 pub(crate) fn status_code(&self) -> Option<u16> {
3297 self.status_code
3298 }
3299
3300 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3302 let encoding = self.encoding.get();
3308
3309 let base_url = self.base_url();
3315
3316 url::Url::options()
3318 .base_url(Some(base_url.as_url()))
3319 .encoding_override(Some(&|input| {
3320 servo_url::encoding::encode_as_url_query_string(input, encoding)
3321 }))
3322 .parse(url)
3323 .map(ServoUrl::from)
3324 }
3325
3326 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3328 if !self.has_browsing_context {
3330 return false;
3331 }
3332
3333 if !self.is_fully_active() {
3335 return false;
3336 }
3337
3338 true
3344 }
3345
3346 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3349 self.intersection_observers
3350 .borrow_mut()
3351 .push(Dom::from_ref(intersection_observer));
3352 }
3353
3354 pub(crate) fn remove_intersection_observer(
3358 &self,
3359 intersection_observer: &IntersectionObserver,
3360 ) {
3361 self.intersection_observers
3362 .borrow_mut()
3363 .retain(|observer| *observer != intersection_observer)
3364 }
3365
3366 pub(crate) fn update_intersection_observer_steps(
3368 &self,
3369 time: CrossProcessInstant,
3370 can_gc: CanGc,
3371 ) {
3372 for intersection_observer in &*self.intersection_observers.borrow() {
3374 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3375 }
3376 }
3377
3378 fn update_single_intersection_observer_steps(
3380 &self,
3381 intersection_observer: &IntersectionObserver,
3382 time: CrossProcessInstant,
3383 can_gc: CanGc,
3384 ) {
3385 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3388
3389 intersection_observer.update_intersection_observations_steps(
3393 self,
3394 time,
3395 root_bounds,
3396 can_gc,
3397 );
3398 }
3399
3400 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3402 self.intersection_observer_task_queued.set(false);
3405
3406 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3411
3412 for intersection_observer in notify_list.iter() {
3415 intersection_observer.invoke_callback_if_necessary(can_gc);
3417 }
3418 }
3419
3420 pub(crate) fn queue_an_intersection_observer_task(&self) {
3422 if self.intersection_observer_task_queued.get() {
3425 return;
3426 }
3427
3428 self.intersection_observer_task_queued.set(true);
3431
3432 let document = Trusted::new(self);
3436 self.owner_global()
3437 .task_manager()
3438 .intersection_observer_task_source()
3439 .queue(task!(notify_intersection_observers: move || {
3440 document.root().notify_intersection_observers(CanGc::note());
3441 }));
3442 }
3443
3444 pub(crate) fn handle_paint_metric(
3445 &self,
3446 metric_type: ProgressiveWebMetricType,
3447 metric_value: CrossProcessInstant,
3448 first_reflow: bool,
3449 can_gc: CanGc,
3450 ) {
3451 let metrics = self.interactive_time.borrow();
3452 match metric_type {
3453 ProgressiveWebMetricType::FirstPaint |
3454 ProgressiveWebMetricType::FirstContentfulPaint => {
3455 let binding = PerformancePaintTiming::new(
3456 self.window.as_global_scope(),
3457 metric_type,
3458 metric_value,
3459 can_gc,
3460 );
3461 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3462 let entry = binding.upcast::<PerformanceEntry>();
3463 self.window.Performance().queue_entry(entry);
3464 },
3465 ProgressiveWebMetricType::LargestContentfulPaint { area, lcp_type } => {
3466 let binding = LargestContentfulPaint::new(
3467 self.window.as_global_scope(),
3468 metric_type,
3469 metric_value,
3470 can_gc,
3471 );
3472 metrics.set_largest_contentful_paint(metric_value, area, lcp_type);
3473 let entry = binding.upcast::<PerformanceEntry>();
3474 self.window.Performance().queue_entry(entry);
3475 },
3476 ProgressiveWebMetricType::TimeToInteractive => {
3477 unreachable!("Unexpected non-paint metric.")
3478 },
3479 }
3480 }
3481
3482 fn write(
3484 &self,
3485 text: Vec<TrustedHTMLOrString>,
3486 line_feed: bool,
3487 containing_class: &str,
3488 field: &str,
3489 can_gc: CanGc,
3490 ) -> ErrorResult {
3491 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3493 let mut is_trusted = true;
3495 for value in text {
3497 match value {
3498 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3500 strings.push(trusted_html.to_string());
3501 },
3502 TrustedHTMLOrString::String(str_) => {
3503 is_trusted = false;
3505 strings.push(str_.into());
3507 },
3508 };
3509 }
3510 let mut string = itertools::join(strings, "");
3511 if !is_trusted {
3515 string = TrustedHTML::get_trusted_script_compliant_string(
3516 &self.global(),
3517 TrustedHTMLOrString::String(string.into()),
3518 &format!("{} {}", containing_class, field),
3519 can_gc,
3520 )?
3521 .str()
3522 .to_owned();
3523 }
3524 if line_feed {
3526 string.push('\n');
3527 }
3528 if !self.is_html_document() {
3530 return Err(Error::InvalidState(None));
3531 }
3532
3533 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3536 return Err(Error::InvalidState(None));
3537 }
3538
3539 if !self.is_active() || self.active_parser_was_aborted.get() {
3541 return Ok(());
3542 }
3543
3544 let parser = match self.get_current_parser() {
3545 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3546 _ => {
3548 if self.is_prompting_or_unloading() ||
3551 self.ignore_destructive_writes_counter.get() > 0
3552 {
3553 return Ok(());
3554 }
3555 self.Open(None, None, can_gc)?;
3557 self.get_current_parser().unwrap()
3558 },
3559 };
3560
3561 parser.write(string.into(), can_gc);
3563
3564 Ok(())
3565 }
3566
3567 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3568 RefMut::map(
3569 self.details_name_groups.borrow_mut(),
3570 |details_name_groups| details_name_groups.get_or_insert_default(),
3571 )
3572 }
3573}
3574
3575#[derive(MallocSizeOf, PartialEq)]
3576pub(crate) enum DocumentSource {
3577 FromParser,
3578 NotFromParser,
3579}
3580
3581pub(crate) trait LayoutDocumentHelpers<'dom> {
3582 fn is_html_document_for_layout(&self) -> bool;
3583 fn quirks_mode(self) -> QuirksMode;
3584 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3585 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3586 fn shadow_roots_styles_changed(self) -> bool;
3587 fn flush_shadow_roots_stylesheets(self);
3588}
3589
3590#[expect(unsafe_code)]
3591impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3592 #[inline]
3593 fn is_html_document_for_layout(&self) -> bool {
3594 self.unsafe_get().is_html_document
3595 }
3596
3597 #[inline]
3598 fn quirks_mode(self) -> QuirksMode {
3599 self.unsafe_get().quirks_mode.get()
3600 }
3601
3602 #[inline]
3603 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3604 self.unsafe_get().style_shared_lock()
3605 }
3606
3607 #[inline]
3608 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3609 unsafe {
3614 self.unsafe_get()
3615 .shadow_roots
3616 .borrow_for_layout()
3617 .iter()
3618 .map(|sr| sr.to_layout())
3619 .collect()
3620 }
3621 }
3622
3623 #[inline]
3624 fn shadow_roots_styles_changed(self) -> bool {
3625 self.unsafe_get().shadow_roots_styles_changed.get()
3626 }
3627
3628 #[inline]
3629 fn flush_shadow_roots_stylesheets(self) {
3630 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3631 }
3632}
3633
3634fn get_registrable_domain_suffix_of_or_is_equal_to(
3638 host_suffix_string: &DOMString,
3639 original_host: Host,
3640) -> Option<Host> {
3641 if host_suffix_string.is_empty() {
3643 return None;
3644 }
3645
3646 let host = match Host::parse(&host_suffix_string.str()) {
3648 Ok(host) => host,
3649 Err(_) => return None,
3650 };
3651
3652 if host != original_host {
3654 let host = match host {
3656 Host::Domain(ref host) => host,
3657 _ => return None,
3658 };
3659 let original_host = match original_host {
3660 Host::Domain(ref original_host) => original_host,
3661 _ => return None,
3662 };
3663
3664 let index = original_host.len().checked_sub(host.len())?;
3666 let (prefix, suffix) = original_host.split_at(index);
3667
3668 if !prefix.ends_with('.') {
3669 return None;
3670 }
3671 if suffix != host {
3672 return None;
3673 }
3674
3675 if is_pub_domain(host) {
3677 return None;
3678 }
3679 }
3680
3681 Some(host)
3683}
3684
3685fn url_has_network_scheme(url: &ServoUrl) -> bool {
3687 matches!(url.scheme(), "ftp" | "http" | "https")
3688}
3689
3690#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3691pub(crate) enum HasBrowsingContext {
3692 No,
3693 Yes,
3694}
3695
3696impl Document {
3697 #[allow(clippy::too_many_arguments)]
3698 pub(crate) fn new_inherited(
3699 window: &Window,
3700 has_browsing_context: HasBrowsingContext,
3701 url: Option<ServoUrl>,
3702 about_base_url: Option<ServoUrl>,
3703 origin: MutableOrigin,
3704 is_html_document: IsHTMLDocument,
3705 content_type: Option<Mime>,
3706 last_modified: Option<String>,
3707 activity: DocumentActivity,
3708 source: DocumentSource,
3709 doc_loader: DocumentLoader,
3710 referrer: Option<String>,
3711 status_code: Option<u16>,
3712 canceller: FetchCanceller,
3713 is_initial_about_blank: bool,
3714 allow_declarative_shadow_roots: bool,
3715 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3716 has_trustworthy_ancestor_origin: bool,
3717 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3718 creation_sandboxing_flag_set: SandboxingFlagSet,
3719 ) -> Document {
3720 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3721
3722 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3723 (DocumentReadyState::Loading, false)
3724 } else {
3725 (DocumentReadyState::Complete, true)
3726 };
3727
3728 let frame_type = match window.is_top_level() {
3729 true => TimerMetadataFrameType::RootWindow,
3730 false => TimerMetadataFrameType::IFrame,
3731 };
3732 let interactive_time = ProgressiveWebMetrics::new(
3733 window.time_profiler_chan().clone(),
3734 url.clone(),
3735 frame_type,
3736 );
3737
3738 let content_type = content_type.unwrap_or_else(|| {
3739 match is_html_document {
3740 IsHTMLDocument::HTMLDocument => "text/html",
3742 IsHTMLDocument::NonHTMLDocument => "application/xml",
3744 }
3745 .parse()
3746 .unwrap()
3747 });
3748
3749 let encoding = content_type
3750 .get_parameter(CHARSET)
3751 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3752 .unwrap_or(UTF_8);
3753
3754 let has_focus = window.parent_info().is_none();
3755
3756 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3757
3758 Document {
3759 node: Node::new_document_node(),
3760 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3761 window: Dom::from_ref(window),
3762 has_browsing_context,
3763 implementation: Default::default(),
3764 content_type,
3765 last_modified,
3766 url: DomRefCell::new(url),
3767 about_base_url: DomRefCell::new(about_base_url),
3768 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3770 event_handler: DocumentEventHandler::new(window),
3771 embedder_controls: DocumentEmbedderControls::new(window),
3772 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3773 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3774 encoding: Cell::new(encoding),
3776 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3777 activity: Cell::new(activity),
3778 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3779 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3780 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3781 images: Default::default(),
3782 embeds: Default::default(),
3783 links: Default::default(),
3784 forms: Default::default(),
3785 scripts: Default::default(),
3786 anchors: Default::default(),
3787 applets: Default::default(),
3788 iframes: RefCell::new(IFrameCollection::new()),
3789 style_shared_lock: {
3790 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3797 LazyLock::new(StyleSharedRwLock::new);
3798
3799 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3800 },
3802 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3803 stylesheet_list: MutNullableDom::new(None),
3804 ready_state: Cell::new(ready_state),
3805 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3806 focus_transaction: DomRefCell::new(None),
3807 focused: Default::default(),
3808 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3809 has_focus: Cell::new(has_focus),
3810 current_script: Default::default(),
3811 pending_parsing_blocking_script: Default::default(),
3812 script_blocking_stylesheets_count: Default::default(),
3813 render_blocking_element_count: Default::default(),
3814 deferred_scripts: Default::default(),
3815 asap_in_order_scripts_list: Default::default(),
3816 asap_scripts_set: Default::default(),
3817 animation_frame_ident: Cell::new(0),
3818 animation_frame_list: DomRefCell::new(VecDeque::new()),
3819 running_animation_callbacks: Cell::new(false),
3820 loader: DomRefCell::new(doc_loader),
3821 current_parser: Default::default(),
3822 base_element: Default::default(),
3823 appropriate_template_contents_owner_document: Default::default(),
3824 pending_restyles: DomRefCell::new(FxHashMap::default()),
3825 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3826 dom_interactive: Cell::new(Default::default()),
3827 dom_content_loaded_event_start: Cell::new(Default::default()),
3828 dom_content_loaded_event_end: Cell::new(Default::default()),
3829 dom_complete: Cell::new(Default::default()),
3830 top_level_dom_complete: Cell::new(Default::default()),
3831 load_event_start: Cell::new(Default::default()),
3832 load_event_end: Cell::new(Default::default()),
3833 unload_event_start: Cell::new(Default::default()),
3834 unload_event_end: Cell::new(Default::default()),
3835 https_state: Cell::new(HttpsState::None),
3836 origin,
3837 referrer,
3838 target_element: MutNullableDom::new(None),
3839 policy_container: DomRefCell::new(PolicyContainer::default()),
3840 preloaded_resources: Default::default(),
3841 ignore_destructive_writes_counter: Default::default(),
3842 ignore_opens_during_unload_counter: Default::default(),
3843 spurious_animation_frames: Cell::new(0),
3844 dom_count: Cell::new(1),
3845 fullscreen_element: MutNullableDom::new(None),
3846 form_id_listener_map: Default::default(),
3847 interactive_time: DomRefCell::new(interactive_time),
3848 tti_window: DomRefCell::new(InteractiveWindow::default()),
3849 canceller,
3850 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3851 page_showing: Cell::new(false),
3852 salvageable: Cell::new(true),
3853 active_parser_was_aborted: Cell::new(false),
3854 fired_unload: Cell::new(false),
3855 responsive_images: Default::default(),
3856 redirect_count: Cell::new(0),
3857 completely_loaded: Cell::new(false),
3858 script_and_layout_blockers: Cell::new(0),
3859 delayed_tasks: Default::default(),
3860 shadow_roots: DomRefCell::new(HashSet::new()),
3861 shadow_roots_styles_changed: Cell::new(false),
3862 media_controls: DomRefCell::new(HashMap::new()),
3863 dirty_canvases: DomRefCell::new(Default::default()),
3864 has_pending_animated_image_update: Cell::new(false),
3865 selection: MutNullableDom::new(None),
3866 animation_timeline: if pref!(layout_animations_test_enabled) {
3867 DomRefCell::new(AnimationTimeline::new_for_testing())
3868 } else {
3869 DomRefCell::new(AnimationTimeline::new())
3870 },
3871 animations: Animations::new(),
3872 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3873 dirty_root: Default::default(),
3874 declarative_refresh: Default::default(),
3875 resize_observers: Default::default(),
3876 fonts: Default::default(),
3877 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3878 status_code,
3879 is_initial_about_blank: Cell::new(is_initial_about_blank),
3880 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3881 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3882 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3883 intersection_observer_task_queued: Cell::new(false),
3884 intersection_observers: Default::default(),
3885 highlighted_dom_node: Default::default(),
3886 adopted_stylesheets: Default::default(),
3887 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3888 pending_scroll_event_targets: Default::default(),
3889 rendering_update_reasons: Default::default(),
3890 waiting_on_canvas_image_updates: Cell::new(false),
3891 current_rendering_epoch: Default::default(),
3892 custom_element_reaction_stack,
3893 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3894 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3895 favicon: RefCell::new(None),
3896 websockets: DOMTracker::new(),
3897 details_name_groups: Default::default(),
3898 protocol_handler_automation_mode: Default::default(),
3899 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3900 }
3901 }
3902
3903 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3905 if let Some(csp_list) = self.get_csp_list() {
3906 for policy in &csp_list.0 {
3907 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3908 policy.disposition == PolicyDisposition::Enforce
3909 {
3910 return InsecureRequestsPolicy::Upgrade;
3911 }
3912 }
3913 }
3914
3915 self.inherited_insecure_requests_policy
3916 .get()
3917 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3918 }
3919
3920 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3922 &self.event_handler
3923 }
3924
3925 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3927 &self.embedder_controls
3928 }
3929
3930 fn has_pending_scroll_events(&self) -> bool {
3933 !self.pending_scroll_event_targets.borrow().is_empty()
3934 }
3935
3936 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3939 self.rendering_update_reasons
3940 .set(self.rendering_update_reasons.get().union(reason));
3941 }
3942
3943 pub(crate) fn clear_rendering_update_reasons(&self) {
3945 self.rendering_update_reasons
3946 .set(RenderingUpdateReason::empty())
3947 }
3948
3949 pub(crate) fn add_script_and_layout_blocker(&self) {
3956 self.script_and_layout_blockers
3957 .set(self.script_and_layout_blockers.get() + 1);
3958 }
3959
3960 #[expect(unsafe_code)]
3961 pub(crate) fn remove_script_and_layout_blocker(&self) {
3965 assert!(self.script_and_layout_blockers.get() > 0);
3966 self.script_and_layout_blockers
3967 .set(self.script_and_layout_blockers.get() - 1);
3968 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3969 {
3970 let task = self.delayed_tasks.borrow_mut().remove(0);
3971 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
3972 task.run_box(&mut cx);
3973 }
3974 }
3975
3976 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3978 self.delayed_tasks.borrow_mut().push(Box::new(task));
3979 }
3980
3981 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3984 assert_eq!(
3985 self.script_and_layout_blockers.get(),
3986 0,
3987 "Attempt to use script or layout while DOM not in a stable state"
3988 );
3989 }
3990
3991 #[allow(clippy::too_many_arguments)]
3992 pub(crate) fn new(
3993 window: &Window,
3994 has_browsing_context: HasBrowsingContext,
3995 url: Option<ServoUrl>,
3996 about_base_url: Option<ServoUrl>,
3997 origin: MutableOrigin,
3998 doctype: IsHTMLDocument,
3999 content_type: Option<Mime>,
4000 last_modified: Option<String>,
4001 activity: DocumentActivity,
4002 source: DocumentSource,
4003 doc_loader: DocumentLoader,
4004 referrer: Option<String>,
4005 status_code: Option<u16>,
4006 canceller: FetchCanceller,
4007 is_initial_about_blank: bool,
4008 allow_declarative_shadow_roots: bool,
4009 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4010 has_trustworthy_ancestor_origin: bool,
4011 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4012 creation_sandboxing_flag_set: SandboxingFlagSet,
4013 can_gc: CanGc,
4014 ) -> DomRoot<Document> {
4015 Self::new_with_proto(
4016 window,
4017 None,
4018 has_browsing_context,
4019 url,
4020 about_base_url,
4021 origin,
4022 doctype,
4023 content_type,
4024 last_modified,
4025 activity,
4026 source,
4027 doc_loader,
4028 referrer,
4029 status_code,
4030 canceller,
4031 is_initial_about_blank,
4032 allow_declarative_shadow_roots,
4033 inherited_insecure_requests_policy,
4034 has_trustworthy_ancestor_origin,
4035 custom_element_reaction_stack,
4036 creation_sandboxing_flag_set,
4037 can_gc,
4038 )
4039 }
4040
4041 #[allow(clippy::too_many_arguments)]
4042 fn new_with_proto(
4043 window: &Window,
4044 proto: Option<HandleObject>,
4045 has_browsing_context: HasBrowsingContext,
4046 url: Option<ServoUrl>,
4047 about_base_url: Option<ServoUrl>,
4048 origin: MutableOrigin,
4049 doctype: IsHTMLDocument,
4050 content_type: Option<Mime>,
4051 last_modified: Option<String>,
4052 activity: DocumentActivity,
4053 source: DocumentSource,
4054 doc_loader: DocumentLoader,
4055 referrer: Option<String>,
4056 status_code: Option<u16>,
4057 canceller: FetchCanceller,
4058 is_initial_about_blank: bool,
4059 allow_declarative_shadow_roots: bool,
4060 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
4061 has_trustworthy_ancestor_origin: bool,
4062 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
4063 creation_sandboxing_flag_set: SandboxingFlagSet,
4064 can_gc: CanGc,
4065 ) -> DomRoot<Document> {
4066 let document = reflect_dom_object_with_proto(
4067 Box::new(Document::new_inherited(
4068 window,
4069 has_browsing_context,
4070 url,
4071 about_base_url,
4072 origin,
4073 doctype,
4074 content_type,
4075 last_modified,
4076 activity,
4077 source,
4078 doc_loader,
4079 referrer,
4080 status_code,
4081 canceller,
4082 is_initial_about_blank,
4083 allow_declarative_shadow_roots,
4084 inherited_insecure_requests_policy,
4085 has_trustworthy_ancestor_origin,
4086 custom_element_reaction_stack,
4087 creation_sandboxing_flag_set,
4088 )),
4089 window,
4090 proto,
4091 can_gc,
4092 );
4093 {
4094 let node = document.upcast::<Node>();
4095 node.set_owner_doc(&document);
4096 }
4097 document
4098 }
4099
4100 pub(crate) fn get_redirect_count(&self) -> u16 {
4101 self.redirect_count.get()
4102 }
4103
4104 pub(crate) fn set_redirect_count(&self, count: u16) {
4105 self.redirect_count.set(count)
4106 }
4107
4108 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
4109 if name.is_empty() {
4110 return 0;
4111 }
4112 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
4113 }
4114
4115 pub(crate) fn nth_element_by_name(
4116 &self,
4117 index: u32,
4118 name: &DOMString,
4119 ) -> Option<DomRoot<Node>> {
4120 if name.is_empty() {
4121 return None;
4122 }
4123 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
4124 }
4125
4126 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
4129 let element = match node.downcast::<Element>() {
4130 Some(element) => element,
4131 None => return false,
4132 };
4133 if element.namespace() != &ns!(html) {
4134 return false;
4135 }
4136 element.get_name().is_some_and(|n| &*n == name)
4137 }
4138
4139 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
4140 let doc = self.GetDocumentElement();
4141 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4142 maybe_node
4143 .iter()
4144 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4145 .filter(|node| callback(node))
4146 .count() as u32
4147 }
4148
4149 fn nth_in_node_list<F: Fn(&Node) -> bool>(
4150 &self,
4151 index: u32,
4152 callback: F,
4153 ) -> Option<DomRoot<Node>> {
4154 let doc = self.GetDocumentElement();
4155 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
4156 maybe_node
4157 .iter()
4158 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
4159 .filter(|node| callback(node))
4160 .nth(index as usize)
4161 .map(|n| DomRoot::from_ref(&*n))
4162 }
4163
4164 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
4165 self.GetDocumentElement().and_then(DomRoot::downcast)
4166 }
4167
4168 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
4170 &self.style_shared_lock
4171 }
4172
4173 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
4175 let mut stylesheets = self.stylesheets.borrow_mut();
4182 let have_changed = stylesheets.has_changed();
4183 stylesheets.flush_without_invalidation();
4184 have_changed
4185 }
4186
4187 pub(crate) fn salvageable(&self) -> bool {
4188 self.salvageable.get()
4189 }
4190
4191 pub(crate) fn appropriate_template_contents_owner_document(
4193 &self,
4194 can_gc: CanGc,
4195 ) -> DomRoot<Document> {
4196 self.appropriate_template_contents_owner_document
4197 .or_init(|| {
4198 let doctype = if self.is_html_document {
4199 IsHTMLDocument::HTMLDocument
4200 } else {
4201 IsHTMLDocument::NonHTMLDocument
4202 };
4203 let new_doc = Document::new(
4204 self.window(),
4205 HasBrowsingContext::No,
4206 None,
4207 None,
4208 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4210 doctype,
4211 None,
4212 None,
4213 DocumentActivity::Inactive,
4214 DocumentSource::NotFromParser,
4215 DocumentLoader::new(&self.loader()),
4216 None,
4217 None,
4218 Default::default(),
4219 false,
4220 self.allow_declarative_shadow_roots(),
4221 Some(self.insecure_requests_policy()),
4222 self.has_trustworthy_ancestor_or_current_origin(),
4223 self.custom_element_reaction_stack.clone(),
4224 self.creation_sandboxing_flag_set(),
4225 can_gc,
4226 );
4227 new_doc
4228 .appropriate_template_contents_owner_document
4229 .set(Some(&new_doc));
4230 new_doc
4231 })
4232 }
4233
4234 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4235 self.id_map
4236 .borrow()
4237 .get(id)
4238 .map(|elements| DomRoot::from_ref(&*elements[0]))
4239 }
4240
4241 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4242 let map = self.pending_restyles.borrow_mut();
4243 RefMut::map(map, |m| {
4244 &mut m
4245 .entry(Dom::from_ref(el))
4246 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4247 .0
4248 })
4249 }
4250
4251 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
4252 let mut entry = self.ensure_pending_restyle(el);
4258 if entry.snapshot.is_none() {
4259 entry.snapshot = Some(Snapshot::new());
4260 }
4261 if attr.local_name() == &local_name!("style") {
4262 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4263 }
4264
4265 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4266 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4267 }
4268
4269 let snapshot = entry.snapshot.as_mut().unwrap();
4270 if attr.local_name() == &local_name!("id") {
4271 if snapshot.id_changed {
4272 return;
4273 }
4274 snapshot.id_changed = true;
4275 } else if attr.local_name() == &local_name!("class") {
4276 if snapshot.class_changed {
4277 return;
4278 }
4279 snapshot.class_changed = true;
4280 } else {
4281 snapshot.other_attributes_changed = true;
4282 }
4283 let local_name = style::LocalName::cast(attr.local_name());
4284 if !snapshot.changed_attrs.contains(local_name) {
4285 snapshot.changed_attrs.push(local_name.clone());
4286 }
4287 if snapshot.attrs.is_none() {
4288 let attrs = el
4289 .attrs()
4290 .iter()
4291 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4292 .collect();
4293 snapshot.attrs = Some(attrs);
4294 }
4295 }
4296
4297 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4298 self.policy_container
4299 .borrow_mut()
4300 .set_referrer_policy(policy);
4301 }
4302
4303 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4304 self.policy_container.borrow().get_referrer_policy()
4305 }
4306
4307 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4308 if let Some(ref element) = self.target_element.get() {
4309 element.set_target_state(false);
4310 }
4311
4312 self.target_element.set(node);
4313
4314 if let Some(ref element) = self.target_element.get() {
4315 element.set_target_state(true);
4316 }
4317 }
4318
4319 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4320 self.ignore_destructive_writes_counter
4321 .set(self.ignore_destructive_writes_counter.get() + 1);
4322 }
4323
4324 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4325 self.ignore_destructive_writes_counter
4326 .set(self.ignore_destructive_writes_counter.get() - 1);
4327 }
4328
4329 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4330 self.ignore_opens_during_unload_counter.get() > 0
4331 }
4332
4333 fn incr_ignore_opens_during_unload_counter(&self) {
4334 self.ignore_opens_during_unload_counter
4335 .set(self.ignore_opens_during_unload_counter.get() + 1);
4336 }
4337
4338 fn decr_ignore_opens_during_unload_counter(&self) {
4339 self.ignore_opens_during_unload_counter
4340 .set(self.ignore_opens_during_unload_counter.get() - 1);
4341 }
4342
4343 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
4345 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4352 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4353
4354 if !self.is_fully_active() {
4357 promise.reject_error(
4358 Error::Type("Document is not fully active".to_owned()),
4359 can_gc,
4360 );
4361 return promise;
4362 }
4363
4364 let mut error = false;
4367
4368 {
4371 match *pending.namespace() {
4373 ns!(mathml) => {
4374 if pending.local_name().as_ref() != "math" {
4375 error = true;
4376 }
4377 },
4378 ns!(svg) => {
4379 if pending.local_name().as_ref() != "svg" {
4380 error = true;
4381 }
4382 },
4383 ns!(html) => (),
4384 _ => error = true,
4385 }
4386
4387 if pending.is::<HTMLDialogElement>() {
4389 error = true;
4390 }
4391
4392 if !pending.fullscreen_element_ready_check() {
4394 error = true;
4395 }
4396
4397 }
4405
4406 if pref!(dom_fullscreen_test) {
4407 info!("Tests don't really enter fullscreen.");
4410 } else {
4411 warn!("Fullscreen not supported yet");
4414 }
4415
4416 if !error {
4426 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4427 self.send_to_embedder(event);
4428 }
4429
4430 let pipeline_id = self.window().pipeline_id();
4433
4434 let trusted_pending = Trusted::new(pending);
4435 let trusted_pending_doc = Trusted::new(self);
4436 let trusted_promise = TrustedPromise::new(promise.clone());
4437 let handler = ElementPerformFullscreenEnter::new(
4438 trusted_pending,
4439 trusted_pending_doc,
4440 trusted_promise,
4441 error,
4442 );
4443 let script_msg = CommonScriptMsg::Task(
4444 ScriptThreadEventCategory::EnterFullscreen,
4445 handler,
4446 Some(pipeline_id),
4447 TaskSourceName::DOMManipulation,
4448 );
4449 let msg = MainThreadScriptMsg::Common(script_msg);
4450 self.window().main_thread_script_chan().send(msg).unwrap();
4451
4452 promise
4453 }
4454
4455 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4457 let global = self.global();
4458
4459 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4462 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4463
4464 if !self.is_fully_active() || self.fullscreen_element.get().is_none() {
4467 promise.reject_error(
4468 Error::Type(
4469 "No fullscreen element to exit or document is not fully active".to_owned(),
4470 ),
4471 can_gc,
4472 );
4473 return promise;
4474 }
4475
4476 let element = self.fullscreen_element.get().unwrap();
4479 let window = self.window();
4480
4481 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4485 self.send_to_embedder(event);
4486
4487 let trusted_element = Trusted::new(&*element);
4490 let trusted_promise = TrustedPromise::new(promise.clone());
4491 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4492 let pipeline_id = Some(global.pipeline_id());
4493 let script_msg = CommonScriptMsg::Task(
4494 ScriptThreadEventCategory::ExitFullscreen,
4495 handler,
4496 pipeline_id,
4497 TaskSourceName::DOMManipulation,
4498 );
4499 let msg = MainThreadScriptMsg::Common(script_msg);
4500 window.main_thread_script_chan().send(msg).unwrap();
4501
4502 promise
4503 }
4504
4505 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4506 self.fullscreen_element.set(element);
4507 }
4508
4509 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4510 match self.browsing_context() {
4512 None => false,
4514 Some(_) => {
4515 let window = self.window();
4517 if window.is_top_level() {
4518 true
4519 } else {
4520 window
4522 .GetFrameElement()
4523 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4524 }
4525 },
4526 }
4527 }
4528
4529 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4530 let map = self.form_id_listener_map.borrow();
4531 if let Some(listeners) = map.get(id) {
4532 for listener in listeners {
4533 listener
4534 .as_maybe_form_control()
4535 .expect("Element must be a form control")
4536 .reset_form_owner(can_gc);
4537 }
4538 }
4539 }
4540
4541 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4542 self.shadow_roots
4543 .borrow_mut()
4544 .insert(Dom::from_ref(shadow_root));
4545 self.invalidate_shadow_roots_stylesheets();
4546 }
4547
4548 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4549 let mut shadow_roots = self.shadow_roots.borrow_mut();
4550 shadow_roots.remove(&Dom::from_ref(shadow_root));
4551 }
4552
4553 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4554 self.shadow_roots_styles_changed.set(true);
4555 }
4556
4557 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4558 self.shadow_roots_styles_changed.get()
4559 }
4560
4561 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4562 if !self.shadow_roots_styles_changed.get() {
4563 return;
4564 }
4565 self.shadow_roots_styles_changed.set(false);
4566 }
4567
4568 pub(crate) fn stylesheet_count(&self) -> usize {
4569 self.stylesheets.borrow().len()
4570 }
4571
4572 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4573 let stylesheets = self.stylesheets.borrow();
4574
4575 stylesheets
4576 .get(Origin::Author, index)
4577 .and_then(|s| s.owner.get_cssom_object())
4578 }
4579
4580 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4587 let stylesheets = &mut *self.stylesheets.borrow_mut();
4588
4589 let insertion_point = stylesheets
4591 .iter()
4592 .map(|(sheet, _origin)| sheet)
4593 .find(|sheet_in_doc| {
4594 match &sheet_in_doc.owner {
4595 StylesheetSource::Element(other_node) => {
4596 owner_node.upcast::<Node>().is_before(other_node.upcast())
4597 },
4598 StylesheetSource::Constructed(_) => true,
4601 }
4602 })
4603 .cloned();
4604
4605 if self.has_browsing_context() {
4606 let document_context = self.window.web_font_context();
4607
4608 self.window.layout_mut().add_stylesheet(
4609 sheet.clone(),
4610 insertion_point.as_ref().map(|s| s.sheet.clone()),
4611 &document_context,
4612 );
4613 }
4614
4615 DocumentOrShadowRoot::add_stylesheet(
4616 StylesheetSource::Element(Dom::from_ref(owner_node)),
4617 StylesheetSetRef::Document(stylesheets),
4618 sheet,
4619 insertion_point,
4620 self.style_shared_lock(),
4621 );
4622 }
4623
4624 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4629 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4630 debug_assert!(cssom_stylesheet.is_constructed());
4631
4632 let stylesheets = &mut *self.stylesheets.borrow_mut();
4633 let sheet = cssom_stylesheet.style_stylesheet().clone();
4634
4635 let insertion_point = stylesheets
4636 .iter()
4637 .last()
4638 .map(|(sheet, _origin)| sheet)
4639 .cloned();
4640
4641 if self.has_browsing_context() {
4642 self.window.layout_mut().add_stylesheet(
4643 sheet.clone(),
4644 insertion_point.as_ref().map(|s| s.sheet.clone()),
4645 &self.window.web_font_context(),
4646 );
4647 }
4648
4649 DocumentOrShadowRoot::add_stylesheet(
4650 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4651 StylesheetSetRef::Document(stylesheets),
4652 sheet,
4653 insertion_point,
4654 self.style_shared_lock(),
4655 );
4656 }
4657
4658 pub(crate) fn load_web_fonts_from_stylesheet(
4660 &self,
4661 stylesheet: &Arc<Stylesheet>,
4662 document_context: &WebFontDocumentContext,
4663 ) {
4664 self.window
4665 .layout()
4666 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4667 }
4668
4669 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4672 if self.has_browsing_context() {
4673 self.window
4674 .layout_mut()
4675 .remove_stylesheet(stylesheet.clone());
4676 }
4677
4678 DocumentOrShadowRoot::remove_stylesheet(
4679 owner,
4680 stylesheet,
4681 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4682 )
4683 }
4684
4685 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4686 Ref::map(self.id_map.borrow(), |map| {
4687 map.get(id).map(|vec| &**vec).unwrap_or_default()
4688 })
4689 }
4690
4691 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4692 Ref::map(self.name_map.borrow(), |map| {
4693 map.get(name).map(|vec| &**vec).unwrap_or_default()
4694 })
4695 }
4696
4697 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4698 self.pending_restyles
4699 .borrow_mut()
4700 .drain()
4701 .filter_map(|(elem, restyle)| {
4702 let node = elem.upcast::<Node>();
4703 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4704 return None;
4705 }
4706 node.note_dirty_descendants();
4707 Some((node.to_trusted_node_address(), restyle.0))
4708 })
4709 .collect()
4710 }
4711
4712 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4713 self.animation_timeline.borrow_mut().advance_specific(delta);
4714 let current_timeline_value = self.current_animation_timeline_value();
4715 self.animations
4716 .update_for_new_timeline_value(&self.window, current_timeline_value);
4717 }
4718
4719 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4720 let current_timeline_value = self.current_animation_timeline_value();
4721 self.animations
4722 .mark_animating_nodes_as_dirty(current_timeline_value);
4723 }
4724
4725 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4726 self.animation_timeline.borrow().current_value()
4727 }
4728
4729 pub(crate) fn animations(&self) -> &Animations {
4730 &self.animations
4731 }
4732
4733 pub(crate) fn update_animations_post_reflow(&self) {
4734 self.animations
4735 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4736 self.image_animation_manager
4737 .borrow()
4738 .maybe_schedule_update_after_layout(
4739 &self.window,
4740 self.current_animation_timeline_value(),
4741 );
4742 }
4743
4744 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4745 self.animations.cancel_animations_for_node(node);
4746 self.image_animation_manager
4747 .borrow()
4748 .cancel_animations_for_node(node);
4749 }
4750
4751 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4753 if !self.layout_animations_test_enabled {
4755 self.animation_timeline.borrow_mut().update();
4756 }
4757
4758 let current_timeline_value = self.current_animation_timeline_value();
4765 self.animations
4766 .update_for_new_timeline_value(&self.window, current_timeline_value);
4767 self.maybe_mark_animating_nodes_as_dirty();
4768
4769 self.window().perform_a_microtask_checkpoint(can_gc);
4771
4772 let _realm = enter_realm(self);
4774 self.animations().send_pending_events(self.window(), can_gc);
4775 }
4776
4777 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4778 self.image_animation_manager.borrow()
4779 }
4780
4781 pub(crate) fn set_has_pending_animated_image_update(&self) {
4782 self.has_pending_animated_image_update.set(true);
4783 }
4784
4785 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4787 if self.will_declaratively_refresh() {
4789 return;
4790 }
4791
4792 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4794 Regex::new(
4798 r#"(?xs)
4799 ^
4800 \s* # 3
4801 ((?<time>[0-9]+)|\.) # 5-6
4802 [0-9.]* # 8
4803 (
4804 (
4805 (\s*;|\s*,|\s) # 10.3
4806 \s* # 10.4
4807 )
4808 (
4809 (
4810 (U|u)(R|r)(L|l) # 11.2-11.4
4811 \s*=\s* # 11.5-11.7
4812 )?
4813 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4814 |
4815 (?<url4>(?s-u:.)*)
4816 )
4817 )?
4818 $
4819 "#,
4820 )
4821 .unwrap()
4822 });
4823
4824 let mut url_record = self.url();
4826 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4827 captures
4828 } else {
4829 return;
4830 };
4831 let time = if let Some(time_string) = captures.name("time") {
4832 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4833 } else {
4834 0
4835 };
4836 let captured_url = captures.name("url1").or(captures
4837 .name("url2")
4838 .or(captures.name("url3").or(captures.name("url4"))));
4839
4840 if let Some(url_match) = captured_url {
4842 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4843 Some(&url_record),
4844 &String::from_utf8_lossy(url_match.as_bytes()),
4845 ) {
4846 info!("Refresh to {}", url.debug_compact());
4847 url
4848 } else {
4849 return;
4851 }
4852 }
4853 if self.completely_loaded() {
4855 self.window.as_global_scope().schedule_callback(
4857 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4858 window: DomRoot::from_ref(self.window()),
4859 url: url_record,
4860 }),
4861 Duration::from_secs(time),
4862 );
4863 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4864 } else {
4865 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4866 url: url_record,
4867 time,
4868 });
4869 }
4870 }
4871
4872 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4873 self.declarative_refresh.borrow().is_some()
4874 }
4875 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4876 *self.declarative_refresh.borrow_mut() = Some(refresh);
4877 }
4878
4879 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4881 if self.visibility_state.get() == visibility_state {
4883 return;
4884 }
4885 self.visibility_state.set(visibility_state);
4887 let entry = VisibilityStateEntry::new(
4890 &self.global(),
4891 visibility_state,
4892 CrossProcessInstant::now(),
4893 can_gc,
4894 );
4895 self.window
4896 .Performance()
4897 .queue_entry(entry.upcast::<PerformanceEntry>());
4898
4899 #[cfg(feature = "gamepad")]
4910 if visibility_state == DocumentVisibilityState::Hidden {
4911 self.window
4912 .Navigator()
4913 .GetGamepads()
4914 .iter_mut()
4915 .for_each(|gamepad| {
4916 if let Some(g) = gamepad {
4917 g.vibration_actuator().handle_visibility_change();
4918 }
4919 });
4920 }
4921
4922 self.upcast::<EventTarget>()
4924 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4925 }
4926
4927 pub(crate) fn is_initial_about_blank(&self) -> bool {
4929 self.is_initial_about_blank.get()
4930 }
4931
4932 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4934 self.allow_declarative_shadow_roots.get()
4935 }
4936
4937 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4938 self.has_trustworthy_ancestor_origin.get()
4939 }
4940
4941 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4942 self.has_trustworthy_ancestor_origin.get() ||
4943 self.origin().immutable().is_potentially_trustworthy()
4944 }
4945
4946 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4947 self.highlighted_dom_node.set(node);
4948 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4949 }
4950
4951 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4952 self.highlighted_dom_node.get()
4953 }
4954
4955 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4956 self.custom_element_reaction_stack.clone()
4957 }
4958
4959 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4960 self.active_sandboxing_flag_set.get().contains(flag)
4961 }
4962
4963 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4964 self.active_sandboxing_flag_set.set(flags)
4965 }
4966
4967 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4968 self.creation_sandboxing_flag_set.get()
4969 }
4970
4971 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4972 &self,
4973 ) -> SandboxingFlagSet {
4974 self.window()
4975 .window_proxy()
4976 .frame_element()
4977 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4978 .map(HTMLIFrameElement::sandboxing_flag_set)
4979 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4980 }
4981
4982 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4983 self.window()
4984 .scrolling_box_query(None, flags)
4985 .expect("We should always have a ScrollingBox for the Viewport")
4986 }
4987
4988 pub(crate) fn notify_embedder_favicon(&self) {
4989 if let Some(ref image) = *self.favicon.borrow() {
4990 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4991 }
4992 }
4993
4994 pub(crate) fn set_favicon(&self, favicon: Image) {
4995 *self.favicon.borrow_mut() = Some(favicon);
4996 self.notify_embedder_favicon();
4997 }
4998}
4999
5000impl DocumentMethods<crate::DomTypeHolder> for Document {
5001 fn Constructor(
5003 window: &Window,
5004 proto: Option<HandleObject>,
5005 can_gc: CanGc,
5006 ) -> Fallible<DomRoot<Document>> {
5007 let doc = window.Document();
5009 let docloader = DocumentLoader::new(&doc.loader());
5010 Ok(Document::new_with_proto(
5011 window,
5012 proto,
5013 HasBrowsingContext::No,
5014 None,
5015 None,
5016 doc.origin().clone(),
5017 IsHTMLDocument::NonHTMLDocument,
5018 None,
5019 None,
5020 DocumentActivity::Inactive,
5021 DocumentSource::NotFromParser,
5022 docloader,
5023 None,
5024 None,
5025 Default::default(),
5026 false,
5027 doc.allow_declarative_shadow_roots(),
5028 Some(doc.insecure_requests_policy()),
5029 doc.has_trustworthy_ancestor_or_current_origin(),
5030 doc.custom_element_reaction_stack(),
5031 doc.active_sandboxing_flag_set.get(),
5032 can_gc,
5033 ))
5034 }
5035
5036 fn ParseHTMLUnsafe(
5038 window: &Window,
5039 s: TrustedHTMLOrString,
5040 can_gc: CanGc,
5041 ) -> Fallible<DomRoot<Self>> {
5042 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
5046 window.as_global_scope(),
5047 s,
5048 "Document parseHTMLUnsafe",
5049 can_gc,
5050 )?;
5051
5052 let url = window.get_url();
5053 let doc = window.Document();
5054 let loader = DocumentLoader::new(&doc.loader());
5055
5056 let content_type = "text/html"
5057 .parse()
5058 .expect("Supported type is not a MIME type");
5059 let document = Document::new(
5062 window,
5063 HasBrowsingContext::No,
5064 Some(ServoUrl::parse("about:blank").unwrap()),
5065 None,
5066 doc.origin().clone(),
5067 IsHTMLDocument::HTMLDocument,
5068 Some(content_type),
5069 None,
5070 DocumentActivity::Inactive,
5071 DocumentSource::FromParser,
5072 loader,
5073 None,
5074 None,
5075 Default::default(),
5076 false,
5077 true,
5078 Some(doc.insecure_requests_policy()),
5079 doc.has_trustworthy_ancestor_or_current_origin(),
5080 doc.custom_element_reaction_stack(),
5081 doc.creation_sandboxing_flag_set(),
5082 can_gc,
5083 );
5084 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, can_gc);
5086 document.set_ready_state(DocumentReadyState::Complete, can_gc);
5088 Ok(document)
5089 }
5090
5091 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
5093 false
5094 }
5095
5096 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
5098 self.stylesheet_list.or_init(|| {
5099 StyleSheetList::new(
5100 &self.window,
5101 StyleSheetListOwner::Document(Dom::from_ref(self)),
5102 can_gc,
5103 )
5104 })
5105 }
5106
5107 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
5109 self.implementation
5110 .or_init(|| DOMImplementation::new(self, can_gc))
5111 }
5112
5113 fn URL(&self) -> USVString {
5115 USVString(String::from(self.url().as_str()))
5116 }
5117
5118 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
5120 self.document_or_shadow_root.get_active_element(
5121 self.get_focused_element(),
5122 self.GetBody(),
5123 self.GetDocumentElement(),
5124 )
5125 }
5126
5127 fn HasFocus(&self) -> bool {
5129 if self.window().parent_info().is_none() {
5151 self.is_fully_active()
5153 } else {
5154 self.is_fully_active() && self.has_focus.get()
5156 }
5157 }
5158
5159 fn Domain(&self) -> DOMString {
5161 match self.origin.effective_domain() {
5163 None => DOMString::new(),
5165 Some(Host::Domain(domain)) => DOMString::from(domain),
5167 Some(host) => DOMString::from(host.to_string()),
5168 }
5169 }
5170
5171 fn SetDomain(&self, value: DOMString) -> ErrorResult {
5173 if !self.has_browsing_context {
5175 return Err(Error::Security(None));
5176 }
5177
5178 if self.has_active_sandboxing_flag(
5181 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
5182 ) {
5183 return Err(Error::Security(None));
5184 }
5185
5186 let effective_domain = match self.origin.effective_domain() {
5188 Some(effective_domain) => effective_domain,
5189 None => return Err(Error::Security(None)),
5191 };
5192
5193 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
5195 None => return Err(Error::Security(None)),
5196 Some(host) => host,
5197 };
5198
5199 self.origin.set_domain(host);
5204
5205 Ok(())
5206 }
5207
5208 fn Referrer(&self) -> DOMString {
5210 match self.referrer {
5211 Some(ref referrer) => DOMString::from(referrer.to_string()),
5212 None => DOMString::new(),
5213 }
5214 }
5215
5216 fn DocumentURI(&self) -> USVString {
5218 self.URL()
5219 }
5220
5221 fn CompatMode(&self) -> DOMString {
5223 DOMString::from(match self.quirks_mode.get() {
5224 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
5225 QuirksMode::Quirks => "BackCompat",
5226 })
5227 }
5228
5229 fn CharacterSet(&self) -> DOMString {
5231 DOMString::from(self.encoding.get().name())
5232 }
5233
5234 fn Charset(&self) -> DOMString {
5236 self.CharacterSet()
5237 }
5238
5239 fn InputEncoding(&self) -> DOMString {
5241 self.CharacterSet()
5242 }
5243
5244 fn ContentType(&self) -> DOMString {
5246 DOMString::from(self.content_type.to_string())
5247 }
5248
5249 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
5251 self.upcast::<Node>().children().find_map(DomRoot::downcast)
5252 }
5253
5254 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
5256 self.upcast::<Node>().child_elements().next()
5257 }
5258
5259 fn GetElementsByTagName(
5261 &self,
5262 qualified_name: DOMString,
5263 can_gc: CanGc,
5264 ) -> DomRoot<HTMLCollection> {
5265 let qualified_name = LocalName::from(qualified_name);
5266 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
5267 return DomRoot::from_ref(entry);
5268 }
5269 let result = HTMLCollection::by_qualified_name(
5270 &self.window,
5271 self.upcast(),
5272 qualified_name.clone(),
5273 can_gc,
5274 );
5275 self.tag_map
5276 .borrow_mut()
5277 .insert(qualified_name, Dom::from_ref(&*result));
5278 result
5279 }
5280
5281 fn GetElementsByTagNameNS(
5283 &self,
5284 maybe_ns: Option<DOMString>,
5285 tag_name: DOMString,
5286 can_gc: CanGc,
5287 ) -> DomRoot<HTMLCollection> {
5288 let ns = namespace_from_domstring(maybe_ns);
5289 let local = LocalName::from(tag_name);
5290 let qname = QualName::new(None, ns, local);
5291 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
5292 return DomRoot::from_ref(collection);
5293 }
5294 let result =
5295 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
5296 self.tagns_map
5297 .borrow_mut()
5298 .insert(qname, Dom::from_ref(&*result));
5299 result
5300 }
5301
5302 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5304 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
5305 .map(Atom::from)
5306 .collect();
5307 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5308 return DomRoot::from_ref(collection);
5309 }
5310 let result = HTMLCollection::by_atomic_class_name(
5311 &self.window,
5312 self.upcast(),
5313 class_atoms.clone(),
5314 can_gc,
5315 );
5316 self.classes_map
5317 .borrow_mut()
5318 .insert(class_atoms, Dom::from_ref(&*result));
5319 result
5320 }
5321
5322 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5324 self.get_element_by_id(&Atom::from(id))
5325 }
5326
5327 fn CreateElement(
5329 &self,
5330 mut local_name: DOMString,
5331 options: StringOrElementCreationOptions,
5332 can_gc: CanGc,
5333 ) -> Fallible<DomRoot<Element>> {
5334 if !is_valid_element_local_name(&local_name.str()) {
5337 debug!("Not a valid element name");
5338 return Err(Error::InvalidCharacter(None));
5339 }
5340
5341 if self.is_html_document {
5342 local_name.make_ascii_lowercase();
5343 }
5344
5345 let ns = if self.is_html_document || self.is_xhtml_document() {
5346 ns!(html)
5347 } else {
5348 ns!()
5349 };
5350
5351 let name = QualName::new(None, ns, LocalName::from(local_name));
5352 let is = match options {
5353 StringOrElementCreationOptions::String(_) => None,
5354 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5355 options.is.as_ref().map(LocalName::from)
5356 },
5357 };
5358 Ok(Element::create(
5359 name,
5360 is,
5361 self,
5362 ElementCreator::ScriptCreated,
5363 CustomElementCreationMode::Synchronous,
5364 None,
5365 can_gc,
5366 ))
5367 }
5368
5369 fn CreateElementNS(
5371 &self,
5372 namespace: Option<DOMString>,
5373 qualified_name: DOMString,
5374 options: StringOrElementCreationOptions,
5375 can_gc: CanGc,
5376 ) -> Fallible<DomRoot<Element>> {
5377 let context = domname::Context::Element;
5380 let (namespace, prefix, local_name) =
5381 domname::validate_and_extract(namespace, &qualified_name, context)?;
5382
5383 let name = QualName::new(prefix, namespace, local_name);
5386 let is = match options {
5387 StringOrElementCreationOptions::String(_) => None,
5388 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5389 options.is.as_ref().map(LocalName::from)
5390 },
5391 };
5392
5393 Ok(Element::create(
5395 name,
5396 is,
5397 self,
5398 ElementCreator::ScriptCreated,
5399 CustomElementCreationMode::Synchronous,
5400 None,
5401 can_gc,
5402 ))
5403 }
5404
5405 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5407 if !is_valid_attribute_local_name(&local_name.str()) {
5410 debug!("Not a valid attribute name");
5411 return Err(Error::InvalidCharacter(None));
5412 }
5413 if self.is_html_document {
5414 local_name.make_ascii_lowercase();
5415 }
5416 let name = LocalName::from(local_name);
5417 let value = AttrValue::String("".to_owned());
5418
5419 Ok(Attr::new(
5420 self,
5421 name.clone(),
5422 value,
5423 name,
5424 ns!(),
5425 None,
5426 None,
5427 can_gc,
5428 ))
5429 }
5430
5431 fn CreateAttributeNS(
5433 &self,
5434 namespace: Option<DOMString>,
5435 qualified_name: DOMString,
5436 can_gc: CanGc,
5437 ) -> Fallible<DomRoot<Attr>> {
5438 let context = domname::Context::Attribute;
5441 let (namespace, prefix, local_name) =
5442 domname::validate_and_extract(namespace, &qualified_name, context)?;
5443 let value = AttrValue::String("".to_owned());
5444 let qualified_name = LocalName::from(qualified_name);
5445 Ok(Attr::new(
5446 self,
5447 local_name,
5448 value,
5449 qualified_name,
5450 namespace,
5451 prefix,
5452 None,
5453 can_gc,
5454 ))
5455 }
5456
5457 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5459 DocumentFragment::new(self, can_gc)
5460 }
5461
5462 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5464 Text::new(data, self, can_gc)
5465 }
5466
5467 fn CreateCDATASection(
5469 &self,
5470 data: DOMString,
5471 can_gc: CanGc,
5472 ) -> Fallible<DomRoot<CDATASection>> {
5473 if self.is_html_document {
5475 return Err(Error::NotSupported(None));
5476 }
5477
5478 if data.contains("]]>") {
5480 return Err(Error::InvalidCharacter(None));
5481 }
5482
5483 Ok(CDATASection::new(data, self, can_gc))
5485 }
5486
5487 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5489 Comment::new(data, self, None, can_gc)
5490 }
5491
5492 fn CreateProcessingInstruction(
5494 &self,
5495 target: DOMString,
5496 data: DOMString,
5497 can_gc: CanGc,
5498 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5499 if !matches_name_production(&target.str()) {
5501 return Err(Error::InvalidCharacter(None));
5502 }
5503
5504 if data.contains("?>") {
5506 return Err(Error::InvalidCharacter(None));
5507 }
5508
5509 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5511 }
5512
5513 fn ImportNode(
5515 &self,
5516 node: &Node,
5517 options: BooleanOrImportNodeOptions,
5518 can_gc: CanGc,
5519 ) -> Fallible<DomRoot<Node>> {
5520 if node.is::<Document>() || node.is::<ShadowRoot>() {
5522 return Err(Error::NotSupported(None));
5523 }
5524 let (subtree, registry) = match options {
5526 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5529 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5531 let subtree = (!options.selfOnly).into();
5533 let registry = options.customElementRegistry;
5535 (subtree, registry)
5539 },
5540 };
5541 let registry = registry
5544 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5545
5546 Ok(Node::clone(node, Some(self), subtree, registry, can_gc))
5549 }
5550
5551 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5553 if node.is::<Document>() {
5555 return Err(Error::NotSupported(None));
5556 }
5557
5558 if node.is::<ShadowRoot>() {
5560 return Err(Error::HierarchyRequest(None));
5561 }
5562
5563 Node::adopt(node, self, can_gc);
5565
5566 Ok(DomRoot::from_ref(node))
5568 }
5569
5570 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5572 interface.make_ascii_lowercase();
5573 match &*interface.str() {
5574 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5575 &self.window,
5576 can_gc,
5577 ))),
5578 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5579 CompositionEvent::new_uninitialized(&self.window, can_gc),
5580 )),
5581 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5582 self.window.upcast(),
5583 can_gc,
5584 ))),
5585 "events" | "event" | "htmlevents" | "svgevents" => {
5588 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5589 },
5590 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5591 &self.window,
5592 can_gc,
5593 ))),
5594 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5595 &self.window,
5596 can_gc,
5597 ))),
5598 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5599 &self.window,
5600 can_gc,
5601 ))),
5602 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5603 self.window.upcast(),
5604 can_gc,
5605 ))),
5606 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5607 &self.window,
5608 can_gc,
5609 ))),
5610 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5611 &self.window,
5612 "".into(),
5613 can_gc,
5614 ))),
5615 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5616 &self.window,
5617 &TouchList::new(&self.window, &[], can_gc),
5618 &TouchList::new(&self.window, &[], can_gc),
5619 &TouchList::new(&self.window, &[], can_gc),
5620 can_gc,
5621 ))),
5622 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5623 &self.window,
5624 can_gc,
5625 ))),
5626 _ => Err(Error::NotSupported(None)),
5627 }
5628 }
5629
5630 fn LastModified(&self) -> DOMString {
5632 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5633 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5639 }))
5640 }
5641
5642 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5644 Range::new_with_doc(self, None, can_gc)
5645 }
5646
5647 fn CreateNodeIterator(
5649 &self,
5650 root: &Node,
5651 what_to_show: u32,
5652 filter: Option<Rc<NodeFilter>>,
5653 can_gc: CanGc,
5654 ) -> DomRoot<NodeIterator> {
5655 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5656 }
5657
5658 fn CreateTreeWalker(
5660 &self,
5661 root: &Node,
5662 what_to_show: u32,
5663 filter: Option<Rc<NodeFilter>>,
5664 ) -> DomRoot<TreeWalker> {
5665 TreeWalker::new(self, root, what_to_show, filter)
5666 }
5667
5668 fn Title(&self) -> DOMString {
5670 self.title().unwrap_or_else(|| DOMString::from(""))
5671 }
5672
5673 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5675 let root = match self.GetDocumentElement() {
5676 Some(root) => root,
5677 None => return,
5678 };
5679
5680 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5681 let elem = root.upcast::<Node>().child_elements().find(|node| {
5682 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5683 });
5684 match elem {
5685 Some(elem) => DomRoot::upcast::<Node>(elem),
5686 None => {
5687 let name = QualName::new(None, ns!(svg), local_name!("title"));
5688 let elem = Element::create(
5689 name,
5690 None,
5691 self,
5692 ElementCreator::ScriptCreated,
5693 CustomElementCreationMode::Synchronous,
5694 None,
5695 can_gc,
5696 );
5697 let parent = root.upcast::<Node>();
5698 let child = elem.upcast::<Node>();
5699 parent
5700 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5701 .unwrap()
5702 },
5703 }
5704 } else if root.namespace() == &ns!(html) {
5705 let elem = root
5706 .upcast::<Node>()
5707 .traverse_preorder(ShadowIncluding::No)
5708 .find(|node| node.is::<HTMLTitleElement>());
5709 match elem {
5710 Some(elem) => elem,
5711 None => match self.GetHead() {
5712 Some(head) => {
5713 let name = QualName::new(None, ns!(html), local_name!("title"));
5714 let elem = Element::create(
5715 name,
5716 None,
5717 self,
5718 ElementCreator::ScriptCreated,
5719 CustomElementCreationMode::Synchronous,
5720 None,
5721 can_gc,
5722 );
5723 head.upcast::<Node>()
5724 .AppendChild(elem.upcast(), can_gc)
5725 .unwrap()
5726 },
5727 None => return,
5728 },
5729 }
5730 } else {
5731 return;
5732 };
5733
5734 node.set_text_content_for_element(Some(title), can_gc);
5735 }
5736
5737 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5739 self.get_html_element()
5740 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5741 }
5742
5743 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5745 self.current_script.get()
5746 }
5747
5748 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5750 self.get_html_element().and_then(|root| {
5751 let node = root.upcast::<Node>();
5752 node.children()
5753 .find(|child| {
5754 matches!(
5755 child.type_id(),
5756 NodeTypeId::Element(ElementTypeId::HTMLElement(
5757 HTMLElementTypeId::HTMLBodyElement,
5758 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5759 HTMLElementTypeId::HTMLFrameSetElement,
5760 ))
5761 )
5762 })
5763 .map(|node| DomRoot::downcast(node).unwrap())
5764 })
5765 }
5766
5767 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5769 let new_body = match new_body {
5771 Some(new_body) => new_body,
5772 None => return Err(Error::HierarchyRequest(None)),
5773 };
5774
5775 let node = new_body.upcast::<Node>();
5776 match node.type_id() {
5777 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5778 NodeTypeId::Element(ElementTypeId::HTMLElement(
5779 HTMLElementTypeId::HTMLFrameSetElement,
5780 )) => {},
5781 _ => return Err(Error::HierarchyRequest(None)),
5782 }
5783
5784 let old_body = self.GetBody();
5786 if old_body.as_deref() == Some(new_body) {
5787 return Ok(());
5788 }
5789
5790 match (self.GetDocumentElement(), &old_body) {
5791 (Some(ref root), Some(child)) => {
5793 let root = root.upcast::<Node>();
5794 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5795 .unwrap();
5796 },
5797
5798 (None, _) => return Err(Error::HierarchyRequest(None)),
5800
5801 (Some(ref root), &None) => {
5803 let root = root.upcast::<Node>();
5804 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5805 },
5806 }
5807 Ok(())
5808 }
5809
5810 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5812 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5813 }
5814
5815 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5817 self.images.or_init(|| {
5818 HTMLCollection::new_with_filter_fn(
5819 &self.window,
5820 self.upcast(),
5821 |element, _| element.is::<HTMLImageElement>(),
5822 can_gc,
5823 )
5824 })
5825 }
5826
5827 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5829 self.embeds.or_init(|| {
5830 HTMLCollection::new_with_filter_fn(
5831 &self.window,
5832 self.upcast(),
5833 |element, _| element.is::<HTMLEmbedElement>(),
5834 can_gc,
5835 )
5836 })
5837 }
5838
5839 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5841 self.Embeds(can_gc)
5842 }
5843
5844 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5846 self.links.or_init(|| {
5847 HTMLCollection::new_with_filter_fn(
5848 &self.window,
5849 self.upcast(),
5850 |element, _| {
5851 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5852 element.has_attribute(&local_name!("href"))
5853 },
5854 can_gc,
5855 )
5856 })
5857 }
5858
5859 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5861 self.forms.or_init(|| {
5862 HTMLCollection::new_with_filter_fn(
5863 &self.window,
5864 self.upcast(),
5865 |element, _| element.is::<HTMLFormElement>(),
5866 can_gc,
5867 )
5868 })
5869 }
5870
5871 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5873 self.scripts.or_init(|| {
5874 HTMLCollection::new_with_filter_fn(
5875 &self.window,
5876 self.upcast(),
5877 |element, _| element.is::<HTMLScriptElement>(),
5878 can_gc,
5879 )
5880 })
5881 }
5882
5883 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5885 self.anchors.or_init(|| {
5886 HTMLCollection::new_with_filter_fn(
5887 &self.window,
5888 self.upcast(),
5889 |element, _| {
5890 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5891 },
5892 can_gc,
5893 )
5894 })
5895 }
5896
5897 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5899 self.applets
5900 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5901 }
5902
5903 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5905 if self.is_fully_active() {
5906 Some(self.window.Location())
5907 } else {
5908 None
5909 }
5910 }
5911
5912 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5914 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5915 }
5916
5917 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5919 self.upcast::<Node>().child_elements().next()
5920 }
5921
5922 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5924 self.upcast::<Node>()
5925 .rev_children()
5926 .find_map(DomRoot::downcast)
5927 }
5928
5929 fn ChildElementCount(&self) -> u32 {
5931 self.upcast::<Node>().child_elements().count() as u32
5932 }
5933
5934 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5936 self.upcast::<Node>().prepend(nodes, can_gc)
5937 }
5938
5939 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5941 self.upcast::<Node>().append(nodes, can_gc)
5942 }
5943
5944 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5946 self.upcast::<Node>().replace_children(nodes, can_gc)
5947 }
5948
5949 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5951 let root = self.upcast::<Node>();
5952 root.query_selector(selectors)
5953 }
5954
5955 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5957 let root = self.upcast::<Node>();
5958 root.query_selector_all(selectors)
5959 }
5960
5961 fn ReadyState(&self) -> DocumentReadyState {
5963 self.ready_state.get()
5964 }
5965
5966 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5968 if self.has_browsing_context {
5969 Some(DomRoot::from_ref(&*self.window))
5970 } else {
5971 None
5972 }
5973 }
5974
5975 fn GetCookie(&self) -> Fallible<DOMString> {
5977 if self.is_cookie_averse() {
5978 return Ok(DOMString::new());
5979 }
5980
5981 if !self.origin.is_tuple() {
5982 return Err(Error::Security(None));
5983 }
5984
5985 let url = self.url();
5986 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5987 let _ = self
5988 .window
5989 .as_global_scope()
5990 .resource_threads()
5991 .send(GetCookiesForUrl(url, tx, NonHTTP));
5992 let cookies = rx.recv().unwrap();
5993 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5994 }
5995
5996 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5998 if self.is_cookie_averse() {
5999 return Ok(());
6000 }
6001
6002 if !self.origin.is_tuple() {
6003 return Err(Error::Security(None));
6004 }
6005
6006 if !cookie.is_valid_for_cookie() {
6007 return Ok(());
6008 }
6009
6010 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
6011 vec![cookie]
6012 } else {
6013 vec![]
6014 };
6015
6016 let _ = self
6017 .window
6018 .as_global_scope()
6019 .resource_threads()
6020 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
6021 Ok(())
6022 }
6023
6024 fn BgColor(&self) -> DOMString {
6026 self.get_body_attribute(&local_name!("bgcolor"))
6027 }
6028
6029 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
6031 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
6032 }
6033
6034 fn FgColor(&self) -> DOMString {
6036 self.get_body_attribute(&local_name!("text"))
6037 }
6038
6039 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
6041 self.set_body_attribute(&local_name!("text"), value, can_gc)
6042 }
6043
6044 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
6046 if name.is_empty() {
6047 return None;
6048 }
6049 let name = Atom::from(name);
6050
6051 let elements_with_name = self.get_elements_with_name(&name);
6054 let name_iter = elements_with_name
6055 .iter()
6056 .filter(|elem| is_named_element_with_name_attribute(elem));
6057 let elements_with_id = self.get_elements_with_id(&name);
6058 let id_iter = elements_with_id
6059 .iter()
6060 .filter(|elem| is_named_element_with_id_attribute(elem));
6061 let mut elements = name_iter.chain(id_iter);
6062
6063 let first = elements.next()?;
6070 if elements.all(|other| first == other) {
6071 if let Some(nested_window_proxy) = first
6072 .downcast::<HTMLIFrameElement>()
6073 .and_then(|iframe| iframe.GetContentWindow())
6074 {
6075 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
6076 }
6077
6078 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
6080 }
6081
6082 #[derive(JSTraceable, MallocSizeOf)]
6085 struct DocumentNamedGetter {
6086 #[no_trace]
6087 name: Atom,
6088 }
6089 impl CollectionFilter for DocumentNamedGetter {
6090 fn filter(&self, elem: &Element, _root: &Node) -> bool {
6091 let type_ = match elem.upcast::<Node>().type_id() {
6092 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6093 _ => return false,
6094 };
6095 match type_ {
6096 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
6097 elem.get_name().as_ref() == Some(&self.name)
6098 },
6099 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
6100 name == *self.name ||
6101 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
6102 }),
6103 _ => false,
6107 }
6108 }
6109 }
6110 let collection = HTMLCollection::create(
6111 self.window(),
6112 self.upcast(),
6113 Box::new(DocumentNamedGetter { name }),
6114 can_gc,
6115 );
6116 Some(NamedPropertyValue::HTMLCollection(collection))
6117 }
6118
6119 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
6121 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
6122
6123 let name_map = self.name_map.borrow();
6124 for (name, elements) in &(name_map).0 {
6125 if name.is_empty() {
6126 continue;
6127 }
6128 let mut name_iter = elements
6129 .iter()
6130 .filter(|elem| is_named_element_with_name_attribute(elem));
6131 if let Some(first) = name_iter.next() {
6132 names_with_first_named_element_map.insert(name, first);
6133 }
6134 }
6135 let id_map = self.id_map.borrow();
6136 for (id, elements) in &(id_map).0 {
6137 if id.is_empty() {
6138 continue;
6139 }
6140 let mut id_iter = elements
6141 .iter()
6142 .filter(|elem| is_named_element_with_id_attribute(elem));
6143 if let Some(first) = id_iter.next() {
6144 match names_with_first_named_element_map.entry(id) {
6145 Vacant(entry) => drop(entry.insert(first)),
6146 Occupied(mut entry) => {
6147 if first.upcast::<Node>().is_before(entry.get().upcast()) {
6148 *entry.get_mut() = first;
6149 }
6150 },
6151 }
6152 }
6153 }
6154
6155 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
6156 names_with_first_named_element_map
6157 .iter()
6158 .map(|(k, v)| (*k, *v))
6159 .collect();
6160 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
6161 if a.1 == b.1 {
6162 a.0.cmp(b.0)
6165 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
6166 Ordering::Less
6167 } else {
6168 Ordering::Greater
6169 }
6170 });
6171
6172 names_with_first_named_element_vec
6173 .iter()
6174 .map(|(k, _v)| DOMString::from(&***k))
6175 .collect()
6176 }
6177
6178 fn Clear(&self) {
6180 }
6182
6183 fn CaptureEvents(&self) {
6185 }
6187
6188 fn ReleaseEvents(&self) {
6190 }
6192
6193 global_event_handlers!();
6195
6196 event_handler!(
6198 readystatechange,
6199 GetOnreadystatechange,
6200 SetOnreadystatechange
6201 );
6202
6203 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
6205 self.document_or_shadow_root.element_from_point(
6206 x,
6207 y,
6208 self.GetDocumentElement(),
6209 self.has_browsing_context,
6210 )
6211 }
6212
6213 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
6215 self.document_or_shadow_root.elements_from_point(
6216 x,
6217 y,
6218 self.GetDocumentElement(),
6219 self.has_browsing_context,
6220 )
6221 }
6222
6223 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
6225 if self.quirks_mode() == QuirksMode::Quirks {
6227 if let Some(ref body) = self.GetBody() {
6229 let e = body.upcast::<Element>();
6230 if !e.is_potentially_scrollable_body_for_scrolling_element() {
6234 return Some(DomRoot::from_ref(e));
6235 }
6236 }
6237
6238 return None;
6240 }
6241
6242 self.GetDocumentElement()
6245 }
6246
6247 fn Open(
6249 &self,
6250 _unused1: Option<DOMString>,
6251 _unused2: Option<DOMString>,
6252 can_gc: CanGc,
6253 ) -> Fallible<DomRoot<Document>> {
6254 if !self.is_html_document() {
6256 return Err(Error::InvalidState(None));
6257 }
6258
6259 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6261 return Err(Error::InvalidState(None));
6262 }
6263
6264 let entry_responsible_document = GlobalScope::entry().as_window().Document();
6266
6267 if !self.origin.same_origin(&entry_responsible_document.origin) {
6269 return Err(Error::Security(None));
6270 }
6271
6272 if self
6274 .get_current_parser()
6275 .is_some_and(|parser| parser.is_active())
6276 {
6277 return Ok(DomRoot::from_ref(self));
6278 }
6279
6280 if self.is_prompting_or_unloading() {
6282 return Ok(DomRoot::from_ref(self));
6283 }
6284
6285 if self.active_parser_was_aborted.get() {
6287 return Ok(DomRoot::from_ref(self));
6288 }
6289
6290 self.window().set_navigation_start();
6294
6295 if self.has_browsing_context() {
6298 self.abort(can_gc);
6301 }
6302
6303 for node in self
6305 .upcast::<Node>()
6306 .traverse_preorder(ShadowIncluding::Yes)
6307 {
6308 node.upcast::<EventTarget>().remove_all_listeners();
6309 }
6310
6311 if self.window.Document() == DomRoot::from_ref(self) {
6313 self.window.upcast::<EventTarget>().remove_all_listeners();
6314 }
6315
6316 Node::replace_all(None, self.upcast::<Node>(), can_gc);
6318
6319 if self.is_fully_active() {
6326 let mut new_url = entry_responsible_document.url();
6328
6329 if entry_responsible_document != DomRoot::from_ref(self) {
6331 new_url.set_fragment(None);
6332 }
6333
6334 self.set_url(new_url);
6337 }
6338
6339 self.is_initial_about_blank.set(false);
6341
6342 self.set_quirks_mode(QuirksMode::NoQuirks);
6348
6349 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6355 *self.loader.borrow_mut() =
6356 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6357 ServoParser::parse_html_script_input(self, self.url());
6358
6359 self.ready_state.set(DocumentReadyState::Loading);
6365
6366 Ok(DomRoot::from_ref(self))
6368 }
6369
6370 fn Open_(
6372 &self,
6373 url: USVString,
6374 target: DOMString,
6375 features: DOMString,
6376 can_gc: CanGc,
6377 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6378 self.browsing_context()
6379 .ok_or(Error::InvalidAccess(None))?
6380 .open(url, target, features, can_gc)
6381 }
6382
6383 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
6385 self.write(text, false, "Document", "write", can_gc)
6388 }
6389
6390 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
6392 self.write(text, true, "Document", "writeln", can_gc)
6395 }
6396
6397 fn Close(&self, can_gc: CanGc) -> ErrorResult {
6399 if !self.is_html_document() {
6400 return Err(Error::InvalidState(None));
6402 }
6403
6404 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6406 return Err(Error::InvalidState(None));
6407 }
6408
6409 let parser = match self.get_current_parser() {
6410 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6411 _ => {
6412 return Ok(());
6414 },
6415 };
6416
6417 parser.close(can_gc);
6419
6420 Ok(())
6421 }
6422
6423 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6425
6426 event_handler!(
6428 fullscreenchange,
6429 GetOnfullscreenchange,
6430 SetOnfullscreenchange
6431 );
6432
6433 fn FullscreenEnabled(&self) -> bool {
6435 self.get_allow_fullscreen()
6436 }
6437
6438 fn Fullscreen(&self) -> bool {
6440 self.fullscreen_element.get().is_some()
6441 }
6442
6443 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6445 self.fullscreen_element.get()
6447 }
6448
6449 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6451 self.exit_fullscreen(can_gc)
6452 }
6453
6454 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6458 match self.media_controls.borrow().get(&*id.str()) {
6459 Some(m) => Ok(DomRoot::from_ref(m)),
6460 None => Err(Error::InvalidAccess(None)),
6461 }
6462 }
6463
6464 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6466 if self.has_browsing_context {
6467 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6468 } else {
6469 None
6470 }
6471 }
6472
6473 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6475 self.fonts
6476 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6477 }
6478
6479 fn Hidden(&self) -> bool {
6481 self.visibility_state.get() == DocumentVisibilityState::Hidden
6482 }
6483
6484 fn VisibilityState(&self) -> DocumentVisibilityState {
6486 self.visibility_state.get()
6487 }
6488
6489 fn CreateExpression(
6490 &self,
6491 expression: DOMString,
6492 resolver: Option<Rc<XPathNSResolver>>,
6493 can_gc: CanGc,
6494 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6495 let parsed_expression =
6496 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6497 Ok(XPathExpression::new(
6498 &self.window,
6499 None,
6500 can_gc,
6501 parsed_expression,
6502 ))
6503 }
6504
6505 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6506 let global = self.global();
6507 let window = global.as_window();
6508 let evaluator = XPathEvaluator::new(window, None, can_gc);
6509 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6510 }
6511
6512 fn Evaluate(
6513 &self,
6514 expression: DOMString,
6515 context_node: &Node,
6516 resolver: Option<Rc<XPathNSResolver>>,
6517 result_type: u16,
6518 result: Option<&super::types::XPathResult>,
6519 can_gc: CanGc,
6520 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6521 let parsed_expression =
6522 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6523 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6524 context_node,
6525 result_type,
6526 result,
6527 can_gc,
6528 )
6529 }
6530
6531 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6533 self.adopted_stylesheets_frozen_types.get_or_init(
6534 || {
6535 self.adopted_stylesheets
6536 .borrow()
6537 .clone()
6538 .iter()
6539 .map(|sheet| sheet.as_rooted())
6540 .collect()
6541 },
6542 context,
6543 retval,
6544 can_gc,
6545 );
6546 }
6547
6548 fn SetAdoptedStyleSheets(
6550 &self,
6551 context: JSContext,
6552 val: HandleValue,
6553 can_gc: CanGc,
6554 ) -> ErrorResult {
6555 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6556 context,
6557 self.adopted_stylesheets.borrow_mut().as_mut(),
6558 val,
6559 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6560 can_gc,
6561 );
6562
6563 if result.is_ok() {
6565 self.adopted_stylesheets_frozen_types.clear()
6566 }
6567
6568 result
6569 }
6570}
6571
6572fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6573 if marker.get().is_none() {
6574 marker.set(Some(CrossProcessInstant::now()))
6575 }
6576}
6577
6578#[derive(Clone, Copy, PartialEq)]
6580pub(crate) enum FocusType {
6581 Element, Parent, }
6584
6585#[derive(Clone, Copy, PartialEq)]
6587pub enum FocusInitiator {
6588 Local,
6591 Remote,
6594}
6595
6596pub(crate) enum FocusEventType {
6598 Focus, Blur, }
6601
6602#[derive(JSTraceable, MallocSizeOf)]
6603pub(crate) enum AnimationFrameCallback {
6604 DevtoolsFramerateTick {
6605 actor_name: String,
6606 },
6607 FrameRequestCallback {
6608 #[conditional_malloc_size_of]
6609 callback: Rc<FrameRequestCallback>,
6610 },
6611}
6612
6613impl AnimationFrameCallback {
6614 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6615 match *self {
6616 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6617 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6618 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6619 devtools_sender.send(msg).unwrap();
6620 },
6621 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6622 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6625 },
6626 }
6627 }
6628}
6629
6630#[derive(Default, JSTraceable, MallocSizeOf)]
6631#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6632struct PendingInOrderScriptVec {
6633 scripts: DomRefCell<VecDeque<PendingScript>>,
6634}
6635
6636impl PendingInOrderScriptVec {
6637 fn is_empty(&self) -> bool {
6638 self.scripts.borrow().is_empty()
6639 }
6640
6641 fn push(&self, element: &HTMLScriptElement) {
6642 self.scripts
6643 .borrow_mut()
6644 .push_back(PendingScript::new(element));
6645 }
6646
6647 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6648 let mut scripts = self.scripts.borrow_mut();
6649 let entry = scripts
6650 .iter_mut()
6651 .find(|entry| &*entry.element == element)
6652 .unwrap();
6653 entry.loaded(result);
6654 }
6655
6656 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6657 let mut scripts = self.scripts.borrow_mut();
6658 let pair = scripts.front_mut()?.take_result()?;
6659 scripts.pop_front();
6660 Some(pair)
6661 }
6662
6663 fn clear(&self) {
6664 *self.scripts.borrow_mut() = Default::default();
6665 }
6666}
6667
6668#[derive(JSTraceable, MallocSizeOf)]
6669#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6670struct PendingScript {
6671 element: Dom<HTMLScriptElement>,
6672 load: Option<ScriptResult>,
6674}
6675
6676impl PendingScript {
6677 fn new(element: &HTMLScriptElement) -> Self {
6678 Self {
6679 element: Dom::from_ref(element),
6680 load: None,
6681 }
6682 }
6683
6684 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6685 Self {
6686 element: Dom::from_ref(element),
6687 load,
6688 }
6689 }
6690
6691 fn loaded(&mut self, result: ScriptResult) {
6692 assert!(self.load.is_none());
6693 self.load = Some(result);
6694 }
6695
6696 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6697 self.load
6698 .take()
6699 .map(|result| (DomRoot::from_ref(&*self.element), result))
6700 }
6701}
6702
6703fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6704 let type_ = match elem.upcast::<Node>().type_id() {
6705 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6706 _ => return false,
6707 };
6708 match type_ {
6709 HTMLElementTypeId::HTMLFormElement |
6710 HTMLElementTypeId::HTMLIFrameElement |
6711 HTMLElementTypeId::HTMLImageElement => true,
6712 _ => false,
6716 }
6717}
6718
6719fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6720 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6724}
6725
6726impl DocumentHelpers for Document {
6727 fn ensure_safe_to_run_script_or_layout(&self) {
6728 Document::ensure_safe_to_run_script_or_layout(self)
6729 }
6730}