1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::{LazyLock, Mutex};
14use std::time::Duration;
15
16use bitflags::bitflags;
17use chrono::Local;
18use content_security_policy::sandboxing_directive::SandboxingFlagSet;
19use content_security_policy::{CspList, Policy as CspPolicy, PolicyDisposition};
20use cookie::Cookie;
21use data_url::mime::Mime;
22use devtools_traits::ScriptToDevtoolsControlMsg;
23use dom_struct::dom_struct;
24use embedder_traits::{
25 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, Image, LoadStatus,
26};
27use encoding_rs::{Encoding, UTF_8};
28use fonts::WebFontDocumentContext;
29use html5ever::{LocalName, Namespace, QualName, local_name, ns};
30use hyper_serde::Serde;
31use js::realm::CurrentRealm;
32use js::rust::{HandleObject, HandleValue, MutableHandleValue};
33use layout_api::{
34 PendingRestyle, ReflowGoal, ReflowPhasesRun, ReflowStatistics, RestyleReason,
35 ScrollContainerQueryFlags, TrustedNodeAddress,
36};
37use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
38use net_traits::CookieSource::NonHTTP;
39use net_traits::CoreResourceMsg::{GetCookieStringForUrl, SetCookiesForUrl};
40use net_traits::ReferrerPolicy;
41use net_traits::policy_container::PolicyContainer;
42use net_traits::pub_domains::is_pub_domain;
43use net_traits::request::{
44 InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
45};
46use percent_encoding::percent_decode;
47use profile_traits::generic_channel as profile_generic_channel;
48use profile_traits::time::TimerMetadataFrameType;
49use regex::bytes::Regex;
50use rustc_hash::{FxBuildHasher, FxHashMap};
51use script_bindings::cell::{DomRefCell, Ref, RefMut};
52use script_bindings::interfaces::DocumentHelpers;
53use script_bindings::reflector::reflect_dom_object_with_proto;
54use script_bindings::script_runtime::JSContext;
55use script_traits::{DocumentActivity, ProgressiveWebMetricType};
56use servo_arc::Arc;
57use servo_base::cross_process_instant::CrossProcessInstant;
58use servo_base::generic_channel::GenericSend;
59use servo_base::id::WebViewId;
60use servo_base::{Epoch, generic_channel};
61use servo_config::pref;
62use servo_constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
63use servo_media::{ClientContextId, ServoMedia};
64use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
65use style::attr::AttrValue;
66use style::context::QuirksMode;
67use style::invalidation::element::restyle_hints::RestyleHint;
68use style::selector_parser::Snapshot;
69use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
70use style::str::{split_html_space_chars, str_join};
71use style::stylesheet_set::DocumentStylesheetSet;
72use style::stylesheets::{Origin, OriginSet, Stylesheet};
73use style::stylist::Stylist;
74use stylo_atoms::Atom;
75use time::Duration as TimeDuration;
76use url::{Host, Position};
77
78use crate::animations::Animations;
79use crate::document_loader::{DocumentLoader, LoadType};
80use crate::dom::animationtimeline::AnimationTimeline;
81use crate::dom::attr::Attr;
82use crate::dom::beforeunloadevent::BeforeUnloadEvent;
83use crate::dom::bindings::callback::ExceptionHandling;
84use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
85use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
86 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
87};
88use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
89use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
90use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
91#[cfg(any(feature = "webxr", feature = "gamepad"))]
92use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
93use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
94use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
95use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
96use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
97use crate::dom::bindings::codegen::Bindings::WindowBinding::{
98 FrameRequestCallback, ScrollBehavior, WindowMethods,
99};
100use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
101use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
102use crate::dom::bindings::codegen::UnionTypes::{
103 BooleanOrImportNodeOptions, NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
104};
105use crate::dom::bindings::domname::{
106 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
107};
108use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
109use crate::dom::bindings::frozenarray::CachedFrozenArray;
110use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
111use crate::dom::bindings::num::Finite;
112use crate::dom::bindings::refcounted::Trusted;
113use crate::dom::bindings::reflector::DomGlobal;
114use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout, UnrootedDom};
115use crate::dom::bindings::str::{DOMString, USVString};
116use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
117use crate::dom::bindings::weakref::DOMTracker;
118use crate::dom::bindings::xmlname::matches_name_production;
119use crate::dom::cdatasection::CDATASection;
120use crate::dom::comment::Comment;
121use crate::dom::compositionevent::CompositionEvent;
122use crate::dom::css::cssstylesheet::CSSStyleSheet;
123use crate::dom::css::fontfaceset::FontFaceSet;
124use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
125use crate::dom::customelementregistry::{
126 CustomElementDefinition, CustomElementReactionStack, CustomElementRegistry,
127};
128use crate::dom::customevent::CustomEvent;
129use crate::dom::document::focus::{DocumentFocusHandler, FocusableArea};
130use crate::dom::document_embedder_controls::DocumentEmbedderControls;
131use crate::dom::document_event_handler::DocumentEventHandler;
132use crate::dom::documentfragment::DocumentFragment;
133use crate::dom::documentorshadowroot::{
134 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
135};
136use crate::dom::documenttimeline::DocumentTimeline;
137use crate::dom::documenttype::DocumentType;
138use crate::dom::domimplementation::DOMImplementation;
139use crate::dom::element::attributes::storage::AttrRef;
140use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
141use crate::dom::event::{Event, EventBubbles, EventCancelable};
142use crate::dom::eventtarget::EventTarget;
143use crate::dom::execcommand::basecommand::{CommandName, DefaultSingleLineContainerName};
144use crate::dom::execcommand::execcommands::DocumentExecCommandSupport;
145use crate::dom::focusevent::FocusEvent;
146use crate::dom::globalscope::GlobalScope;
147use crate::dom::hashchangeevent::HashChangeEvent;
148use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
149use crate::dom::html::htmlareaelement::HTMLAreaElement;
150use crate::dom::html::htmlbaseelement::HTMLBaseElement;
151use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
152use crate::dom::html::htmlelement::HTMLElement;
153use crate::dom::html::htmlembedelement::HTMLEmbedElement;
154use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
155use crate::dom::html::htmlheadelement::HTMLHeadElement;
156use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
157use crate::dom::html::htmliframeelement::HTMLIFrameElement;
158use crate::dom::html::htmlimageelement::HTMLImageElement;
159use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
160use crate::dom::html::htmltitleelement::HTMLTitleElement;
161use crate::dom::htmldetailselement::DetailsNameGroups;
162use crate::dom::intersectionobserver::IntersectionObserver;
163use crate::dom::keyboardevent::KeyboardEvent;
164use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
165use crate::dom::location::Location;
166use crate::dom::messageevent::MessageEvent;
167use crate::dom::mouseevent::MouseEvent;
168use crate::dom::node::{Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding};
169use crate::dom::nodeiterator::NodeIterator;
170use crate::dom::nodelist::NodeList;
171use crate::dom::pagetransitionevent::PageTransitionEvent;
172use crate::dom::performance::performanceentry::PerformanceEntry;
173use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
174use crate::dom::processinginstruction::ProcessingInstruction;
175use crate::dom::promise::Promise;
176use crate::dom::range::Range;
177use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
178use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
179use crate::dom::selection::Selection;
180use crate::dom::servoparser::ServoParser;
181use crate::dom::shadowroot::ShadowRoot;
182use crate::dom::storageevent::StorageEvent;
183use crate::dom::text::Text;
184use crate::dom::touchevent::TouchEvent as DomTouchEvent;
185use crate::dom::touchlist::TouchList;
186use crate::dom::treewalker::TreeWalker;
187use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
188use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
189use crate::dom::uievent::UIEvent;
190use crate::dom::virtualmethods::vtable_for;
191use crate::dom::websocket::WebSocket;
192use crate::dom::window::Window;
193use crate::dom::windowproxy::WindowProxy;
194use crate::dom::xpathevaluator::XPathEvaluator;
195use crate::dom::xpathexpression::XPathExpression;
196use crate::fetch::{DeferredFetchRecordInvokeState, FetchCanceller};
197use crate::iframe_collection::IFrameCollection;
198use crate::image_animation::ImageAnimationManager;
199use crate::mime::{APPLICATION, CHARSET};
200use crate::navigation::navigate;
201use crate::network_listener::{FetchResponseListener, NetworkListener};
202use crate::script_runtime::CanGc;
203use crate::script_thread::ScriptThread;
204use crate::stylesheet_set::StylesheetSetRef;
205use crate::task::NonSendTaskBox;
206use crate::task_source::TaskSourceName;
207use crate::timers::OneshotTimerCallback;
208use crate::xpath::parse_expression;
209
210#[derive(Clone, Copy, PartialEq)]
211pub(crate) enum FireMouseEventType {
212 Move,
213 Over,
214 Out,
215 Enter,
216 Leave,
217}
218
219impl FireMouseEventType {
220 pub(crate) fn as_str(&self) -> &str {
221 match *self {
222 FireMouseEventType::Move => "mousemove",
223 FireMouseEventType::Over => "mouseover",
224 FireMouseEventType::Out => "mouseout",
225 FireMouseEventType::Enter => "mouseenter",
226 FireMouseEventType::Leave => "mouseleave",
227 }
228 }
229}
230
231#[derive(JSTraceable, MallocSizeOf)]
232pub(crate) struct RefreshRedirectDue {
233 #[no_trace]
234 pub(crate) url: ServoUrl,
235 #[ignore_malloc_size_of = "non-owning"]
236 pub(crate) window: DomRoot<Window>,
237}
238impl RefreshRedirectDue {
239 pub(crate) fn invoke(self, cx: &mut js::context::JSContext) {
241 let load_data = self
251 .window
252 .load_data_for_document(self.url.clone(), self.window.pipeline_id());
253 navigate(
254 cx,
255 &self.window,
256 NavigationHistoryBehavior::Replace,
257 false,
258 load_data,
259 );
260 }
261}
262
263#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
264pub(crate) enum IsHTMLDocument {
265 HTMLDocument,
266 NonHTMLDocument,
267}
268
269#[derive(JSTraceable, MallocSizeOf)]
271pub(crate) enum DeclarativeRefresh {
272 PendingLoad {
273 #[no_trace]
274 url: ServoUrl,
275 time: u64,
276 },
277 CreatedAfterLoad,
278}
279
280#[derive(JSTraceable, MallocSizeOf, PartialEq)]
281#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
282struct PendingScrollEvent {
283 target: Dom<EventTarget>,
285 #[no_trace]
287 event: Atom,
288}
289
290impl PendingScrollEvent {
291 fn equivalent(&self, target: &EventTarget, event: &Atom) -> bool {
292 &*self.target == target && self.event == *event
293 }
294}
295
296#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
299pub(crate) struct RenderingUpdateReason(u8);
300
301bitflags! {
302 impl RenderingUpdateReason: u8 {
303 const ResizeObserverStartedObservingTarget = 1 << 0;
306 const IntersectionObserverStartedObservingTarget = 1 << 1;
309 const FontReadyPromiseFulfilled = 1 << 2;
313 }
314}
315
316#[dom_struct]
318pub(crate) struct Document {
319 node: Node,
320 document_or_shadow_root: DocumentOrShadowRoot,
321 window: Dom<Window>,
322 implementation: MutNullableDom<DOMImplementation>,
323 #[ignore_malloc_size_of = "type from external crate"]
324 #[no_trace]
325 content_type: Mime,
326 last_modified: Option<String>,
327 #[no_trace]
328 encoding: Cell<&'static Encoding>,
329 has_browsing_context: bool,
330 is_html_document: bool,
331 #[no_trace]
332 activity: Cell<DocumentActivity>,
333 #[no_trace]
335 url: DomRefCell<ServoUrl>,
336 #[no_trace]
338 about_base_url: DomRefCell<Option<ServoUrl>>,
339 #[ignore_malloc_size_of = "defined in selectors"]
340 #[no_trace]
341 quirks_mode: Cell<QuirksMode>,
342 event_handler: DocumentEventHandler,
344 focus_handler: DocumentFocusHandler,
346 embedder_controls: DocumentEmbedderControls,
348 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
351 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
352 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
353 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
354 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
355 images: MutNullableDom<HTMLCollection>,
356 embeds: MutNullableDom<HTMLCollection>,
357 links: MutNullableDom<HTMLCollection>,
358 forms: MutNullableDom<HTMLCollection>,
359 scripts: MutNullableDom<HTMLCollection>,
360 anchors: MutNullableDom<HTMLCollection>,
361 applets: MutNullableDom<HTMLCollection>,
362 iframes: RefCell<IFrameCollection>,
364 #[no_trace]
367 style_shared_lock: StyleSharedRwLock,
368 #[custom_trace]
370 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
371 stylesheet_list: MutNullableDom<StyleSheetList>,
372 ready_state: Cell<DocumentReadyState>,
373 domcontentloaded_dispatched: Cell<bool>,
375 current_script: MutNullableDom<HTMLScriptElement>,
377 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
379 script_blocking_stylesheets_count: Cell<u32>,
381 render_blocking_element_count: Cell<u32>,
384 deferred_scripts: PendingInOrderScriptVec,
386 asap_in_order_scripts_list: PendingInOrderScriptVec,
388 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
390 animation_frame_ident: Cell<u32>,
393 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
396 running_animation_callbacks: Cell<bool>,
401 loader: DomRefCell<DocumentLoader>,
403 current_parser: MutNullableDom<ServoParser>,
405 base_element: MutNullableDom<HTMLBaseElement>,
407 target_base_element: MutNullableDom<HTMLBaseElement>,
409 appropriate_template_contents_owner_document: MutNullableDom<Document>,
412 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
415 #[no_trace]
419 needs_restyle: Cell<RestyleReason>,
420 #[no_trace]
423 dom_interactive: Cell<Option<CrossProcessInstant>>,
424 #[no_trace]
426 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
427 #[no_trace]
429 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
430 #[no_trace]
431 dom_complete: Cell<Option<CrossProcessInstant>>,
432 #[no_trace]
433 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
434 #[no_trace]
435 load_event_start: Cell<Option<CrossProcessInstant>>,
436 #[no_trace]
437 load_event_end: Cell<Option<CrossProcessInstant>>,
438 #[no_trace]
439 unload_event_start: Cell<Option<CrossProcessInstant>>,
440 #[no_trace]
441 unload_event_end: Cell<Option<CrossProcessInstant>>,
442
443 #[no_trace]
445 origin: DomRefCell<MutableOrigin>,
446 referrer: Option<String>,
448 target_element: MutNullableDom<Element>,
450 #[no_trace]
452 policy_container: DomRefCell<PolicyContainer>,
453 #[no_trace]
455 preloaded_resources: DomRefCell<PreloadedResources>,
456 ignore_destructive_writes_counter: Cell<u32>,
458 ignore_opens_during_unload_counter: Cell<u32>,
460 spurious_animation_frames: Cell<u8>,
464
465 fullscreen_element: MutNullableDom<Element>,
467 form_id_listener_map:
474 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
475 #[no_trace]
476 interactive_time: DomRefCell<ProgressiveWebMetrics>,
477 #[no_trace]
478 tti_window: DomRefCell<InteractiveWindow>,
479 canceller: FetchCanceller,
481 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
483 page_showing: Cell<bool>,
485 salvageable: Cell<bool>,
487 active_parser_was_aborted: Cell<bool>,
489 fired_unload: Cell<bool>,
491 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
493 redirect_count: Cell<u16>,
495 #[no_trace]
497 redirect_start: Cell<Option<CrossProcessInstant>>,
498 #[no_trace]
500 redirect_end: Cell<Option<CrossProcessInstant>>,
501 #[no_trace]
503 secure_connection_start: Cell<Option<CrossProcessInstant>>,
504 script_and_layout_blockers: Cell<u32>,
506 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
508 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
509 completely_loaded: Cell<bool>,
511 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
513 shadow_roots_styles_changed: Cell<bool>,
515 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
521 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
524 has_pending_animated_image_update: Cell<bool>,
526 selection: MutNullableDom<Selection>,
528 timeline: Dom<DocumentTimeline>,
531 animations: Animations,
533 image_animation_manager: DomRefCell<ImageAnimationManager>,
535 dirty_root: MutNullableDom<Element>,
537 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
539 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
548 fonts: MutNullableDom<FontFaceSet>,
551 visibility_state: Cell<DocumentVisibilityState>,
553 status_code: Option<u16>,
555 is_initial_about_blank: Cell<bool>,
557 allow_declarative_shadow_roots: Cell<bool>,
559 #[no_trace]
561 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
562 has_trustworthy_ancestor_origin: Cell<bool>,
564 intersection_observer_task_queued: Cell<bool>,
566 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
578 highlighted_dom_node: MutNullableDom<Node>,
580 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
583 #[ignore_malloc_size_of = "mozjs"]
585 adopted_stylesheets_frozen_types: CachedFrozenArray,
586 pending_scroll_events: DomRefCell<Vec<PendingScrollEvent>>,
590 rendering_update_reasons: Cell<RenderingUpdateReason>,
592 waiting_on_canvas_image_updates: Cell<bool>,
596 root_removal_noted: Cell<bool>,
598 #[no_trace]
606 current_rendering_epoch: Cell<Epoch>,
607 #[conditional_malloc_size_of]
609 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
610 #[no_trace]
611 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
613 #[no_trace]
614 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
621 #[no_trace]
623 favicon: RefCell<Option<Image>>,
624
625 websockets: DOMTracker<WebSocket>,
627
628 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
630
631 #[no_trace]
633 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
634
635 layout_animations_test_enabled: bool,
637
638 #[no_trace]
640 state_override: DomRefCell<FxHashMap<CommandName, bool>>,
641
642 #[no_trace]
644 value_override: DomRefCell<FxHashMap<CommandName, DOMString>>,
645
646 #[no_trace]
648 default_single_line_container_name: Cell<DefaultSingleLineContainerName>,
649
650 css_styling_flag: Cell<bool>,
652}
653
654impl Document {
655 fn unloading_cleanup_steps(&self) {
657 if self.close_outstanding_websockets() {
660 self.salvageable.set(false);
662 }
663
664 if !self.salvageable.get() {
669 let global_scope = self.window.as_global_scope();
670
671 global_scope.close_event_sources();
673
674 let msg = ScriptToConstellationMessage::DiscardDocument;
679 let _ = global_scope.script_to_constellation_chan().send(msg);
680 }
681 }
682
683 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
684 self.websockets.track(websocket);
685 }
686
687 fn close_outstanding_websockets(&self) -> bool {
688 let mut closed_any_websocket = false;
689 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
690 if websocket.make_disappear() {
691 closed_any_websocket = true;
692 }
693 });
694 closed_any_websocket
695 }
696
697 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
698 debug_assert!(*node.owner_doc() == *self);
699 if !node.is_connected() {
700 return;
701 }
702
703 let parent = match node.parent_in_flat_tree() {
704 Some(parent) => parent,
705 None => {
706 let Some(document_element) = self.GetDocumentElement() else {
709 if !self.root_removal_noted.get() {
711 self.add_restyle_reason(RestyleReason::DOMChanged);
712 self.root_removal_noted.set(true);
713 }
714 return;
715 };
716 self.root_removal_noted.set(false);
719
720 if let Some(dirty_root) = self.dirty_root.get() {
721 if dirty_root.is_connected() {
722 for ancestor in dirty_root
725 .upcast::<Node>()
726 .inclusive_ancestors_in_flat_tree()
727 {
728 if ancestor.is::<Element>() {
729 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
730 }
731 }
732 }
733 }
734 self.dirty_root.set(Some(&document_element));
735 return;
736 },
737 };
738
739 if let Some(parent_element) = parent.downcast::<Element>() {
740 if !parent_element.is_styled() {
741 return;
742 }
743 if parent_element.is_display_none() {
744 return;
745 }
746 }
747
748 let element_parent: DomRoot<Element>;
749 let element = match node.downcast::<Element>() {
750 Some(element) => element,
751 None => {
752 match DomRoot::downcast::<Element>(parent) {
755 Some(parent) => {
756 element_parent = parent;
757 &element_parent
758 },
759 None => {
760 return;
764 },
765 }
766 },
767 };
768
769 let dirty_root = match self.dirty_root.get() {
770 Some(root) if root.is_connected() => root,
771 _ => {
772 element
773 .upcast::<Node>()
774 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
775 self.dirty_root.set(Some(element));
776 return;
777 },
778 };
779
780 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
781 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
782 return;
783 }
784
785 if ancestor.is::<Element>() {
786 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
787 }
788 }
789
790 let new_dirty_root = element
791 .upcast::<Node>()
792 .common_ancestor_in_flat_tree(dirty_root.upcast())
793 .expect("Couldn't find common ancestor");
794
795 let mut has_dirty_descendants = true;
796 for ancestor in dirty_root
797 .upcast::<Node>()
798 .inclusive_ancestors_in_flat_tree()
799 {
800 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
801 has_dirty_descendants &= *ancestor != *new_dirty_root;
802 }
803
804 self.dirty_root
805 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
806 }
807
808 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
809 self.dirty_root.take()
810 }
811
812 #[inline]
813 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
814 self.loader.borrow()
815 }
816
817 #[inline]
818 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
819 self.loader.borrow_mut()
820 }
821
822 #[inline]
823 pub(crate) fn has_browsing_context(&self) -> bool {
824 self.has_browsing_context
825 }
826
827 #[inline]
829 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
830 if self.has_browsing_context {
831 self.window.undiscarded_window_proxy()
832 } else {
833 None
834 }
835 }
836
837 pub(crate) fn webview_id(&self) -> WebViewId {
838 self.window.webview_id()
839 }
840
841 #[inline]
842 pub(crate) fn window(&self) -> &Window {
843 &self.window
844 }
845
846 #[inline]
847 pub(crate) fn is_html_document(&self) -> bool {
848 self.is_html_document
849 }
850
851 pub(crate) fn is_xhtml_document(&self) -> bool {
852 self.content_type.matches(APPLICATION, "xhtml+xml")
853 }
854
855 pub(crate) fn is_fully_active(&self) -> bool {
856 self.activity.get() == DocumentActivity::FullyActive
857 }
858
859 pub(crate) fn is_active(&self) -> bool {
860 self.activity.get() != DocumentActivity::Inactive
861 }
862
863 #[inline]
864 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
865 self.current_rendering_epoch.get()
866 }
867
868 pub(crate) fn set_activity(&self, cx: &mut js::context::JSContext, activity: DocumentActivity) {
869 assert!(self.has_browsing_context);
871 if activity == self.activity.get() {
872 return;
873 }
874
875 self.activity.set(activity);
877 let media = ServoMedia::get();
878 let pipeline_id = self.window().pipeline_id();
879 let client_context_id =
880 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
881
882 if activity != DocumentActivity::FullyActive {
883 self.window().suspend(cx);
884 media.suspend(&client_context_id);
885 return;
886 }
887
888 self.title_changed();
889 self.notify_embedder_favicon();
890 self.dirty_all_nodes();
891 self.window().resume(CanGc::from_cx(cx));
892 media.resume(&client_context_id);
893
894 if self.ready_state.get() != DocumentReadyState::Complete {
895 return;
896 }
897
898 let document = Trusted::new(self);
902 self.owner_global()
903 .task_manager()
904 .dom_manipulation_task_source()
905 .queue(task!(fire_pageshow_event: move |cx| {
906 let document = document.root();
907 let window = document.window();
908 if document.page_showing.get() {
910 return;
911 }
912 document.page_showing.set(true);
914 document.update_visibility_state(cx, DocumentVisibilityState::Visible);
916 let event = PageTransitionEvent::new(
919 window,
920 atom!("pageshow"),
921 false, false, true, CanGc::from_cx(cx),
925 );
926 let event = event.upcast::<Event>();
927 event.set_trusted(true);
928 window.dispatch_event_with_target_override(cx, event);
929 }))
930 }
931
932 pub(crate) fn origin(&self) -> Ref<'_, MutableOrigin> {
933 self.origin.borrow()
934 }
935
936 pub(crate) fn mark_as_internal(&self) {
939 *self.origin.borrow_mut() = MutableOrigin::new(ImmutableOrigin::new_opaque());
940 }
941
942 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
943 *self.protocol_handler_automation_mode.borrow_mut() = mode;
944 }
945
946 pub(crate) fn url(&self) -> ServoUrl {
948 self.url.borrow().clone()
949 }
950
951 pub(crate) fn set_url(&self, url: ServoUrl) {
952 *self.url.borrow_mut() = url;
953 }
954
955 pub(crate) fn about_base_url(&self) -> Option<ServoUrl> {
956 self.about_base_url.borrow().clone()
957 }
958
959 pub(crate) fn set_about_base_url(&self, about_base_url: Option<ServoUrl>) {
960 *self.about_base_url.borrow_mut() = about_base_url;
961 }
962
963 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
965 let document_url = self.url();
966 if document_url.as_str() == "about:srcdoc" {
968 return self
971 .about_base_url()
972 .expect("about:srcdoc page should always have an about base URL");
973 }
974
975 if document_url.matches_about_blank() {
978 if let Some(about_base_url) = self.about_base_url() {
979 return about_base_url;
980 }
981 }
982
983 document_url
985 }
986
987 pub(crate) fn base_url(&self) -> ServoUrl {
989 match self.base_element() {
990 None => self.fallback_base_url(),
992 Some(base) => base.frozen_base_url(),
994 }
995 }
996
997 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
998 self.needs_restyle.set(self.needs_restyle.get() | reason)
999 }
1000
1001 pub(crate) fn clear_restyle_reasons(&self) {
1002 self.needs_restyle.set(RestyleReason::empty());
1003 }
1004
1005 pub(crate) fn restyle_reason(&self) -> RestyleReason {
1006 let mut condition = self.needs_restyle.get();
1007 if self.stylesheets.borrow().has_changed() {
1008 condition.insert(RestyleReason::StylesheetsChanged);
1009 }
1010
1011 if let Some(root) = self.GetDocumentElement() {
1015 if root.upcast::<Node>().has_dirty_descendants() {
1016 condition.insert(RestyleReason::DOMChanged);
1017 }
1018 }
1019
1020 if !self.pending_restyles.borrow().is_empty() {
1021 condition.insert(RestyleReason::PendingRestyles);
1022 }
1023
1024 condition
1025 }
1026
1027 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1029 self.base_element.get()
1030 }
1031
1032 pub(crate) fn target_base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
1034 self.target_base_element.get()
1035 }
1036
1037 pub(crate) fn refresh_base_element(&self) {
1039 if let Some(base_element) = self.base_element.get() {
1040 base_element.clear_frozen_base_url();
1041 }
1042 let new_base_element = self
1043 .upcast::<Node>()
1044 .traverse_preorder(ShadowIncluding::No)
1045 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1046 .find(|element| {
1047 element
1048 .upcast::<Element>()
1049 .has_attribute(&local_name!("href"))
1050 });
1051 if let Some(ref new_base_element) = new_base_element {
1052 new_base_element.set_frozen_base_url();
1053 }
1054 self.base_element.set(new_base_element.as_deref());
1055
1056 let new_target_base_element = self
1057 .upcast::<Node>()
1058 .traverse_preorder(ShadowIncluding::No)
1059 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
1060 .next();
1061 self.target_base_element
1062 .set(new_target_base_element.as_deref());
1063 }
1064
1065 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1066 self.quirks_mode.get()
1067 }
1068
1069 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1070 let old_mode = self.quirks_mode.replace(new_mode);
1071
1072 if old_mode != new_mode {
1073 self.window.layout_mut().set_quirks_mode(new_mode);
1074 }
1075 }
1076
1077 pub(crate) fn encoding(&self) -> &'static Encoding {
1078 self.encoding.get()
1079 }
1080
1081 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1082 self.encoding.set(encoding);
1083 }
1084
1085 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1086 if node.is_connected() {
1087 node.note_dirty_descendants();
1088 }
1089
1090 node.dirty(NodeDamage::ContentOrHeritage);
1093 }
1094
1095 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1097 self.document_or_shadow_root
1098 .unregister_named_element(&self.id_map, to_unregister, &id);
1099 self.reset_form_owner_for_listeners(&id, can_gc);
1100 }
1101
1102 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1104 let root = self.GetDocumentElement().expect(
1105 "The element is in the document, so there must be a document \
1106 element.",
1107 );
1108 self.document_or_shadow_root.register_named_element(
1109 &self.id_map,
1110 element,
1111 &id,
1112 DomRoot::from_ref(root.upcast::<Node>()),
1113 );
1114 self.reset_form_owner_for_listeners(&id, can_gc);
1115 }
1116
1117 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1119 self.document_or_shadow_root
1120 .unregister_named_element(&self.name_map, to_unregister, &name);
1121 }
1122
1123 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1125 let root = self.GetDocumentElement().expect(
1126 "The element is in the document, so there must be a document \
1127 element.",
1128 );
1129 self.document_or_shadow_root.register_named_element(
1130 &self.name_map,
1131 element,
1132 &name,
1133 DomRoot::from_ref(root.upcast::<Node>()),
1134 );
1135 }
1136
1137 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1138 &self,
1139 id: DOMString,
1140 listener: &T,
1141 ) {
1142 let mut map = self.form_id_listener_map.borrow_mut();
1143 let listener = listener.to_element();
1144 let set = map.entry(Atom::from(id)).or_default();
1145 set.insert(Dom::from_ref(listener));
1146 }
1147
1148 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1149 &self,
1150 id: DOMString,
1151 listener: &T,
1152 ) {
1153 let mut map = self.form_id_listener_map.borrow_mut();
1154 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1155 entry
1156 .get_mut()
1157 .remove(&Dom::from_ref(listener.to_element()));
1158 if entry.get().is_empty() {
1159 entry.remove();
1160 }
1161 }
1162 }
1163
1164 fn find_a_potential_indicated_element(&self, fragment: &str) -> Option<DomRoot<Element>> {
1166 self.get_element_by_id(&Atom::from(fragment))
1170 .or_else(|| self.get_anchor_by_name(fragment))
1174 }
1175
1176 fn select_indicated_part(&self, fragment: &str) -> Option<DomRoot<Node>> {
1179 if fragment.is_empty() {
1189 return Some(DomRoot::from_ref(self.upcast()));
1190 }
1191 if let Some(potential_indicated_element) = self.find_a_potential_indicated_element(fragment)
1193 {
1194 return Some(DomRoot::upcast(potential_indicated_element));
1196 }
1197 let fragment_bytes = percent_decode(fragment.as_bytes());
1199 let Ok(decoded_fragment) = fragment_bytes.decode_utf8() else {
1201 return None;
1202 };
1203 if let Some(potential_indicated_element) =
1205 self.find_a_potential_indicated_element(&decoded_fragment)
1206 {
1207 return Some(DomRoot::upcast(potential_indicated_element));
1209 }
1210 if decoded_fragment.eq_ignore_ascii_case("top") {
1212 return Some(DomRoot::from_ref(self.upcast()));
1213 }
1214 None
1216 }
1217
1218 pub(crate) fn scroll_to_the_fragment(&self, cx: &mut js::context::JSContext, fragment: &str) {
1220 let Some(indicated_part) = self.select_indicated_part(fragment) else {
1225 self.set_target_element(None);
1226 return;
1227 };
1228 if *indicated_part == *self.upcast() {
1230 self.set_target_element(None);
1232 self.window.scroll(0.0, 0.0, ScrollBehavior::Instant);
1237 return;
1239 }
1240 let Some(target) = indicated_part.downcast::<Element>() else {
1243 unreachable!("Indicated part should always be an element");
1245 };
1246 self.set_target_element(Some(target));
1248 target.scroll_into_view_with_options(
1252 ScrollBehavior::Auto,
1253 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Start),
1254 ScrollAxisState::new_always_scroll_position(ScrollLogicalPosition::Nearest),
1255 None,
1256 None,
1257 );
1258
1259 indicated_part.run_the_focusing_steps(cx, Some(FocusableArea::Viewport));
1262
1263 self.event_handler()
1265 .set_sequential_focus_navigation_starting_point(target.upcast());
1266 }
1267
1268 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1269 let name = Atom::from(name);
1270 self.name_map.borrow().get(&name).and_then(|elements| {
1271 elements
1272 .iter()
1273 .find(|e| e.is::<HTMLAnchorElement>())
1274 .map(|e| DomRoot::from_ref(&**e))
1275 })
1276 }
1277
1278 pub(crate) fn set_ready_state(
1280 &self,
1281 cx: &mut js::context::JSContext,
1282 state: DocumentReadyState,
1283 ) {
1284 match state {
1285 DocumentReadyState::Loading => {
1286 if self.window().is_top_level() {
1287 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1288 self.webview_id(),
1289 LoadStatus::Started,
1290 ));
1291 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1292 }
1293 },
1294 DocumentReadyState::Complete => {
1295 if self.window().is_top_level() {
1296 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1297 self.webview_id(),
1298 LoadStatus::Complete,
1299 ));
1300 }
1301 update_with_current_instant(&self.dom_complete);
1302 },
1303 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1304 };
1305
1306 self.ready_state.set(state);
1307
1308 self.upcast::<EventTarget>()
1309 .fire_event(cx, atom!("readystatechange"));
1310 }
1311
1312 pub(crate) fn scripting_enabled(&self) -> bool {
1315 self.has_browsing_context() &&
1318 !self.has_active_sandboxing_flag(
1322 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1323 )
1324 }
1325
1326 pub(crate) fn title_changed(&self) {
1328 if self.browsing_context().is_some() {
1329 self.send_title_to_embedder();
1330 let title = String::from(self.Title());
1331 self.window
1332 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1333 self.window.pipeline_id(),
1334 title.clone(),
1335 ));
1336 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1337 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1338 self.window.pipeline_id(),
1339 title,
1340 ));
1341 }
1342 }
1343 }
1344
1345 fn title(&self) -> Option<DOMString> {
1349 let title = self.GetDocumentElement().and_then(|root| {
1350 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1351 root.upcast::<Node>()
1353 .child_elements()
1354 .find(|node| {
1355 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1356 })
1357 .map(DomRoot::upcast::<Node>)
1358 } else {
1359 root.upcast::<Node>()
1361 .traverse_preorder(ShadowIncluding::No)
1362 .find(|node| node.is::<HTMLTitleElement>())
1363 }
1364 });
1365
1366 title.map(|title| {
1367 let value = title.child_text_content();
1369 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1370 })
1371 }
1372
1373 pub(crate) fn send_title_to_embedder(&self) {
1375 let window = self.window();
1376 if window.is_top_level() {
1377 let title = self.title().map(String::from);
1378 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1379 }
1380 }
1381
1382 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1383 let window = self.window();
1384 window.send_to_embedder(msg);
1385 }
1386
1387 pub(crate) fn dirty_all_nodes(&self) {
1388 let root = match self.GetDocumentElement() {
1389 Some(root) => root,
1390 None => return,
1391 };
1392 for node in root
1393 .upcast::<Node>()
1394 .traverse_preorder(ShadowIncluding::Yes)
1395 {
1396 node.dirty(NodeDamage::Other)
1397 }
1398 }
1399
1400 pub(crate) fn run_the_scroll_steps(&self, cx: &mut js::context::JSContext) {
1402 let boxes_that_were_scrolled: Vec<_> = self
1410 .pending_scroll_events
1411 .borrow()
1412 .iter()
1413 .filter_map(|pending_event| {
1414 if &*pending_event.event == "scroll" {
1415 Some(pending_event.target.as_rooted())
1416 } else {
1417 None
1418 }
1419 })
1420 .collect();
1421
1422 for target in boxes_that_were_scrolled.into_iter() {
1423 let Some(element) = target.downcast::<Element>() else {
1429 continue;
1430 };
1431 let document = element.owner_document();
1432
1433 let mut pending_scroll_events = document.pending_scroll_events.borrow_mut();
1440 let event = "scrollend".into();
1441 if pending_scroll_events
1442 .iter()
1443 .any(|existing| existing.equivalent(&target, &event))
1444 {
1445 continue;
1446 }
1447
1448 pending_scroll_events.push(PendingScrollEvent {
1450 target: target.as_traced(),
1451 event: "scrollend".into(),
1452 });
1453 }
1454
1455 rooted_vec!(let pending_scroll_events <- self.pending_scroll_events.take().into_iter());
1458 for pending_event in pending_scroll_events.iter() {
1459 let event = pending_event.event.clone();
1462 if pending_event.target.is::<Document>() {
1463 pending_event.target.fire_bubbling_event(cx, event);
1464 }
1465 else {
1474 pending_event.target.fire_event(cx, event);
1475 }
1476 }
1477
1478 }
1481
1482 pub(crate) fn handle_viewport_scroll_event(&self) {
1487 self.finish_handle_scroll_event(self.upcast());
1499 }
1500
1501 pub(crate) fn finish_handle_scroll_event(&self, event_target: &EventTarget) {
1506 let event = "scroll".into();
1509 if self
1510 .pending_scroll_events
1511 .borrow()
1512 .iter()
1513 .any(|existing| existing.equivalent(event_target, &event))
1514 {
1515 return;
1516 }
1517
1518 self.pending_scroll_events
1521 .borrow_mut()
1522 .push(PendingScrollEvent {
1523 target: Dom::from_ref(event_target),
1524 event: "scroll".into(),
1525 });
1526 }
1527
1528 pub(crate) fn node_from_nodes_and_strings(
1530 &self,
1531 cx: &mut js::context::JSContext,
1532 mut nodes: Vec<NodeOrString>,
1533 ) -> Fallible<DomRoot<Node>> {
1534 if nodes.len() == 1 {
1535 Ok(match nodes.pop().unwrap() {
1536 NodeOrString::Node(node) => node,
1537 NodeOrString::String(string) => DomRoot::upcast(self.CreateTextNode(cx, string)),
1538 })
1539 } else {
1540 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(cx));
1541 for node in nodes {
1542 match node {
1543 NodeOrString::Node(node) => {
1544 fragment.AppendChild(cx, &node)?;
1545 },
1546 NodeOrString::String(string) => {
1547 let node = DomRoot::upcast::<Node>(self.CreateTextNode(cx, string));
1548 fragment.AppendChild(cx, &node).unwrap();
1551 },
1552 }
1553 }
1554 Ok(fragment)
1555 }
1556 }
1557
1558 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1559 match self.GetBody() {
1560 Some(ref body) if body.is_body_element() => {
1561 body.upcast::<Element>().get_string_attribute(local_name)
1562 },
1563 _ => DOMString::new(),
1564 }
1565 }
1566
1567 pub(crate) fn set_body_attribute(
1568 &self,
1569 cx: &mut js::context::JSContext,
1570 local_name: &LocalName,
1571 value: DOMString,
1572 ) {
1573 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1574 let body = body.upcast::<Element>();
1575 let value = body.parse_attribute(&ns!(), local_name, value);
1576 body.set_attribute(cx, local_name, value);
1577 }
1578 }
1579
1580 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1581 self.current_script.set(script);
1582 }
1583
1584 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1585 self.script_blocking_stylesheets_count.get()
1586 }
1587
1588 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1589 let count_cell = &self.script_blocking_stylesheets_count;
1590 count_cell.set(count_cell.get() + 1);
1591 }
1592
1593 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1594 let count_cell = &self.script_blocking_stylesheets_count;
1595 assert!(count_cell.get() > 0);
1596 count_cell.set(count_cell.get() - 1);
1597 }
1598
1599 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1600 self.render_blocking_element_count.get()
1601 }
1602
1603 pub(crate) fn increment_render_blocking_element_count(&self) {
1605 assert!(self.allows_adding_render_blocking_elements());
1612 let count_cell = &self.render_blocking_element_count;
1613 count_cell.set(count_cell.get() + 1);
1614 }
1615
1616 pub(crate) fn decrement_render_blocking_element_count(&self) {
1618 let count_cell = &self.render_blocking_element_count;
1624 assert!(count_cell.get() > 0);
1625 count_cell.set(count_cell.get() - 1);
1626 }
1627
1628 pub(crate) fn allows_adding_render_blocking_elements(&self) -> bool {
1630 self.is_html_document && self.GetBody().is_none()
1633 }
1634
1635 pub(crate) fn is_render_blocked(&self) -> bool {
1637 self.render_blocking_element_count() > 0
1641 }
1646
1647 pub(crate) fn invalidate_stylesheets(&self) {
1648 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1649
1650 if let Some(element) = self.GetDocumentElement() {
1654 element.upcast::<Node>().dirty(NodeDamage::Style);
1655 }
1656 }
1657
1658 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1661 !self.animation_frame_list.borrow().is_empty()
1662 }
1663
1664 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1666 let ident = self.animation_frame_ident.get() + 1;
1667 self.animation_frame_ident.set(ident);
1668
1669 let had_animation_frame_callbacks;
1670 {
1671 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1672 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1673 animation_frame_list.push_back((ident, Some(callback)));
1674 }
1675
1676 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1682 self.window().send_to_constellation(
1683 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1684 AnimationState::AnimationCallbacksPresent,
1685 ),
1686 );
1687 }
1688
1689 ident
1690 }
1691
1692 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1694 let mut list = self.animation_frame_list.borrow_mut();
1695 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1696 pair.1 = None;
1697 }
1698 }
1699
1700 pub(crate) fn run_the_animation_frame_callbacks(&self, cx: &mut CurrentRealm) {
1702 self.running_animation_callbacks.set(true);
1703 let timing = self.global().performance().Now();
1704
1705 let num_callbacks = self.animation_frame_list.borrow().len();
1706 for _ in 0..num_callbacks {
1707 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1708 if let Some(callback) = maybe_callback {
1709 callback.call(cx, self, *timing);
1710 }
1711 }
1712 self.running_animation_callbacks.set(false);
1713
1714 if self.animation_frame_list.borrow().is_empty() {
1715 self.window().send_to_constellation(
1716 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1717 AnimationState::NoAnimationCallbacksPresent,
1718 ),
1719 );
1720 }
1721 }
1722
1723 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1724 self.policy_container.borrow()
1725 }
1726
1727 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1728 *self.policy_container.borrow_mut() = policy_container;
1729 }
1730
1731 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1732 self.policy_container.borrow_mut().set_csp_list(csp_list);
1733 }
1734
1735 pub(crate) fn enforce_csp_policy(&self, policy: CspPolicy) {
1737 let mut csp_list = self.get_csp_list().clone().unwrap_or(CspList(vec![]));
1739 csp_list.push(policy);
1740 self.policy_container
1741 .borrow_mut()
1742 .set_csp_list(Some(csp_list));
1743 }
1744
1745 pub(crate) fn get_csp_list(&self) -> Ref<'_, Option<CspList>> {
1746 Ref::map(self.policy_container.borrow(), |policy_container| {
1747 &policy_container.csp_list
1748 })
1749 }
1750
1751 pub(crate) fn preloaded_resources(&self) -> std::cell::Ref<'_, PreloadedResources> {
1752 self.preloaded_resources.borrow()
1753 }
1754
1755 pub(crate) fn insert_preloaded_resource(&self, key: PreloadKey, preload_id: PreloadId) {
1756 self.preloaded_resources
1757 .borrow_mut()
1758 .insert(key, preload_id);
1759 }
1760
1761 pub(crate) fn fetch<Listener: FetchResponseListener>(
1762 &self,
1763 load: LoadType,
1764 mut request: RequestBuilder,
1765 listener: Listener,
1766 ) {
1767 request = request
1768 .insecure_requests_policy(self.insecure_requests_policy())
1769 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1770 let callback = NetworkListener {
1771 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1772 task_source: self
1773 .owner_global()
1774 .task_manager()
1775 .networking_task_source()
1776 .into(),
1777 }
1778 .into_callback();
1779 self.loader_mut()
1780 .fetch_async_with_callback(load, request, callback);
1781 }
1782
1783 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1784 &self,
1785 mut request: RequestBuilder,
1786 listener: Listener,
1787 ) {
1788 request = request
1789 .insecure_requests_policy(self.insecure_requests_policy())
1790 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1791 let callback = NetworkListener {
1792 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1793 task_source: self
1794 .owner_global()
1795 .task_manager()
1796 .networking_task_source()
1797 .into(),
1798 }
1799 .into_callback();
1800 self.loader_mut().fetch_async_background(request, callback);
1801 }
1802
1803 fn deferred_fetch_control_document(&self) -> DomRoot<Document> {
1805 match self.window().window_proxy().frame_element() {
1806 None => DomRoot::from_ref(self),
1809 Some(container) => container.owner_document().deferred_fetch_control_document(),
1811 }
1812 }
1813
1814 pub(crate) fn available_deferred_fetch_quota(&self, origin: ImmutableOrigin) -> isize {
1816 let control_document = self.deferred_fetch_control_document();
1818 let navigable = control_document.window();
1820 let is_top_level = navigable.is_top_level();
1823 let deferred_fetch_allowed = true;
1827 let deferred_fetch_minimal_allowed = true;
1831 let mut quota = match is_top_level {
1833 true if !deferred_fetch_allowed => 0,
1835 true if !deferred_fetch_minimal_allowed => 640 * 1024,
1837 true => 512 * 1024,
1839 _ if deferred_fetch_allowed => 0,
1843 _ if deferred_fetch_minimal_allowed => 8 * 1024,
1847 _ => 0,
1849 } as isize;
1850 let mut quota_for_request_origin = 64 * 1024_isize;
1852 for deferred_fetch in navigable.as_global_scope().deferred_fetches() {
1861 if deferred_fetch.invoke_state.get() != DeferredFetchRecordInvokeState::Pending {
1863 continue;
1864 }
1865 let request_length = deferred_fetch.request.total_request_length();
1867 quota -= request_length as isize;
1869 if deferred_fetch.request.url().origin() == origin {
1872 quota_for_request_origin -= request_length as isize;
1873 }
1874 }
1875 if quota <= 0 {
1877 return 0;
1878 }
1879 if quota < quota_for_request_origin {
1881 return quota;
1882 }
1883 quota_for_request_origin
1885 }
1886
1887 pub(crate) fn update_document_for_history_step_application(
1889 &self,
1890 old_url: &ServoUrl,
1891 new_url: &ServoUrl,
1892 ) {
1893 if old_url.as_url()[Position::BeforeFragment..] !=
1923 new_url.as_url()[Position::BeforeFragment..]
1924 {
1925 let window = Trusted::new(self.owner_window().deref());
1926 let old_url = old_url.to_string();
1927 let new_url = new_url.to_string();
1928 self.owner_global()
1929 .task_manager()
1930 .dom_manipulation_task_source()
1931 .queue(task!(hashchange_event: move |cx| {
1932 let window = window.root();
1933 HashChangeEvent::new(
1934 &window,
1935 atom!("hashchange"),
1936 false,
1937 false,
1938 old_url,
1939 new_url,
1940 CanGc::from_cx(cx),
1941 )
1942 .upcast::<Event>()
1943 .fire(window.upcast(), CanGc::from_cx(cx));
1944 }));
1945 }
1946 }
1947
1948 pub(crate) fn finish_load(&self, load: LoadType, cx: &mut js::context::JSContext) {
1951 debug!("Document got finish_load: {:?}", load);
1953 self.loader.borrow_mut().finish_load(&load);
1954
1955 match load {
1956 LoadType::Stylesheet(_) => {
1957 self.process_pending_parsing_blocking_script(cx);
1960
1961 self.process_deferred_scripts(cx);
1963 },
1964 LoadType::PageSource(_) => {
1965 if self.has_browsing_context && self.is_fully_active() {
1968 self.window().allow_layout_if_necessary();
1969 }
1970
1971 self.process_deferred_scripts(cx);
1976 },
1977 _ => {},
1978 }
1979
1980 let loader = self.loader.borrow();
1987
1988 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1990 update_with_current_instant(&self.top_level_dom_complete);
1991 }
1992
1993 if loader.is_blocked() || loader.events_inhibited() {
1994 return;
1996 }
1997
1998 ScriptThread::mark_document_with_no_blocked_loads(self);
1999 }
2000
2001 pub(crate) fn check_if_unloading_is_cancelled(
2003 &self,
2004 cx: &mut js::context::JSContext,
2005 recursive_flag: bool,
2006 ) -> bool {
2007 self.incr_ignore_opens_during_unload_counter();
2010 let beforeunload_event = BeforeUnloadEvent::new(
2012 &self.window,
2013 atom!("beforeunload"),
2014 EventBubbles::Bubbles,
2015 EventCancelable::Cancelable,
2016 CanGc::from_cx(cx),
2017 );
2018 let event = beforeunload_event.upcast::<Event>();
2019 event.set_trusted(true);
2020 let event_target = self.window.upcast::<EventTarget>();
2021 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2022 self.window.dispatch_event_with_target_override(cx, event);
2023 if has_listeners {
2026 self.salvageable.set(false);
2027 }
2028 let mut can_unload = true;
2029 let default_prevented = event.DefaultPrevented();
2031 let return_value_not_empty = !event
2032 .downcast::<BeforeUnloadEvent>()
2033 .unwrap()
2034 .ReturnValue()
2035 .is_empty();
2036 if default_prevented || return_value_not_empty {
2037 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2038 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2039 self.send_to_embedder(msg);
2040 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2041 }
2042 if !recursive_flag {
2044 let iframes: Vec<_> = self.iframes().iter().collect();
2047 for iframe in &iframes {
2048 let document = iframe.owner_document();
2050 can_unload = document.check_if_unloading_is_cancelled(cx, true);
2051 if !document.salvageable() {
2052 self.salvageable.set(false);
2053 }
2054 if !can_unload {
2055 break;
2056 }
2057 }
2058 }
2059 self.decr_ignore_opens_during_unload_counter();
2061 can_unload
2062 }
2063
2064 pub(crate) fn unload(&self, cx: &mut js::context::JSContext, recursive_flag: bool) {
2066 self.incr_ignore_opens_during_unload_counter();
2069 if self.page_showing.get() {
2071 self.page_showing.set(false);
2073 let event = PageTransitionEvent::new(
2076 &self.window,
2077 atom!("pagehide"),
2078 false, false, self.salvageable.get(), CanGc::from_cx(cx),
2082 );
2083 let event = event.upcast::<Event>();
2084 event.set_trusted(true);
2085 self.window.dispatch_event_with_target_override(cx, event);
2086 self.update_visibility_state(cx, DocumentVisibilityState::Hidden);
2088 }
2089 if !self.fired_unload.get() {
2091 let event = Event::new(
2092 self.window.upcast(),
2093 atom!("unload"),
2094 EventBubbles::Bubbles,
2095 EventCancelable::Cancelable,
2096 CanGc::from_cx(cx),
2097 );
2098 event.set_trusted(true);
2099 let event_target = self.window.upcast::<EventTarget>();
2100 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2101 self.window.dispatch_event_with_target_override(cx, &event);
2102 self.fired_unload.set(true);
2103 if has_listeners {
2105 self.salvageable.set(false);
2106 }
2107 }
2108 if !recursive_flag {
2112 let iframes: Vec<_> = self.iframes().iter().collect();
2115 for iframe in &iframes {
2116 let document = iframe.owner_document();
2118 document.unload(cx, true);
2119 if !document.salvageable() {
2120 self.salvageable.set(false);
2121 }
2122 }
2123 }
2124
2125 self.unloading_cleanup_steps();
2127
2128 self.window.as_global_scope().clean_up_all_file_resources();
2130
2131 self.decr_ignore_opens_during_unload_counter();
2133
2134 }
2137
2138 fn completely_finish_loading(&self) {
2140 self.completely_loaded.set(true);
2145 self.notify_constellation_load();
2154
2155 if let Some(DeclarativeRefresh::PendingLoad { url, time }) =
2164 &*self.declarative_refresh.borrow()
2165 {
2166 self.window.as_global_scope().schedule_callback(
2167 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2168 window: DomRoot::from_ref(self.window()),
2169 url: url.clone(),
2170 }),
2171 Duration::from_secs(*time),
2172 );
2173 }
2174 }
2175
2176 pub(crate) fn maybe_queue_document_completion(&self) {
2178 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2180 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2181 None => false,
2182 };
2183
2184 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2189 !self.is_fully_active() ||
2190 is_in_delaying_load_events_mode ||
2191 self.loader.borrow().events_inhibited();
2194
2195 if not_ready_for_load {
2196 return;
2198 }
2199
2200 self.loader.borrow_mut().inhibit_events();
2201
2202 debug!("Document loads are complete.");
2207 let document = Trusted::new(self);
2208 self.owner_global()
2209 .task_manager()
2210 .dom_manipulation_task_source()
2211 .queue(task!(fire_load_event: move |cx| {
2212 let document = document.root();
2213 let window = document.window();
2215 if !window.is_alive() {
2216 return;
2217 }
2218
2219 document.set_ready_state(cx,DocumentReadyState::Complete);
2221
2222 if document.browsing_context().is_none() {
2224 return;
2225 }
2226
2227 update_with_current_instant(&document.load_event_start);
2229
2230 let load_event = Event::new(
2232 window.upcast(),
2233 atom!("load"),
2234 EventBubbles::DoesNotBubble,
2235 EventCancelable::NotCancelable,
2236 CanGc::from_cx(cx),
2237 );
2238 load_event.set_trusted(true);
2239 debug!("About to dispatch load for {:?}", document.url());
2240 window.dispatch_event_with_target_override(cx, &load_event);
2241
2242 update_with_current_instant(&document.load_event_end);
2252
2253 document.page_showing.set(true);
2258
2259 let page_show_event = PageTransitionEvent::new(
2261 window,
2262 atom!("pageshow"),
2263 false, false, false, CanGc::from_cx(cx),
2267 );
2268 let page_show_event = page_show_event.upcast::<Event>();
2269 page_show_event.set_trusted(true);
2270 page_show_event.fire(window.upcast(), CanGc::from_cx(cx));
2271
2272 document.completely_finish_loading();
2274
2275 if let Some(fragment) = document.url().fragment() {
2279 document.scroll_to_the_fragment(cx, fragment);
2280 }
2281 }));
2282
2283 #[cfg(feature = "webxr")]
2298 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2299 self.window.Navigator().Xr().dispatch_sessionavailable();
2300 }
2301 }
2302
2303 pub(crate) fn completely_loaded(&self) -> bool {
2304 self.completely_loaded.get()
2305 }
2306
2307 pub(crate) fn set_pending_parsing_blocking_script(
2309 &self,
2310 script: &HTMLScriptElement,
2311 load: Option<ScriptResult>,
2312 ) {
2313 assert!(!self.has_pending_parsing_blocking_script());
2314 *self.pending_parsing_blocking_script.borrow_mut() =
2315 Some(PendingScript::new_with_load(script, load));
2316 }
2317
2318 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2320 self.pending_parsing_blocking_script.borrow().is_some()
2321 }
2322
2323 pub(crate) fn pending_parsing_blocking_script_loaded(
2325 &self,
2326 element: &HTMLScriptElement,
2327 result: ScriptResult,
2328 cx: &mut js::context::JSContext,
2329 ) {
2330 {
2331 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2332 let entry = blocking_script.as_mut().unwrap();
2333 assert!(&*entry.element == element);
2334 entry.loaded(result);
2335 }
2336 self.process_pending_parsing_blocking_script(cx);
2337 }
2338
2339 fn process_pending_parsing_blocking_script(&self, cx: &mut js::context::JSContext) {
2340 if self.script_blocking_stylesheets_count.get() > 0 {
2341 return;
2342 }
2343 let pair = self
2344 .pending_parsing_blocking_script
2345 .borrow_mut()
2346 .as_mut()
2347 .and_then(PendingScript::take_result);
2348 if let Some((element, result)) = pair {
2349 *self.pending_parsing_blocking_script.borrow_mut() = None;
2350 self.get_current_parser()
2351 .unwrap()
2352 .resume_with_pending_parsing_blocking_script(&element, result, cx);
2353 }
2354 }
2355
2356 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2358 self.asap_scripts_set
2359 .borrow_mut()
2360 .push(Dom::from_ref(script));
2361 }
2362
2363 pub(crate) fn asap_script_loaded(
2366 &self,
2367 cx: &mut js::context::JSContext,
2368 element: &HTMLScriptElement,
2369 result: ScriptResult,
2370 ) {
2371 {
2372 let mut scripts = self.asap_scripts_set.borrow_mut();
2373 let idx = scripts
2374 .iter()
2375 .position(|entry| &**entry == element)
2376 .unwrap();
2377 scripts.swap_remove(idx);
2378 }
2379 element.execute(cx, result);
2380 }
2381
2382 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2384 self.asap_in_order_scripts_list.push(script);
2385 }
2386
2387 pub(crate) fn asap_in_order_script_loaded(
2390 &self,
2391 cx: &mut js::context::JSContext,
2392 element: &HTMLScriptElement,
2393 result: ScriptResult,
2394 ) {
2395 self.asap_in_order_scripts_list.loaded(element, result);
2396 while let Some((element, result)) = self
2397 .asap_in_order_scripts_list
2398 .take_next_ready_to_be_executed()
2399 {
2400 element.execute(cx, result);
2401 }
2402 }
2403
2404 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2406 self.deferred_scripts.push(script);
2407 }
2408
2409 pub(crate) fn deferred_script_loaded(
2412 &self,
2413 cx: &mut js::context::JSContext,
2414 element: &HTMLScriptElement,
2415 result: ScriptResult,
2416 ) {
2417 self.deferred_scripts.loaded(element, result);
2418 self.process_deferred_scripts(cx);
2419 }
2420
2421 fn process_deferred_scripts(&self, cx: &mut js::context::JSContext) {
2423 if self.ready_state.get() != DocumentReadyState::Interactive {
2424 return;
2425 }
2426 loop {
2428 if self.script_blocking_stylesheets_count.get() > 0 {
2429 return;
2430 }
2431 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2432 {
2433 element.execute(cx, result);
2434 } else {
2435 break;
2436 }
2437 }
2438 if self.deferred_scripts.is_empty() {
2439 self.maybe_dispatch_dom_content_loaded();
2441 }
2442 }
2443
2444 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2446 if self.domcontentloaded_dispatched.get() {
2447 return;
2448 }
2449 self.domcontentloaded_dispatched.set(true);
2450 assert_ne!(
2451 self.ReadyState(),
2452 DocumentReadyState::Complete,
2453 "Complete before DOMContentLoaded?"
2454 );
2455
2456 let document = Trusted::new(self);
2459 self.owner_global()
2460 .task_manager()
2461 .dom_manipulation_task_source()
2462 .queue(task!(fire_dom_content_loaded_event: move |cx| {
2463 let document = document.root();
2464
2465 update_with_current_instant(&document.dom_content_loaded_event_start);
2468
2469 document.upcast::<EventTarget>().fire_bubbling_event(cx, atom!("DOMContentLoaded"));
2472
2473 update_with_current_instant(&document.dom_content_loaded_event_end);
2476
2477 }));
2484
2485 self.interactive_time
2487 .borrow()
2488 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2489
2490 }
2493
2494 pub(crate) fn destroy_document_and_its_descendants(&self, cx: &mut js::context::JSContext) {
2496 if !self.is_fully_active() {
2498 self.salvageable.set(false);
2503 }
2507 for exited_iframe in self.iframes().iter() {
2520 debug!("Destroying nested iframe document");
2521 exited_iframe.destroy_document_and_its_descendants(cx);
2522 }
2523 self.destroy(cx);
2528 }
2531
2532 pub(crate) fn destroy(&self, cx: &mut js::context::JSContext) {
2534 let exited_window = self.window();
2535 self.abort(cx);
2537 self.salvageable.set(false);
2539 self.unloading_cleanup_steps();
2549
2550 exited_window
2553 .as_global_scope()
2554 .task_manager()
2555 .cancel_all_tasks_and_ignore_future_tasks();
2556
2557 exited_window.discard_browsing_context();
2559
2560 }
2572
2573 fn terminate_fetch_group(&self) -> bool {
2575 let mut load_cancellers = self.loader.borrow_mut().cancel_all_loads();
2576
2577 for canceller in &mut load_cancellers {
2581 if !canceller.keep_alive() {
2582 canceller.terminate();
2583 }
2584 }
2585 self.owner_global().process_deferred_fetches();
2587
2588 !load_cancellers.is_empty()
2589 }
2590
2591 pub(crate) fn abort(&self, cx: &mut js::context::JSContext) {
2593 self.loader.borrow_mut().inhibit_events();
2595
2596 for iframe in self.iframes().iter() {
2598 if let Some(document) = iframe.GetContentDocument() {
2599 document.abort(cx);
2600 }
2601 }
2602
2603 self.script_blocking_stylesheets_count.set(0);
2609 *self.pending_parsing_blocking_script.borrow_mut() = None;
2610 *self.asap_scripts_set.borrow_mut() = vec![];
2611 self.asap_in_order_scripts_list.clear();
2612 self.deferred_scripts.clear();
2613 let loads_cancelled = self.terminate_fetch_group();
2614 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2615 if loads_cancelled || event_sources_canceled {
2616 self.salvageable.set(false);
2618 };
2619
2620 self.owner_global()
2625 .task_manager()
2626 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2627
2628 if let Some(parser) = self.get_current_parser() {
2633 self.active_parser_was_aborted.set(true);
2635 parser.abort(cx);
2637 self.salvageable.set(false);
2639 }
2640 }
2641
2642 pub(crate) fn notify_constellation_load(&self) {
2643 self.window()
2644 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2645 }
2646
2647 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2648 self.current_parser.set(script);
2649 }
2650
2651 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2652 self.current_parser.get()
2653 }
2654
2655 pub(crate) fn get_current_parser_line(&self) -> u32 {
2656 self.get_current_parser()
2657 .map(|parser| parser.get_current_line())
2658 .unwrap_or(0)
2659 }
2660
2661 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2664 self.iframes.borrow_mut().validate(self);
2665 self.iframes.borrow()
2666 }
2667
2668 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2671 self.iframes.borrow_mut().validate(self);
2672 self.iframes.borrow_mut()
2673 }
2674
2675 pub(crate) fn invalidate_iframes_collection(&self) {
2676 self.iframes.borrow_mut().invalidate();
2677 }
2678
2679 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2680 self.dom_interactive.get()
2681 }
2682
2683 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2684 self.interactive_time
2685 .borrow_mut()
2686 .set_navigation_start(navigation_start);
2687 }
2688
2689 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2690 self.interactive_time.borrow()
2691 }
2692
2693 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2694 self.get_interactive_metrics().get_tti().is_some()
2695 }
2696
2697 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2698 self.dom_content_loaded_event_start.get()
2699 }
2700
2701 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2702 self.dom_content_loaded_event_end.get()
2703 }
2704
2705 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2706 self.dom_complete.get()
2707 }
2708
2709 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2710 self.top_level_dom_complete.get()
2711 }
2712
2713 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2714 self.load_event_start.get()
2715 }
2716
2717 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2718 self.load_event_end.get()
2719 }
2720
2721 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2722 self.unload_event_start.get()
2723 }
2724
2725 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2726 self.unload_event_end.get()
2727 }
2728
2729 pub(crate) fn start_tti(&self) {
2730 if self.get_interactive_metrics().needs_tti() {
2731 self.tti_window.borrow_mut().start_window();
2732 }
2733 }
2734
2735 pub(crate) fn record_tti_if_necessary(&self) {
2739 if self.has_recorded_tti_metric() {
2740 return;
2741 }
2742 if self.tti_window.borrow().needs_check() {
2743 self.get_interactive_metrics()
2744 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2745 self.tti_window.borrow().get_start(),
2746 ));
2747 }
2748 }
2749
2750 pub(crate) fn is_cookie_averse(&self) -> bool {
2752 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2753 }
2754
2755 pub(crate) fn lookup_custom_element_definition(
2757 &self,
2758 namespace: &Namespace,
2759 local_name: &LocalName,
2760 is: Option<&LocalName>,
2761 ) -> Option<Rc<CustomElementDefinition>> {
2762 if *namespace != ns!(html) {
2764 return None;
2765 }
2766
2767 if !self.has_browsing_context {
2769 return None;
2770 }
2771
2772 let registry = self.window.CustomElements();
2774
2775 registry.lookup_definition(local_name, is)
2776 }
2777
2778 pub(crate) fn custom_element_registry(&self) -> DomRoot<CustomElementRegistry> {
2780 self.window.CustomElements()
2781 }
2782
2783 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2784 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2785 self.throw_on_dynamic_markup_insertion_counter
2786 .set(counter + 1);
2787 }
2788
2789 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2790 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2791 self.throw_on_dynamic_markup_insertion_counter
2792 .set(counter - 1);
2793 }
2794
2795 pub(crate) fn react_to_environment_changes(&self) {
2796 for image in self.responsive_images.borrow().iter() {
2797 image.react_to_environment_changes();
2798 }
2799 }
2800
2801 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2802 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2803 }
2804
2805 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2806 let index = self
2807 .responsive_images
2808 .borrow()
2809 .iter()
2810 .position(|x| **x == *img);
2811 if let Some(i) = index {
2812 self.responsive_images.borrow_mut().remove(i);
2813 }
2814 }
2815
2816 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
2817 let did_have_these_media_controls = self
2818 .media_controls
2819 .borrow_mut()
2820 .insert(id.to_string(), Dom::from_ref(controls))
2821 .is_some();
2822 debug_assert!(
2823 !did_have_these_media_controls,
2824 "Trying to register known media controls"
2825 );
2826 }
2827
2828 pub(crate) fn unregister_media_controls(&self, id: &str) {
2829 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2830 debug_assert!(
2831 did_have_these_media_controls,
2832 "Trying to unregister unknown media controls"
2833 );
2834 }
2835
2836 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
2837 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
2838 if dirty_canvases
2839 .iter()
2840 .any(|dirty_canvas| dirty_canvas == canvas)
2841 {
2842 return;
2843 }
2844 dirty_canvases.push(canvas.clone());
2845 }
2846
2847 pub(crate) fn needs_rendering_update(&self) -> bool {
2851 if !self.is_fully_active() {
2852 return false;
2853 }
2854 if !self.window().layout_blocked() &&
2855 (!self.restyle_reason().is_empty() ||
2856 self.window().layout().needs_new_display_list() ||
2857 self.window().layout().needs_accessibility_update())
2858 {
2859 return true;
2860 }
2861 if !self.rendering_update_reasons.get().is_empty() {
2862 return true;
2863 }
2864 if self.event_handler.has_pending_input_events() {
2865 return true;
2866 }
2867 if self.has_pending_scroll_events() {
2868 return true;
2869 }
2870 if self.window().has_unhandled_resize_event() {
2871 return true;
2872 }
2873 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
2874 {
2875 return true;
2876 }
2877
2878 false
2879 }
2880
2881 pub(crate) fn update_the_rendering(&self) -> (ReflowPhasesRun, ReflowStatistics) {
2889 assert!(!self.is_render_blocked());
2890
2891 let mut phases = ReflowPhasesRun::empty();
2892 if self.has_pending_animated_image_update.get() {
2893 self.image_animation_manager
2894 .borrow()
2895 .update_active_frames(&self.window, self.current_animation_timeline_value());
2896 self.has_pending_animated_image_update.set(false);
2897 phases.insert(ReflowPhasesRun::UpdatedImageData);
2898 }
2899
2900 self.current_rendering_epoch
2901 .set(self.current_rendering_epoch.get().next());
2902 let current_rendering_epoch = self.current_rendering_epoch.get();
2903
2904 let image_keys: Vec<_> = self
2906 .dirty_canvases
2907 .borrow_mut()
2908 .drain(..)
2909 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
2910 .collect();
2911
2912 let pipeline_id = self.window().pipeline_id();
2915 if !image_keys.is_empty() {
2916 phases.insert(ReflowPhasesRun::UpdatedImageData);
2917 self.waiting_on_canvas_image_updates.set(true);
2918 self.window().paint_api().delay_new_frame_for_canvas(
2919 self.webview_id(),
2920 self.window().pipeline_id(),
2921 current_rendering_epoch,
2922 image_keys,
2923 );
2924 }
2925
2926 let (reflow_phases, statistics) = self.window().reflow(ReflowGoal::UpdateTheRendering);
2927 let phases = phases.union(reflow_phases);
2928
2929 self.window().paint_api().update_epoch(
2930 self.webview_id(),
2931 pipeline_id,
2932 current_rendering_epoch,
2933 );
2934
2935 (phases, statistics)
2936 }
2937
2938 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2939 self.waiting_on_canvas_image_updates.set(false);
2940 }
2941
2942 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2943 self.waiting_on_canvas_image_updates.get()
2944 }
2945
2946 pub(crate) fn maybe_fulfill_font_ready_promise(&self, cx: &mut js::context::JSContext) -> bool {
2956 if !self.is_fully_active() {
2957 return false;
2958 }
2959
2960 let fonts = self.Fonts(cx);
2961 if !fonts.waiting_to_fullfill_promise() {
2962 return false;
2963 }
2964 if self.window().font_context().web_fonts_still_loading() != 0 {
2965 return false;
2966 }
2967 if self.ReadyState() != DocumentReadyState::Complete {
2968 return false;
2969 }
2970 if !self.restyle_reason().is_empty() {
2971 return false;
2972 }
2973 if !self.rendering_update_reasons.get().is_empty() {
2974 return false;
2975 }
2976
2977 let result = fonts.fulfill_ready_promise_if_needed(cx);
2978
2979 if result {
2983 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
2984 }
2985
2986 result
2987 }
2988
2989 pub(crate) fn id_map(
2990 &self,
2991 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2992 self.id_map.borrow()
2993 }
2994
2995 pub(crate) fn name_map(
2996 &self,
2997 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2998 self.name_map.borrow()
2999 }
3000
3001 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
3003 self.resize_observers
3004 .borrow_mut()
3005 .push(Dom::from_ref(resize_observer));
3006 }
3007
3008 pub(crate) fn has_resize_observers(&self) -> bool {
3010 !self.resize_observers.borrow().is_empty()
3011 }
3012
3013 pub(crate) fn gather_active_resize_observations_at_depth(
3016 &self,
3017 depth: &ResizeObservationDepth,
3018 ) -> bool {
3019 let mut has_active_resize_observations = false;
3020 for observer in self.resize_observers.borrow_mut().iter_mut() {
3021 observer.gather_active_resize_observations_at_depth(
3022 depth,
3023 &mut has_active_resize_observations,
3024 );
3025 }
3026 has_active_resize_observations
3027 }
3028
3029 #[expect(clippy::redundant_iter_cloned)]
3031 pub(crate) fn broadcast_active_resize_observations(
3032 &self,
3033 cx: &mut js::context::JSContext,
3034 ) -> ResizeObservationDepth {
3035 let mut shallowest = ResizeObservationDepth::max();
3036 let iterator: Vec<DomRoot<ResizeObserver>> = self
3040 .resize_observers
3041 .borrow()
3042 .iter()
3043 .cloned()
3044 .map(|obs| DomRoot::from_ref(&*obs))
3045 .collect();
3046 for observer in iterator {
3047 observer.broadcast_active_resize_observations(cx, &mut shallowest);
3048 }
3049 shallowest
3050 }
3051
3052 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
3054 self.resize_observers
3055 .borrow()
3056 .iter()
3057 .any(|observer| observer.has_skipped_resize_observations())
3058 }
3059
3060 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
3062 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
3063 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
3064 ..Default::default()
3065 };
3066 self.window
3067 .as_global_scope()
3068 .report_an_error(error_info, HandleValue::null(), can_gc);
3069 }
3070
3071 pub(crate) fn status_code(&self) -> Option<u16> {
3072 self.status_code
3073 }
3074
3075 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
3077 let encoding = self.encoding.get();
3083
3084 let base_url = self.base_url();
3090
3091 url::Url::options()
3093 .base_url(Some(base_url.as_url()))
3094 .encoding_override(Some(&|input| {
3095 servo_url::encoding::encode_as_url_query_string(input, encoding)
3096 }))
3097 .parse(url)
3098 .map(ServoUrl::from)
3099 }
3100
3101 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3103 if !self.has_browsing_context {
3105 return false;
3106 }
3107
3108 if !self.is_fully_active() {
3110 return false;
3111 }
3112
3113 true
3119 }
3120
3121 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3124 self.intersection_observers
3125 .borrow_mut()
3126 .push(Dom::from_ref(intersection_observer));
3127 }
3128
3129 pub(crate) fn remove_intersection_observer(
3133 &self,
3134 intersection_observer: &IntersectionObserver,
3135 ) {
3136 self.intersection_observers
3137 .borrow_mut()
3138 .retain(|observer| *observer != intersection_observer)
3139 }
3140
3141 pub(crate) fn update_intersection_observer_steps(
3143 &self,
3144 cx: &mut js::context::JSContext,
3145 time: CrossProcessInstant,
3146 ) {
3147 for intersection_observer in &*self.intersection_observers.borrow() {
3149 self.update_single_intersection_observer_steps(cx, intersection_observer, time);
3150 }
3151 }
3152
3153 fn update_single_intersection_observer_steps(
3155 &self,
3156 cx: &mut js::context::JSContext,
3157 intersection_observer: &IntersectionObserver,
3158 time: CrossProcessInstant,
3159 ) {
3160 let root_bounds = intersection_observer.root_intersection_rectangle();
3163
3164 intersection_observer.update_intersection_observations_steps(cx, self, time, root_bounds);
3168 }
3169
3170 pub(crate) fn notify_intersection_observers(&self, cx: &mut js::context::JSContext) {
3172 self.intersection_observer_task_queued.set(false);
3175
3176 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3181
3182 for intersection_observer in notify_list.iter() {
3185 intersection_observer.invoke_callback_if_necessary(cx);
3187 }
3188 }
3189
3190 pub(crate) fn queue_an_intersection_observer_task(&self) {
3192 if self.intersection_observer_task_queued.get() {
3195 return;
3196 }
3197
3198 self.intersection_observer_task_queued.set(true);
3201
3202 let document = Trusted::new(self);
3206 self.owner_global()
3207 .task_manager()
3208 .intersection_observer_task_source()
3209 .queue(task!(notify_intersection_observers: move |cx| {
3210 document.root().notify_intersection_observers(cx);
3211 }));
3212 }
3213
3214 pub(crate) fn handle_paint_metric(
3215 &self,
3216 metric_type: ProgressiveWebMetricType,
3217 metric_value: CrossProcessInstant,
3218 first_reflow: bool,
3219 can_gc: CanGc,
3220 ) {
3221 let metrics = self.interactive_time.borrow();
3222 match metric_type {
3223 ProgressiveWebMetricType::FirstPaint |
3224 ProgressiveWebMetricType::FirstContentfulPaint => {
3225 let binding = PerformancePaintTiming::new(
3226 self.window.as_global_scope(),
3227 metric_type.clone(),
3228 metric_value,
3229 can_gc,
3230 );
3231 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3232 let entry = binding.upcast::<PerformanceEntry>();
3233 self.window.Performance().queue_entry(entry);
3234 },
3235 ProgressiveWebMetricType::LargestContentfulPaint { area, url } => {
3236 let binding = LargestContentfulPaint::new(
3237 self.window.as_global_scope(),
3238 metric_value,
3239 area,
3240 url,
3241 can_gc,
3242 );
3243 metrics.set_largest_contentful_paint(metric_value, area);
3244 let entry = binding.upcast::<PerformanceEntry>();
3245 self.window.Performance().queue_entry(entry);
3246 },
3247 ProgressiveWebMetricType::TimeToInteractive => {
3248 unreachable!("Unexpected non-paint metric.")
3249 },
3250 }
3251 }
3252
3253 fn write(
3255 &self,
3256 cx: &mut js::context::JSContext,
3257 text: Vec<TrustedHTMLOrString>,
3258 line_feed: bool,
3259 containing_class: &str,
3260 field: &str,
3261 ) -> ErrorResult {
3262 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3264 let mut is_trusted = true;
3266 for value in text {
3268 match value {
3269 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3271 strings.push(trusted_html.to_string());
3272 },
3273 TrustedHTMLOrString::String(str_) => {
3274 is_trusted = false;
3276 strings.push(str_.into());
3278 },
3279 };
3280 }
3281 let mut string = itertools::join(strings, "");
3282 if !is_trusted {
3286 string = TrustedHTML::get_trusted_type_compliant_string(
3287 cx,
3288 &self.global(),
3289 TrustedHTMLOrString::String(string.into()),
3290 &format!("{} {}", containing_class, field),
3291 )?
3292 .str()
3293 .to_owned();
3294 }
3295 if line_feed {
3297 string.push('\n');
3298 }
3299 if !self.is_html_document() {
3301 return Err(Error::InvalidState(None));
3302 }
3303
3304 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3307 return Err(Error::InvalidState(None));
3308 }
3309
3310 if !self.is_active() || self.active_parser_was_aborted.get() {
3312 return Ok(());
3313 }
3314
3315 let parser = match self.get_current_parser() {
3316 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3317 _ => {
3319 if self.is_prompting_or_unloading() ||
3322 self.ignore_destructive_writes_counter.get() > 0
3323 {
3324 return Ok(());
3325 }
3326 self.Open(cx, None, None)?;
3328 self.get_current_parser().unwrap()
3329 },
3330 };
3331
3332 parser.write(string.into(), cx);
3334
3335 Ok(())
3336 }
3337
3338 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3339 RefMut::map(
3340 self.details_name_groups.borrow_mut(),
3341 |details_name_groups| details_name_groups.get_or_insert_default(),
3342 )
3343 }
3344}
3345
3346#[derive(MallocSizeOf, PartialEq)]
3347pub(crate) enum DocumentSource {
3348 FromParser,
3349 NotFromParser,
3350}
3351
3352#[expect(unsafe_code)]
3353impl<'dom> LayoutDom<'dom, Document> {
3354 #[inline]
3355 pub(crate) fn is_html_document_for_layout(&self) -> bool {
3356 self.unsafe_get().is_html_document
3357 }
3358
3359 #[inline]
3360 pub(crate) fn quirks_mode(self) -> QuirksMode {
3361 self.unsafe_get().quirks_mode.get()
3362 }
3363
3364 #[inline]
3365 pub(crate) fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3366 self.unsafe_get().style_shared_lock()
3367 }
3368
3369 #[inline]
3370 pub(crate) fn flush_shadow_root_stylesheets_if_necessary(
3371 self,
3372 stylist: &mut Stylist,
3373 guard: &SharedRwLockReadGuard,
3374 ) {
3375 (*self.unsafe_get()).flush_shadow_root_stylesheets_if_necessary_for_layout(stylist, guard)
3376 }
3377
3378 #[inline]
3379 pub(crate) fn shadow_roots_styles_changed(self) -> bool {
3380 self.unsafe_get().shadow_roots_styles_changed.get()
3381 }
3382
3383 pub(crate) fn elements_with_id(self, id: &Atom) -> &[LayoutDom<'dom, Element>] {
3384 let id_map = unsafe { self.unsafe_get().id_map.borrow_for_layout() };
3385 let matching_elements = id_map.get(id).map(Vec::as_slice).unwrap_or_default();
3386 unsafe { LayoutDom::to_layout_slice(matching_elements) }
3387 }
3388}
3389
3390pub(crate) fn get_registrable_domain_suffix_of_or_is_equal_to(
3394 host_suffix_string: &str,
3395 original_host: Host,
3396) -> Option<Host> {
3397 if host_suffix_string.is_empty() {
3399 return None;
3400 }
3401
3402 let host = match Host::parse(host_suffix_string) {
3404 Ok(host) => host,
3405 Err(_) => return None,
3406 };
3407
3408 if host != original_host {
3410 let host = match host {
3412 Host::Domain(ref host) => host,
3413 _ => return None,
3414 };
3415 let original_host = match original_host {
3416 Host::Domain(ref original_host) => original_host,
3417 _ => return None,
3418 };
3419
3420 let index = original_host.len().checked_sub(host.len())?;
3422 let (prefix, suffix) = original_host.split_at(index);
3423
3424 if !prefix.ends_with('.') {
3425 return None;
3426 }
3427 if suffix != host {
3428 return None;
3429 }
3430
3431 if is_pub_domain(host) {
3433 return None;
3434 }
3435 }
3436
3437 Some(host)
3439}
3440
3441fn url_has_network_scheme(url: &ServoUrl) -> bool {
3443 matches!(url.scheme(), "ftp" | "http" | "https")
3444}
3445
3446#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3447pub(crate) enum HasBrowsingContext {
3448 No,
3449 Yes,
3450}
3451
3452impl Document {
3453 #[allow(clippy::too_many_arguments)]
3454 pub(crate) fn new_inherited(
3455 window: &Window,
3456 has_browsing_context: HasBrowsingContext,
3457 url: Option<ServoUrl>,
3458 about_base_url: Option<ServoUrl>,
3459 origin: MutableOrigin,
3460 is_html_document: IsHTMLDocument,
3461 content_type: Option<Mime>,
3462 last_modified: Option<String>,
3463 activity: DocumentActivity,
3464 source: DocumentSource,
3465 doc_loader: DocumentLoader,
3466 referrer: Option<String>,
3467 status_code: Option<u16>,
3468 canceller: FetchCanceller,
3469 is_initial_about_blank: bool,
3470 allow_declarative_shadow_roots: bool,
3471 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3472 has_trustworthy_ancestor_origin: bool,
3473 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3474 creation_sandboxing_flag_set: SandboxingFlagSet,
3475 can_gc: CanGc,
3476 ) -> Document {
3477 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3478
3479 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3480 (DocumentReadyState::Loading, false)
3481 } else {
3482 (DocumentReadyState::Complete, true)
3483 };
3484
3485 let frame_type = match window.is_top_level() {
3486 true => TimerMetadataFrameType::RootWindow,
3487 false => TimerMetadataFrameType::IFrame,
3488 };
3489 let interactive_time = ProgressiveWebMetrics::new(
3490 window.time_profiler_chan().clone(),
3491 url.clone(),
3492 frame_type,
3493 );
3494
3495 let content_type = content_type.unwrap_or_else(|| {
3496 match is_html_document {
3497 IsHTMLDocument::HTMLDocument => "text/html",
3499 IsHTMLDocument::NonHTMLDocument => "application/xml",
3501 }
3502 .parse()
3503 .unwrap()
3504 });
3505
3506 let encoding = content_type
3507 .get_parameter(CHARSET)
3508 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3509 .unwrap_or(UTF_8);
3510
3511 let has_focus = window.parent_info().is_none();
3512
3513 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3514
3515 Document {
3516 node: Node::new_document_node(),
3517 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3518 window: Dom::from_ref(window),
3519 has_browsing_context,
3520 implementation: Default::default(),
3521 content_type,
3522 last_modified,
3523 url: DomRefCell::new(url),
3524 about_base_url: DomRefCell::new(about_base_url),
3525 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3527 event_handler: DocumentEventHandler::new(window),
3528 focus_handler: DocumentFocusHandler::new(window, has_focus),
3529 embedder_controls: DocumentEmbedderControls::new(window),
3530 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3531 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3532 encoding: Cell::new(encoding),
3534 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3535 activity: Cell::new(activity),
3536 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3537 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3538 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3539 images: Default::default(),
3540 embeds: Default::default(),
3541 links: Default::default(),
3542 forms: Default::default(),
3543 scripts: Default::default(),
3544 anchors: Default::default(),
3545 applets: Default::default(),
3546 iframes: RefCell::new(IFrameCollection::new()),
3547 style_shared_lock: {
3548 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3555 LazyLock::new(StyleSharedRwLock::new);
3556
3557 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3558 },
3560 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3561 stylesheet_list: MutNullableDom::new(None),
3562 ready_state: Cell::new(ready_state),
3563 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3564
3565 current_script: Default::default(),
3566 pending_parsing_blocking_script: Default::default(),
3567 script_blocking_stylesheets_count: Default::default(),
3568 render_blocking_element_count: Default::default(),
3569 deferred_scripts: Default::default(),
3570 asap_in_order_scripts_list: Default::default(),
3571 asap_scripts_set: Default::default(),
3572 animation_frame_ident: Cell::new(0),
3573 animation_frame_list: DomRefCell::new(VecDeque::new()),
3574 running_animation_callbacks: Cell::new(false),
3575 loader: DomRefCell::new(doc_loader),
3576 current_parser: Default::default(),
3577 base_element: Default::default(),
3578 target_base_element: Default::default(),
3579 appropriate_template_contents_owner_document: Default::default(),
3580 pending_restyles: DomRefCell::new(FxHashMap::default()),
3581 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3582 dom_interactive: Cell::new(Default::default()),
3583 dom_content_loaded_event_start: Cell::new(Default::default()),
3584 dom_content_loaded_event_end: Cell::new(Default::default()),
3585 dom_complete: Cell::new(Default::default()),
3586 top_level_dom_complete: Cell::new(Default::default()),
3587 load_event_start: Cell::new(Default::default()),
3588 load_event_end: Cell::new(Default::default()),
3589 unload_event_start: Cell::new(Default::default()),
3590 unload_event_end: Cell::new(Default::default()),
3591 origin: DomRefCell::new(origin),
3592 referrer,
3593 target_element: MutNullableDom::new(None),
3594 policy_container: DomRefCell::new(PolicyContainer::default()),
3595 preloaded_resources: Default::default(),
3596 ignore_destructive_writes_counter: Default::default(),
3597 ignore_opens_during_unload_counter: Default::default(),
3598 spurious_animation_frames: Cell::new(0),
3599 fullscreen_element: MutNullableDom::new(None),
3600 form_id_listener_map: Default::default(),
3601 interactive_time: DomRefCell::new(interactive_time),
3602 tti_window: DomRefCell::new(InteractiveWindow::default()),
3603 canceller,
3604 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3605 page_showing: Cell::new(false),
3606 salvageable: Cell::new(true),
3607 active_parser_was_aborted: Cell::new(false),
3608 fired_unload: Cell::new(false),
3609 responsive_images: Default::default(),
3610 redirect_count: Cell::new(0),
3611 redirect_start: Cell::new(None),
3612 redirect_end: Cell::new(None),
3613 secure_connection_start: Cell::new(None),
3614 completely_loaded: Cell::new(false),
3615 script_and_layout_blockers: Cell::new(0),
3616 delayed_tasks: Default::default(),
3617 shadow_roots: DomRefCell::new(HashSet::new()),
3618 shadow_roots_styles_changed: Cell::new(false),
3619 media_controls: DomRefCell::new(HashMap::new()),
3620 dirty_canvases: DomRefCell::new(Default::default()),
3621 has_pending_animated_image_update: Cell::new(false),
3622 selection: MutNullableDom::new(None),
3623 timeline: DocumentTimeline::new(window, can_gc).as_traced(),
3624 animations: Animations::new(),
3625 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3626 dirty_root: Default::default(),
3627 declarative_refresh: Default::default(),
3628 resize_observers: Default::default(),
3629 fonts: Default::default(),
3630 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3631 status_code,
3632 is_initial_about_blank: Cell::new(is_initial_about_blank),
3633 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3634 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3635 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3636 intersection_observer_task_queued: Cell::new(false),
3637 intersection_observers: Default::default(),
3638 highlighted_dom_node: Default::default(),
3639 adopted_stylesheets: Default::default(),
3640 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3641 pending_scroll_events: Default::default(),
3642 rendering_update_reasons: Default::default(),
3643 waiting_on_canvas_image_updates: Cell::new(false),
3644 root_removal_noted: Cell::new(true),
3645 current_rendering_epoch: Default::default(),
3646 custom_element_reaction_stack,
3647 active_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3648 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3649 favicon: RefCell::new(None),
3650 websockets: DOMTracker::new(),
3651 details_name_groups: Default::default(),
3652 protocol_handler_automation_mode: Default::default(),
3653 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3654 state_override: Default::default(),
3655 value_override: Default::default(),
3656 default_single_line_container_name: Default::default(),
3657 css_styling_flag: Default::default(),
3658 }
3659 }
3660
3661 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3663 if let Some(csp_list) = self.get_csp_list().as_ref() {
3664 for policy in &csp_list.0 {
3665 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3666 policy.disposition == PolicyDisposition::Enforce
3667 {
3668 return InsecureRequestsPolicy::Upgrade;
3669 }
3670 }
3671 }
3672
3673 self.inherited_insecure_requests_policy
3674 .get()
3675 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3676 }
3677
3678 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3680 &self.event_handler
3681 }
3682
3683 pub(crate) fn focus_handler(&self) -> &DocumentFocusHandler {
3685 &self.focus_handler
3686 }
3687
3688 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3690 &self.embedder_controls
3691 }
3692
3693 fn has_pending_scroll_events(&self) -> bool {
3696 !self.pending_scroll_events.borrow().is_empty()
3697 }
3698
3699 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3702 self.rendering_update_reasons
3703 .set(self.rendering_update_reasons.get().union(reason));
3704 }
3705
3706 pub(crate) fn clear_rendering_update_reasons(&self) {
3708 self.rendering_update_reasons
3709 .set(RenderingUpdateReason::empty())
3710 }
3711
3712 pub(crate) fn add_script_and_layout_blocker(&self) {
3719 self.script_and_layout_blockers
3720 .set(self.script_and_layout_blockers.get() + 1);
3721 }
3722
3723 pub(crate) fn remove_script_and_layout_blocker(&self, cx: &mut js::context::JSContext) {
3727 assert!(self.script_and_layout_blockers.get() > 0);
3728 self.script_and_layout_blockers
3729 .set(self.script_and_layout_blockers.get() - 1);
3730 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3731 {
3732 let task = self.delayed_tasks.borrow_mut().remove(0);
3733 task.run_box(cx);
3734 }
3735 }
3736
3737 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3739 self.delayed_tasks.borrow_mut().push(Box::new(task));
3740 }
3741
3742 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3745 assert_eq!(
3746 self.script_and_layout_blockers.get(),
3747 0,
3748 "Attempt to use script or layout while DOM not in a stable state"
3749 );
3750 }
3751
3752 #[allow(clippy::too_many_arguments)]
3753 pub(crate) fn new(
3754 window: &Window,
3755 has_browsing_context: HasBrowsingContext,
3756 url: Option<ServoUrl>,
3757 about_base_url: Option<ServoUrl>,
3758 origin: MutableOrigin,
3759 doctype: IsHTMLDocument,
3760 content_type: Option<Mime>,
3761 last_modified: Option<String>,
3762 activity: DocumentActivity,
3763 source: DocumentSource,
3764 doc_loader: DocumentLoader,
3765 referrer: Option<String>,
3766 status_code: Option<u16>,
3767 canceller: FetchCanceller,
3768 is_initial_about_blank: bool,
3769 allow_declarative_shadow_roots: bool,
3770 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3771 has_trustworthy_ancestor_origin: bool,
3772 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3773 creation_sandboxing_flag_set: SandboxingFlagSet,
3774 can_gc: CanGc,
3775 ) -> DomRoot<Document> {
3776 Self::new_with_proto(
3777 window,
3778 None,
3779 has_browsing_context,
3780 url,
3781 about_base_url,
3782 origin,
3783 doctype,
3784 content_type,
3785 last_modified,
3786 activity,
3787 source,
3788 doc_loader,
3789 referrer,
3790 status_code,
3791 canceller,
3792 is_initial_about_blank,
3793 allow_declarative_shadow_roots,
3794 inherited_insecure_requests_policy,
3795 has_trustworthy_ancestor_origin,
3796 custom_element_reaction_stack,
3797 creation_sandboxing_flag_set,
3798 can_gc,
3799 )
3800 }
3801
3802 #[allow(clippy::too_many_arguments)]
3803 fn new_with_proto(
3804 window: &Window,
3805 proto: Option<HandleObject>,
3806 has_browsing_context: HasBrowsingContext,
3807 url: Option<ServoUrl>,
3808 about_base_url: Option<ServoUrl>,
3809 origin: MutableOrigin,
3810 doctype: IsHTMLDocument,
3811 content_type: Option<Mime>,
3812 last_modified: Option<String>,
3813 activity: DocumentActivity,
3814 source: DocumentSource,
3815 doc_loader: DocumentLoader,
3816 referrer: Option<String>,
3817 status_code: Option<u16>,
3818 canceller: FetchCanceller,
3819 is_initial_about_blank: bool,
3820 allow_declarative_shadow_roots: bool,
3821 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3822 has_trustworthy_ancestor_origin: bool,
3823 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3824 creation_sandboxing_flag_set: SandboxingFlagSet,
3825 can_gc: CanGc,
3826 ) -> DomRoot<Document> {
3827 let document = reflect_dom_object_with_proto(
3828 Box::new(Document::new_inherited(
3829 window,
3830 has_browsing_context,
3831 url,
3832 about_base_url,
3833 origin,
3834 doctype,
3835 content_type,
3836 last_modified,
3837 activity,
3838 source,
3839 doc_loader,
3840 referrer,
3841 status_code,
3842 canceller,
3843 is_initial_about_blank,
3844 allow_declarative_shadow_roots,
3845 inherited_insecure_requests_policy,
3846 has_trustworthy_ancestor_origin,
3847 custom_element_reaction_stack,
3848 creation_sandboxing_flag_set,
3849 can_gc,
3850 )),
3851 window,
3852 proto,
3853 can_gc,
3854 );
3855 {
3856 let node = document.upcast::<Node>();
3857 node.set_owner_doc(&document);
3858 }
3859 document
3860 }
3861
3862 pub(crate) fn get_redirect_count(&self) -> u16 {
3863 self.redirect_count.get()
3864 }
3865
3866 pub(crate) fn set_redirect_count(&self, count: u16) {
3867 self.redirect_count.set(count)
3868 }
3869
3870 pub(crate) fn get_redirect_start(&self) -> Option<CrossProcessInstant> {
3871 self.redirect_start.get()
3872 }
3873
3874 pub(crate) fn set_redirect_start(&self, time: Option<CrossProcessInstant>) {
3875 self.redirect_start.set(time)
3876 }
3877
3878 pub(crate) fn get_redirect_end(&self) -> Option<CrossProcessInstant> {
3879 self.redirect_end.get()
3880 }
3881
3882 pub(crate) fn set_redirect_end(&self, time: Option<CrossProcessInstant>) {
3883 self.redirect_end.set(time)
3884 }
3885
3886 pub(crate) fn get_secure_connection_start(&self) -> Option<CrossProcessInstant> {
3887 self.secure_connection_start.get()
3888 }
3889
3890 pub(crate) fn set_secure_connection_start(&self, time: Option<CrossProcessInstant>) {
3891 self.secure_connection_start.set(time)
3892 }
3893
3894 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3895 if name.is_empty() {
3896 return 0;
3897 }
3898 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3899 }
3900
3901 pub(crate) fn nth_element_by_name(
3902 &self,
3903 index: u32,
3904 name: &DOMString,
3905 ) -> Option<DomRoot<Node>> {
3906 if name.is_empty() {
3907 return None;
3908 }
3909 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3910 }
3911
3912 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3915 let element = match node.downcast::<Element>() {
3916 Some(element) => element,
3917 None => return false,
3918 };
3919 if element.namespace() != &ns!(html) {
3920 return false;
3921 }
3922 element.get_name().is_some_and(|n| &*n == name)
3923 }
3924
3925 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3926 let doc = self.GetDocumentElement();
3927 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3928 maybe_node
3929 .iter()
3930 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3931 .filter(|node| callback(node))
3932 .count() as u32
3933 }
3934
3935 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3936 &self,
3937 index: u32,
3938 callback: F,
3939 ) -> Option<DomRoot<Node>> {
3940 let doc = self.GetDocumentElement();
3941 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3942 maybe_node
3943 .iter()
3944 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3945 .filter(|node| callback(node))
3946 .nth(index as usize)
3947 .map(|n| DomRoot::from_ref(&*n))
3948 }
3949
3950 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3951 self.GetDocumentElement().and_then(DomRoot::downcast)
3952 }
3953
3954 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3956 &self.style_shared_lock
3957 }
3958
3959 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3961 let mut stylesheets = self.stylesheets.borrow_mut();
3968 let have_changed = stylesheets.has_changed();
3969 stylesheets.flush_without_invalidation();
3970 have_changed
3971 }
3972
3973 pub(crate) fn salvageable(&self) -> bool {
3974 self.salvageable.get()
3975 }
3976
3977 pub(crate) fn make_document_unsalvageable(&self) {
3979 self.salvageable.set(false);
3985 }
3986
3987 pub(crate) fn appropriate_template_contents_owner_document(
3989 &self,
3990 can_gc: CanGc,
3991 ) -> DomRoot<Document> {
3992 self.appropriate_template_contents_owner_document
3993 .or_init(|| {
3994 let doctype = if self.is_html_document {
3995 IsHTMLDocument::HTMLDocument
3996 } else {
3997 IsHTMLDocument::NonHTMLDocument
3998 };
3999 let new_doc = Document::new(
4000 self.window(),
4001 HasBrowsingContext::No,
4002 None,
4003 None,
4004 MutableOrigin::new(ImmutableOrigin::new_opaque()),
4006 doctype,
4007 None,
4008 None,
4009 DocumentActivity::Inactive,
4010 DocumentSource::NotFromParser,
4011 DocumentLoader::new(&self.loader()),
4012 None,
4013 None,
4014 Default::default(),
4015 false,
4016 self.allow_declarative_shadow_roots(),
4017 Some(self.insecure_requests_policy()),
4018 self.has_trustworthy_ancestor_or_current_origin(),
4019 self.custom_element_reaction_stack.clone(),
4020 self.creation_sandboxing_flag_set(),
4021 can_gc,
4022 );
4023 new_doc
4024 .appropriate_template_contents_owner_document
4025 .set(Some(&new_doc));
4026 new_doc
4027 })
4028 }
4029
4030 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
4031 self.id_map
4032 .borrow()
4033 .get(id)
4034 .map(|elements| DomRoot::from_ref(&*elements[0]))
4035 }
4036
4037 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
4038 let map = self.pending_restyles.borrow_mut();
4039 RefMut::map(map, |m| {
4040 &mut m
4041 .entry(Dom::from_ref(el))
4042 .or_insert_with(|| NoTrace(PendingRestyle::default()))
4043 .0
4044 })
4045 }
4046
4047 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: AttrRef<'_>) {
4048 let mut entry = self.ensure_pending_restyle(el);
4054 if entry.snapshot.is_none() {
4055 entry.snapshot = Some(Snapshot::new());
4056 }
4057 if attr.local_name() == &local_name!("style") {
4058 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
4059 }
4060
4061 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
4062 entry.hint.insert(RestyleHint::RESTYLE_SELF);
4063 }
4064
4065 let snapshot = entry.snapshot.as_mut().unwrap();
4066 if attr.local_name() == &local_name!("id") {
4067 if snapshot.id_changed {
4068 return;
4069 }
4070 snapshot.id_changed = true;
4071 } else if attr.local_name() == &local_name!("class") {
4072 if snapshot.class_changed {
4073 return;
4074 }
4075 snapshot.class_changed = true;
4076 } else {
4077 snapshot.other_attributes_changed = true;
4078 }
4079 let local_name = style::LocalName::cast(attr.local_name());
4080 if !snapshot.changed_attrs.contains(local_name) {
4081 snapshot.changed_attrs.push(local_name.clone());
4082 }
4083 if snapshot.attrs.is_none() {
4084 let attrs = el
4085 .attrs()
4086 .borrow()
4087 .iter()
4088 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
4089 .collect();
4090 snapshot.attrs = Some(attrs);
4091 }
4092 }
4093
4094 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
4095 self.policy_container
4096 .borrow_mut()
4097 .set_referrer_policy(policy);
4098 }
4099
4100 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
4101 self.policy_container.borrow().get_referrer_policy()
4102 }
4103
4104 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
4105 if let Some(ref element) = self.target_element.get() {
4106 element.set_target_state(false);
4107 }
4108
4109 self.target_element.set(node);
4110
4111 if let Some(ref element) = self.target_element.get() {
4112 element.set_target_state(true);
4113 }
4114 }
4115
4116 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
4117 self.ignore_destructive_writes_counter
4118 .set(self.ignore_destructive_writes_counter.get() + 1);
4119 }
4120
4121 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
4122 self.ignore_destructive_writes_counter
4123 .set(self.ignore_destructive_writes_counter.get() - 1);
4124 }
4125
4126 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
4127 self.ignore_opens_during_unload_counter.get() > 0
4128 }
4129
4130 fn incr_ignore_opens_during_unload_counter(&self) {
4131 self.ignore_opens_during_unload_counter
4132 .set(self.ignore_opens_during_unload_counter.get() + 1);
4133 }
4134
4135 fn decr_ignore_opens_during_unload_counter(&self) {
4136 self.ignore_opens_during_unload_counter
4137 .set(self.ignore_opens_during_unload_counter.get() - 1);
4138 }
4139
4140 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4141 self.fullscreen_element.set(element);
4142 }
4143
4144 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4145 let map = self.form_id_listener_map.borrow();
4146 if let Some(listeners) = map.get(id) {
4147 for listener in listeners {
4148 listener
4149 .as_maybe_form_control()
4150 .expect("Element must be a form control")
4151 .reset_form_owner(can_gc);
4152 }
4153 }
4154 }
4155
4156 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4157 self.shadow_roots
4158 .borrow_mut()
4159 .insert(Dom::from_ref(shadow_root));
4160 self.invalidate_shadow_roots_stylesheets();
4161 }
4162
4163 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4164 let mut shadow_roots = self.shadow_roots.borrow_mut();
4165 shadow_roots.remove(&Dom::from_ref(shadow_root));
4166 }
4167
4168 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4169 self.shadow_roots_styles_changed.set(true);
4170 }
4171
4172 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4173 self.shadow_roots_styles_changed.get()
4174 }
4175
4176 pub(crate) fn flush_shadow_root_stylesheets_if_necessary_for_layout(
4177 &self,
4178 stylist: &mut Stylist,
4179 guard: &SharedRwLockReadGuard,
4180 ) {
4181 if !self.shadow_roots_styles_changed.get() {
4182 return;
4183 }
4184 #[expect(unsafe_code)]
4185 unsafe {
4186 for shadow_root in self.shadow_roots.borrow_for_layout().iter() {
4187 shadow_root
4188 .to_layout()
4189 .flush_stylesheets_for_layout(stylist, guard);
4190 }
4191 }
4192 self.shadow_roots_styles_changed.set(false);
4193 }
4194
4195 pub(crate) fn stylesheet_count(&self) -> usize {
4196 self.stylesheets.borrow().len()
4197 }
4198
4199 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4200 let stylesheets = self.stylesheets.borrow();
4201
4202 stylesheets
4203 .get(Origin::Author, index)
4204 .and_then(|s| s.owner.get_cssom_object())
4205 }
4206
4207 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4214 let stylesheets = &mut *self.stylesheets.borrow_mut();
4215
4216 let insertion_point = stylesheets
4218 .iter()
4219 .map(|(sheet, _origin)| sheet)
4220 .find(|sheet_in_doc| {
4221 match &sheet_in_doc.owner {
4222 StylesheetSource::Element(other_node) => {
4223 owner_node.upcast::<Node>().is_before(other_node.upcast())
4224 },
4225 StylesheetSource::Constructed(_) => true,
4228 }
4229 })
4230 .cloned();
4231
4232 if self.has_browsing_context() {
4233 let document_context = self.window.web_font_context();
4234
4235 self.window.layout_mut().add_stylesheet(
4236 sheet.clone(),
4237 insertion_point.as_ref().map(|s| s.sheet.clone()),
4238 &document_context,
4239 );
4240 }
4241
4242 DocumentOrShadowRoot::add_stylesheet(
4243 StylesheetSource::Element(Dom::from_ref(owner_node)),
4244 StylesheetSetRef::Document(stylesheets),
4245 sheet,
4246 insertion_point,
4247 self.style_shared_lock(),
4248 );
4249 }
4250
4251 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4256 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4257 debug_assert!(cssom_stylesheet.is_constructed());
4258
4259 let stylesheets = &mut *self.stylesheets.borrow_mut();
4260 let sheet = cssom_stylesheet.style_stylesheet().clone();
4261
4262 let insertion_point = stylesheets
4263 .iter()
4264 .last()
4265 .map(|(sheet, _origin)| sheet)
4266 .cloned();
4267
4268 if self.has_browsing_context() {
4269 self.window.layout_mut().add_stylesheet(
4270 sheet.clone(),
4271 insertion_point.as_ref().map(|s| s.sheet.clone()),
4272 &self.window.web_font_context(),
4273 );
4274 }
4275
4276 DocumentOrShadowRoot::add_stylesheet(
4277 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4278 StylesheetSetRef::Document(stylesheets),
4279 sheet,
4280 insertion_point,
4281 self.style_shared_lock(),
4282 );
4283 }
4284
4285 pub(crate) fn load_web_fonts_from_stylesheet(
4287 &self,
4288 stylesheet: &Arc<Stylesheet>,
4289 document_context: &WebFontDocumentContext,
4290 ) {
4291 self.window
4292 .layout()
4293 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4294 }
4295
4296 #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4299 if self.has_browsing_context() {
4300 self.window
4301 .layout_mut()
4302 .remove_stylesheet(stylesheet.clone());
4303 }
4304
4305 DocumentOrShadowRoot::remove_stylesheet(
4306 owner,
4307 stylesheet,
4308 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4309 )
4310 }
4311
4312 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4313 Ref::map(self.id_map.borrow(), |map| {
4314 map.get(id).map(|vec| &**vec).unwrap_or_default()
4315 })
4316 }
4317
4318 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4319 Ref::map(self.name_map.borrow(), |map| {
4320 map.get(name).map(|vec| &**vec).unwrap_or_default()
4321 })
4322 }
4323
4324 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4325 self.pending_restyles
4326 .borrow_mut()
4327 .drain()
4328 .filter_map(|(elem, restyle)| {
4329 let node = elem.upcast::<Node>();
4330 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4331 return None;
4332 }
4333 node.note_dirty_descendants();
4334 Some((node.to_trusted_node_address(), restyle.0))
4335 })
4336 .collect()
4337 }
4338
4339 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: TimeDuration) {
4340 self.timeline.advance_specific(delta);
4341 let current_timeline_value = self.current_animation_timeline_value();
4342 self.animations
4343 .update_for_new_timeline_value(&self.window, current_timeline_value);
4344 }
4345
4346 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4347 let current_timeline_value = self.current_animation_timeline_value();
4348 self.animations
4349 .mark_animating_nodes_as_dirty(current_timeline_value);
4350 }
4351
4352 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4353 self.timeline
4354 .upcast::<AnimationTimeline>()
4355 .current_time_in_seconds()
4356 }
4357
4358 pub(crate) fn animations(&self) -> &Animations {
4359 &self.animations
4360 }
4361
4362 pub(crate) fn update_animations_post_reflow(&self) {
4363 let current_timeline_value = self.current_animation_timeline_value();
4364 self.animations
4365 .do_post_reflow_update(&self.window, current_timeline_value);
4366 self.image_animation_manager
4367 .borrow_mut()
4368 .do_post_reflow_update(&self.window, current_timeline_value);
4369 }
4370
4371 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4372 self.animations.cancel_animations_for_node(node);
4373 self.image_animation_manager
4374 .borrow_mut()
4375 .cancel_animations_for_node(node);
4376 }
4377
4378 pub(crate) fn update_animations_and_send_events(&self, cx: &mut CurrentRealm) {
4380 if !self.layout_animations_test_enabled {
4382 self.timeline.update(self.window());
4383 }
4384
4385 let current_timeline_value = self.current_animation_timeline_value();
4392 self.animations
4393 .update_for_new_timeline_value(&self.window, current_timeline_value);
4394 self.maybe_mark_animating_nodes_as_dirty();
4395
4396 self.window().perform_a_microtask_checkpoint(cx);
4398
4399 self.animations().send_pending_events(self.window(), cx);
4401 }
4402
4403 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4404 self.image_animation_manager.borrow()
4405 }
4406
4407 pub(crate) fn set_has_pending_animated_image_update(&self) {
4408 self.has_pending_animated_image_update.set(true);
4409 }
4410
4411 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4413 if self.will_declaratively_refresh() {
4415 return;
4416 }
4417
4418 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4420 Regex::new(
4424 r#"(?xs)
4425 ^
4426 \s* # 3
4427 ((?<time>[0-9]+)|\.) # 5-6
4428 [0-9.]* # 8
4429 (
4430 (
4431 (\s*;|\s*,|\s) # 10.3
4432 \s* # 10.4
4433 )
4434 (
4435 (
4436 (U|u)(R|r)(L|l) # 11.2-11.4
4437 \s*=\s* # 11.5-11.7
4438 )?
4439 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4440 |
4441 (?<url4>(?s-u:.)*)
4442 )
4443 )?
4444 $
4445 "#,
4446 )
4447 .unwrap()
4448 });
4449
4450 let mut url_record = self.url();
4452 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4453 captures
4454 } else {
4455 return;
4456 };
4457 let time = if let Some(time_string) = captures.name("time") {
4458 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4459 } else {
4460 0
4461 };
4462 let captured_url = captures.name("url1").or(captures
4463 .name("url2")
4464 .or(captures.name("url3").or(captures.name("url4"))));
4465
4466 if let Some(url_match) = captured_url {
4468 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4469 Some(&url_record),
4470 &String::from_utf8_lossy(url_match.as_bytes()),
4471 ) {
4472 info!("Refresh to {}", url.debug_compact());
4473 url
4474 } else {
4475 return;
4477 }
4478 }
4479 if self.completely_loaded() {
4481 self.window.as_global_scope().schedule_callback(
4483 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4484 window: DomRoot::from_ref(self.window()),
4485 url: url_record,
4486 }),
4487 Duration::from_secs(time),
4488 );
4489 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4490 } else {
4491 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4492 url: url_record,
4493 time,
4494 });
4495 }
4496 }
4497
4498 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4499 self.declarative_refresh.borrow().is_some()
4500 }
4501 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4502 *self.declarative_refresh.borrow_mut() = Some(refresh);
4503 }
4504
4505 fn update_visibility_state(
4507 &self,
4508 cx: &mut js::context::JSContext,
4509 visibility_state: DocumentVisibilityState,
4510 ) {
4511 if self.visibility_state.get() == visibility_state {
4513 return;
4514 }
4515 self.visibility_state.set(visibility_state);
4517 let entry = VisibilityStateEntry::new(
4520 &self.global(),
4521 visibility_state,
4522 CrossProcessInstant::now(),
4523 CanGc::from_cx(cx),
4524 );
4525 self.window
4526 .Performance()
4527 .queue_entry(entry.upcast::<PerformanceEntry>());
4528
4529 #[cfg(feature = "gamepad")]
4540 if visibility_state == DocumentVisibilityState::Hidden {
4541 self.window
4542 .Navigator()
4543 .GetGamepads()
4544 .iter_mut()
4545 .for_each(|gamepad| {
4546 if let Some(g) = gamepad {
4547 g.vibration_actuator().handle_visibility_change();
4548 }
4549 });
4550 }
4551
4552 self.upcast::<EventTarget>()
4554 .fire_bubbling_event(cx, atom!("visibilitychange"));
4555 }
4556
4557 pub(crate) fn is_initial_about_blank(&self) -> bool {
4559 self.is_initial_about_blank.get()
4560 }
4561
4562 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4564 self.allow_declarative_shadow_roots.get()
4565 }
4566
4567 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4568 self.has_trustworthy_ancestor_origin.get()
4569 }
4570
4571 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4572 self.has_trustworthy_ancestor_origin.get() ||
4573 self.origin().immutable().is_potentially_trustworthy()
4574 }
4575
4576 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4577 self.highlighted_dom_node.set(node);
4578 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4579 }
4580
4581 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4582 self.highlighted_dom_node.get()
4583 }
4584
4585 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4586 self.custom_element_reaction_stack.clone()
4587 }
4588
4589 pub(crate) fn active_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4590 self.active_sandboxing_flag_set.get()
4591 }
4592
4593 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4594 self.active_sandboxing_flag_set.get().contains(flag)
4595 }
4596
4597 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4598 self.active_sandboxing_flag_set.set(flags)
4599 }
4600
4601 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4602 self.creation_sandboxing_flag_set.get()
4603 }
4604
4605 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4606 &self,
4607 ) -> SandboxingFlagSet {
4608 self.window()
4609 .window_proxy()
4610 .frame_element()
4611 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4612 .map(HTMLIFrameElement::sandboxing_flag_set)
4613 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4614 }
4615
4616 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4617 self.window()
4618 .scrolling_box_query(None, flags)
4619 .expect("We should always have a ScrollingBox for the Viewport")
4620 }
4621
4622 pub(crate) fn notify_embedder_favicon(&self) {
4623 if let Some(ref image) = *self.favicon.borrow() {
4624 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4625 }
4626 }
4627
4628 pub(crate) fn set_favicon(&self, favicon: Image) {
4629 *self.favicon.borrow_mut() = Some(favicon);
4630 self.notify_embedder_favicon();
4631 }
4632
4633 pub(crate) fn fullscreen_element(&self) -> Option<DomRoot<Element>> {
4634 self.fullscreen_element.get()
4635 }
4636
4637 pub(crate) fn state_override(&self, command_name: &CommandName) -> Option<bool> {
4639 self.state_override.borrow().get(command_name).copied()
4640 }
4641
4642 pub(crate) fn set_state_override(&self, command_name: CommandName, state: Option<bool>) {
4644 if let Some(state) = state {
4645 self.state_override.borrow_mut().insert(command_name, state);
4646 } else {
4647 self.value_override.borrow_mut().remove(&command_name);
4648 }
4649 }
4650
4651 pub(crate) fn value_override(&self, command_name: &CommandName) -> Option<DOMString> {
4653 self.value_override.borrow().get(command_name).cloned()
4654 }
4655
4656 pub(crate) fn set_value_override(&self, command_name: CommandName, value: Option<DOMString>) {
4658 if let Some(value) = value {
4659 self.value_override.borrow_mut().insert(command_name, value);
4660 } else {
4661 self.value_override.borrow_mut().remove(&command_name);
4662 }
4663 }
4664
4665 pub(crate) fn clear_command_overrides(&self) {
4668 self.state_override.borrow_mut().clear();
4669 self.value_override.borrow_mut().clear();
4670 }
4671
4672 pub(crate) fn default_single_line_container_name(&self) -> DefaultSingleLineContainerName {
4674 self.default_single_line_container_name.get()
4675 }
4676
4677 pub(crate) fn set_default_single_line_container_name(
4679 &self,
4680 value: DefaultSingleLineContainerName,
4681 ) {
4682 self.default_single_line_container_name.set(value)
4683 }
4684
4685 pub(crate) fn css_styling_flag(&self) -> bool {
4687 self.css_styling_flag.get()
4688 }
4689
4690 pub(crate) fn set_css_styling_flag(&self, value: bool) {
4692 self.css_styling_flag.set(value)
4693 }
4694}
4695
4696impl DocumentMethods<crate::DomTypeHolder> for Document {
4697 fn Constructor(
4699 window: &Window,
4700 proto: Option<HandleObject>,
4701 can_gc: CanGc,
4702 ) -> Fallible<DomRoot<Document>> {
4703 let doc = window.Document();
4705 let docloader = DocumentLoader::new(&doc.loader());
4706 Ok(Document::new_with_proto(
4707 window,
4708 proto,
4709 HasBrowsingContext::No,
4710 None,
4711 None,
4712 doc.origin().clone(),
4713 IsHTMLDocument::NonHTMLDocument,
4714 None,
4715 None,
4716 DocumentActivity::Inactive,
4717 DocumentSource::NotFromParser,
4718 docloader,
4719 None,
4720 None,
4721 Default::default(),
4722 false,
4723 doc.allow_declarative_shadow_roots(),
4724 Some(doc.insecure_requests_policy()),
4725 doc.has_trustworthy_ancestor_or_current_origin(),
4726 doc.custom_element_reaction_stack(),
4727 doc.active_sandboxing_flag_set.get(),
4728 can_gc,
4729 ))
4730 }
4731
4732 fn ParseHTMLUnsafe(
4734 cx: &mut js::context::JSContext,
4735 window: &Window,
4736 s: TrustedHTMLOrString,
4737 ) -> Fallible<DomRoot<Self>> {
4738 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
4742 cx,
4743 window.as_global_scope(),
4744 s,
4745 "Document parseHTMLUnsafe",
4746 )?;
4747
4748 let url = window.get_url();
4749 let doc = window.Document();
4750 let loader = DocumentLoader::new(&doc.loader());
4751
4752 let content_type = "text/html"
4753 .parse()
4754 .expect("Supported type is not a MIME type");
4755 let document = Document::new(
4758 window,
4759 HasBrowsingContext::No,
4760 Some(ServoUrl::parse("about:blank").unwrap()),
4761 None,
4762 doc.origin().clone(),
4763 IsHTMLDocument::HTMLDocument,
4764 Some(content_type),
4765 None,
4766 DocumentActivity::Inactive,
4767 DocumentSource::FromParser,
4768 loader,
4769 None,
4770 None,
4771 Default::default(),
4772 false,
4773 true,
4774 Some(doc.insecure_requests_policy()),
4775 doc.has_trustworthy_ancestor_or_current_origin(),
4776 doc.custom_element_reaction_stack(),
4777 doc.creation_sandboxing_flag_set(),
4778 CanGc::from_cx(cx),
4779 );
4780 ServoParser::parse_html_document(&document, Some(compliant_html), url, None, None, cx);
4782 document.set_ready_state(cx, DocumentReadyState::Complete);
4784 Ok(document)
4785 }
4786
4787 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4789 self.stylesheet_list.or_init(|| {
4790 StyleSheetList::new(
4791 &self.window,
4792 StyleSheetListOwner::Document(Dom::from_ref(self)),
4793 can_gc,
4794 )
4795 })
4796 }
4797
4798 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4800 self.implementation
4801 .or_init(|| DOMImplementation::new(self, can_gc))
4802 }
4803
4804 fn URL(&self) -> USVString {
4806 USVString(String::from(self.url().as_str()))
4807 }
4808
4809 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4811 self.document_or_shadow_root.active_element(self.upcast())
4812 }
4813
4814 fn HasFocus(&self) -> bool {
4816 if self.window().parent_info().is_none() {
4838 self.is_fully_active()
4840 } else {
4841 self.is_fully_active() && self.focus_handler.has_focus()
4843 }
4844 }
4845
4846 fn Domain(&self) -> DOMString {
4848 match self.origin().effective_domain() {
4850 None => DOMString::new(),
4852 Some(Host::Domain(domain)) => DOMString::from(domain),
4854 Some(host) => DOMString::from(host.to_string()),
4855 }
4856 }
4857
4858 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4860 if !self.has_browsing_context {
4862 return Err(Error::Security(None));
4863 }
4864
4865 if self.has_active_sandboxing_flag(
4868 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4869 ) {
4870 return Err(Error::Security(None));
4871 }
4872
4873 let effective_domain = match self.origin().effective_domain() {
4875 Some(effective_domain) => effective_domain,
4876 None => return Err(Error::Security(None)),
4878 };
4879
4880 let host =
4882 match get_registrable_domain_suffix_of_or_is_equal_to(&value.str(), effective_domain) {
4883 None => return Err(Error::Security(None)),
4884 Some(host) => host,
4885 };
4886
4887 self.origin().set_domain(host);
4892
4893 Ok(())
4894 }
4895
4896 fn Referrer(&self) -> DOMString {
4898 match self.referrer {
4899 Some(ref referrer) => DOMString::from(referrer.to_string()),
4900 None => DOMString::new(),
4901 }
4902 }
4903
4904 fn DocumentURI(&self) -> USVString {
4906 self.URL()
4907 }
4908
4909 fn CompatMode(&self) -> DOMString {
4911 DOMString::from(match self.quirks_mode.get() {
4912 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4913 QuirksMode::Quirks => "BackCompat",
4914 })
4915 }
4916
4917 fn CharacterSet(&self) -> DOMString {
4919 DOMString::from(self.encoding.get().name())
4920 }
4921
4922 fn Charset(&self) -> DOMString {
4924 self.CharacterSet()
4925 }
4926
4927 fn InputEncoding(&self) -> DOMString {
4929 self.CharacterSet()
4930 }
4931
4932 fn ContentType(&self) -> DOMString {
4934 DOMString::from(self.content_type.to_string())
4935 }
4936
4937 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4939 self.upcast::<Node>().children().find_map(DomRoot::downcast)
4940 }
4941
4942 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4944 self.upcast::<Node>().child_elements().next()
4945 }
4946
4947 fn GetElementsByTagName(
4949 &self,
4950 cx: &mut js::context::JSContext,
4951 qualified_name: DOMString,
4952 ) -> DomRoot<HTMLCollection> {
4953 let qualified_name = LocalName::from(qualified_name);
4954 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4955 return DomRoot::from_ref(entry);
4956 }
4957 let result = HTMLCollection::by_qualified_name(
4958 cx,
4959 &self.window,
4960 self.upcast(),
4961 qualified_name.clone(),
4962 );
4963 self.tag_map
4964 .borrow_mut()
4965 .insert(qualified_name, Dom::from_ref(&*result));
4966 result
4967 }
4968
4969 fn GetElementsByTagNameNS(
4971 &self,
4972 cx: &mut js::context::JSContext,
4973 maybe_ns: Option<DOMString>,
4974 tag_name: DOMString,
4975 ) -> DomRoot<HTMLCollection> {
4976 let ns = namespace_from_domstring(maybe_ns);
4977 let local = LocalName::from(tag_name);
4978 let qname = QualName::new(None, ns, local);
4979 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4980 return DomRoot::from_ref(collection);
4981 }
4982 let result =
4983 HTMLCollection::by_qual_tag_name(cx, &self.window, self.upcast(), qname.clone());
4984 self.tagns_map
4985 .borrow_mut()
4986 .insert(qname, Dom::from_ref(&*result));
4987 result
4988 }
4989
4990 fn GetElementsByClassName(
4992 &self,
4993 cx: &mut js::context::JSContext,
4994 classes: DOMString,
4995 ) -> DomRoot<HTMLCollection> {
4996 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4997 .map(Atom::from)
4998 .collect();
4999 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
5000 return DomRoot::from_ref(collection);
5001 }
5002 let result = HTMLCollection::by_atomic_class_name(
5003 cx,
5004 &self.window,
5005 self.upcast(),
5006 class_atoms.clone(),
5007 );
5008 self.classes_map
5009 .borrow_mut()
5010 .insert(class_atoms, Dom::from_ref(&*result));
5011 result
5012 }
5013
5014 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
5016 self.get_element_by_id(&Atom::from(id))
5017 }
5018
5019 fn CreateElement(
5021 &self,
5022 cx: &mut js::context::JSContext,
5023 mut local_name: DOMString,
5024 options: StringOrElementCreationOptions,
5025 ) -> Fallible<DomRoot<Element>> {
5026 if !is_valid_element_local_name(&local_name.str()) {
5029 debug!("Not a valid element name");
5030 return Err(Error::InvalidCharacter(None));
5031 }
5032
5033 if self.is_html_document {
5034 local_name.make_ascii_lowercase();
5035 }
5036
5037 let ns = if self.is_html_document || self.is_xhtml_document() {
5038 ns!(html)
5039 } else {
5040 ns!()
5041 };
5042
5043 let name = QualName::new(None, ns, LocalName::from(local_name));
5044 let is = match options {
5045 StringOrElementCreationOptions::String(_) => None,
5046 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5047 options.is.as_ref().map(LocalName::from)
5048 },
5049 };
5050 Ok(Element::create(
5051 cx,
5052 name,
5053 is,
5054 self,
5055 ElementCreator::ScriptCreated,
5056 CustomElementCreationMode::Synchronous,
5057 None,
5058 ))
5059 }
5060
5061 fn CreateElementNS(
5063 &self,
5064 cx: &mut js::context::JSContext,
5065 namespace: Option<DOMString>,
5066 qualified_name: DOMString,
5067 options: StringOrElementCreationOptions,
5068 ) -> Fallible<DomRoot<Element>> {
5069 let context = domname::Context::Element;
5072 let (namespace, prefix, local_name) =
5073 domname::validate_and_extract(namespace, &qualified_name, context)?;
5074
5075 let name = QualName::new(prefix, namespace, local_name);
5078 let is = match options {
5079 StringOrElementCreationOptions::String(_) => None,
5080 StringOrElementCreationOptions::ElementCreationOptions(options) => {
5081 options.is.as_ref().map(LocalName::from)
5082 },
5083 };
5084
5085 Ok(Element::create(
5087 cx,
5088 name,
5089 is,
5090 self,
5091 ElementCreator::ScriptCreated,
5092 CustomElementCreationMode::Synchronous,
5093 None,
5094 ))
5095 }
5096
5097 fn CreateAttribute(
5099 &self,
5100 cx: &mut js::context::JSContext,
5101 mut local_name: DOMString,
5102 ) -> Fallible<DomRoot<Attr>> {
5103 if !is_valid_attribute_local_name(&local_name.str()) {
5106 debug!("Not a valid attribute name");
5107 return Err(Error::InvalidCharacter(None));
5108 }
5109 if self.is_html_document {
5110 local_name.make_ascii_lowercase();
5111 }
5112 let name = LocalName::from(local_name);
5113 let value = AttrValue::String("".to_owned());
5114
5115 Ok(Attr::new(
5116 cx,
5117 self,
5118 name.clone(),
5119 value,
5120 name,
5121 ns!(),
5122 None,
5123 None,
5124 ))
5125 }
5126
5127 fn CreateAttributeNS(
5129 &self,
5130 cx: &mut js::context::JSContext,
5131 namespace: Option<DOMString>,
5132 qualified_name: DOMString,
5133 ) -> Fallible<DomRoot<Attr>> {
5134 let context = domname::Context::Attribute;
5137 let (namespace, prefix, local_name) =
5138 domname::validate_and_extract(namespace, &qualified_name, context)?;
5139 let value = AttrValue::String("".to_owned());
5140 let qualified_name = LocalName::from(qualified_name);
5141 Ok(Attr::new(
5142 cx,
5143 self,
5144 local_name,
5145 value,
5146 qualified_name,
5147 namespace,
5148 prefix,
5149 None,
5150 ))
5151 }
5152
5153 fn CreateDocumentFragment(&self, cx: &mut js::context::JSContext) -> DomRoot<DocumentFragment> {
5155 DocumentFragment::new(cx, self)
5156 }
5157
5158 fn CreateTextNode(&self, cx: &mut js::context::JSContext, data: DOMString) -> DomRoot<Text> {
5160 Text::new(cx, data, self)
5161 }
5162
5163 fn CreateCDATASection(
5165 &self,
5166 cx: &mut js::context::JSContext,
5167 data: DOMString,
5168 ) -> Fallible<DomRoot<CDATASection>> {
5169 if self.is_html_document {
5171 return Err(Error::NotSupported(None));
5172 }
5173
5174 if data.contains("]]>") {
5176 return Err(Error::InvalidCharacter(None));
5177 }
5178
5179 Ok(CDATASection::new(cx, data, self))
5181 }
5182
5183 fn CreateComment(&self, cx: &mut js::context::JSContext, data: DOMString) -> DomRoot<Comment> {
5185 Comment::new(cx, data, self, None)
5186 }
5187
5188 fn CreateProcessingInstruction(
5190 &self,
5191 cx: &mut js::context::JSContext,
5192 target: DOMString,
5193 data: DOMString,
5194 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5195 if !matches_name_production(&target.str()) {
5197 return Err(Error::InvalidCharacter(None));
5198 }
5199
5200 if data.contains("?>") {
5202 return Err(Error::InvalidCharacter(None));
5203 }
5204
5205 Ok(ProcessingInstruction::new(cx, target, data, self))
5207 }
5208
5209 fn ImportNode(
5211 &self,
5212 cx: &mut js::context::JSContext,
5213 node: &Node,
5214 options: BooleanOrImportNodeOptions,
5215 ) -> Fallible<DomRoot<Node>> {
5216 if node.is::<Document>() || node.is::<ShadowRoot>() {
5218 return Err(Error::NotSupported(None));
5219 }
5220 let (subtree, registry) = match options {
5222 BooleanOrImportNodeOptions::Boolean(boolean) => (boolean.into(), None),
5225 BooleanOrImportNodeOptions::ImportNodeOptions(options) => {
5227 let subtree = (!options.selfOnly).into();
5229 let registry = options.customElementRegistry;
5231 (subtree, registry)
5235 },
5236 };
5237 let registry = registry
5240 .or_else(|| CustomElementRegistry::lookup_a_custom_element_registry(self.upcast()));
5241
5242 Ok(Node::clone(cx, node, Some(self), subtree, registry))
5245 }
5246
5247 fn AdoptNode(&self, cx: &mut js::context::JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
5249 if node.is::<Document>() {
5251 return Err(Error::NotSupported(None));
5252 }
5253
5254 if node.is::<ShadowRoot>() {
5256 return Err(Error::HierarchyRequest(None));
5257 }
5258
5259 Node::adopt(cx, node, self);
5261
5262 Ok(DomRoot::from_ref(node))
5264 }
5265
5266 fn CreateEvent(
5268 &self,
5269 cx: &mut js::context::JSContext,
5270 mut interface: DOMString,
5271 ) -> Fallible<DomRoot<Event>> {
5272 interface.make_ascii_lowercase();
5273 match &*interface.str() {
5274 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5275 &self.window,
5276 CanGc::from_cx(cx),
5277 ))),
5278 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5279 CompositionEvent::new_uninitialized(&self.window, CanGc::from_cx(cx)),
5280 )),
5281 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5282 self.window.upcast(),
5283 CanGc::from_cx(cx),
5284 ))),
5285 "events" | "event" | "htmlevents" | "svgevents" => Ok(Event::new_uninitialized(
5288 self.window.upcast(),
5289 CanGc::from_cx(cx),
5290 )),
5291 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5292 &self.window,
5293 CanGc::from_cx(cx),
5294 ))),
5295 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5296 &self.window,
5297 CanGc::from_cx(cx),
5298 ))),
5299 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5300 cx,
5301 &self.window,
5302 ))),
5303 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5304 self.window.upcast(),
5305 CanGc::from_cx(cx),
5306 ))),
5307 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5308 cx,
5309 &self.window,
5310 ))),
5311 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5312 &self.window,
5313 "".into(),
5314 CanGc::from_cx(cx),
5315 ))),
5316 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5317 &self.window,
5318 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5319 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5320 &TouchList::new(&self.window, &[], CanGc::from_cx(cx)),
5321 CanGc::from_cx(cx),
5322 ))),
5323 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5324 &self.window,
5325 CanGc::from_cx(cx),
5326 ))),
5327 _ => Err(Error::NotSupported(None)),
5328 }
5329 }
5330
5331 fn LastModified(&self) -> DOMString {
5333 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5334 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5340 }))
5341 }
5342
5343 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5345 Range::new_with_doc(self, None, can_gc)
5346 }
5347
5348 fn CreateNodeIterator(
5350 &self,
5351 root: &Node,
5352 what_to_show: u32,
5353 filter: Option<Rc<NodeFilter>>,
5354 can_gc: CanGc,
5355 ) -> DomRoot<NodeIterator> {
5356 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5357 }
5358
5359 fn CreateTreeWalker(
5361 &self,
5362 root: &Node,
5363 what_to_show: u32,
5364 filter: Option<Rc<NodeFilter>>,
5365 ) -> DomRoot<TreeWalker> {
5366 TreeWalker::new(self, root, what_to_show, filter)
5367 }
5368
5369 fn Title(&self) -> DOMString {
5371 self.title().unwrap_or_else(|| DOMString::from(""))
5372 }
5373
5374 fn SetTitle(&self, cx: &mut js::context::JSContext, title: DOMString) {
5376 let root = match self.GetDocumentElement() {
5377 Some(root) => root,
5378 None => return,
5379 };
5380
5381 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5382 let elem = root
5383 .upcast::<Node>()
5384 .child_elements_unrooted(cx.no_gc())
5385 .find(|node| {
5386 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5387 });
5388 match elem {
5389 Some(elem) => UnrootedDom::upcast::<Node>(elem).as_rooted(),
5390 None => {
5391 let name = QualName::new(None, ns!(svg), local_name!("title"));
5392 let elem = Element::create(
5393 cx,
5394 name,
5395 None,
5396 self,
5397 ElementCreator::ScriptCreated,
5398 CustomElementCreationMode::Synchronous,
5399 None,
5400 );
5401 let parent = root.upcast::<Node>();
5402 let child = elem.upcast::<Node>();
5403 parent
5404 .InsertBefore(cx, child, parent.GetFirstChild().as_deref())
5405 .unwrap()
5406 },
5407 }
5408 } else if root.namespace() == &ns!(html) {
5409 let elem = root
5410 .upcast::<Node>()
5411 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
5412 .find(|node| node.is::<HTMLTitleElement>());
5413 match elem {
5414 Some(elem) => elem.as_rooted(),
5415 None => match self.GetHead() {
5416 Some(head) => {
5417 let name = QualName::new(None, ns!(html), local_name!("title"));
5418 let elem = Element::create(
5419 cx,
5420 name,
5421 None,
5422 self,
5423 ElementCreator::ScriptCreated,
5424 CustomElementCreationMode::Synchronous,
5425 None,
5426 );
5427 head.upcast::<Node>()
5428 .AppendChild(cx, elem.upcast())
5429 .unwrap()
5430 },
5431 None => return,
5432 },
5433 }
5434 } else {
5435 return;
5436 };
5437
5438 node.set_text_content_for_element(cx, Some(title));
5439 }
5440
5441 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5443 self.get_html_element()
5444 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5445 }
5446
5447 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5449 self.current_script.get()
5450 }
5451
5452 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5454 self.get_html_element().and_then(|root| {
5457 let node = root.upcast::<Node>();
5458 node.children()
5459 .find(|child| {
5460 matches!(
5461 child.type_id(),
5462 NodeTypeId::Element(ElementTypeId::HTMLElement(
5463 HTMLElementTypeId::HTMLBodyElement,
5464 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5465 HTMLElementTypeId::HTMLFrameSetElement,
5466 ))
5467 )
5468 })
5469 .map(|node| DomRoot::downcast(node).unwrap())
5470 })
5471 }
5472
5473 fn SetBody(
5475 &self,
5476 cx: &mut js::context::JSContext,
5477 new_body: Option<&HTMLElement>,
5478 ) -> ErrorResult {
5479 let new_body = match new_body {
5481 Some(new_body) => new_body,
5482 None => return Err(Error::HierarchyRequest(None)),
5483 };
5484
5485 let node = new_body.upcast::<Node>();
5486 match node.type_id() {
5487 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5488 NodeTypeId::Element(ElementTypeId::HTMLElement(
5489 HTMLElementTypeId::HTMLFrameSetElement,
5490 )) => {},
5491 _ => return Err(Error::HierarchyRequest(None)),
5492 }
5493
5494 let old_body = self.GetBody();
5496 if old_body.as_deref() == Some(new_body) {
5497 return Ok(());
5498 }
5499
5500 match (self.GetDocumentElement(), &old_body) {
5501 (Some(ref root), Some(child)) => {
5504 let root = root.upcast::<Node>();
5505 root.ReplaceChild(cx, new_body.upcast(), child.upcast())
5506 .map(|_| ())
5507 },
5508
5509 (None, _) => Err(Error::HierarchyRequest(None)),
5511
5512 (Some(ref root), &None) => {
5515 let root = root.upcast::<Node>();
5516 root.AppendChild(cx, new_body.upcast()).map(|_| ())
5517 },
5518 }
5519 }
5520
5521 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5523 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5524 }
5525
5526 fn Images(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5528 self.images.or_init(|| {
5529 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5530 element.is::<HTMLImageElement>()
5531 })
5532 })
5533 }
5534
5535 fn Embeds(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5537 self.embeds.or_init(|| {
5538 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5539 element.is::<HTMLEmbedElement>()
5540 })
5541 })
5542 }
5543
5544 fn Plugins(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5546 self.Embeds(cx)
5547 }
5548
5549 fn Links(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5551 self.links.or_init(|| {
5552 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5553 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5554 element.has_attribute(&local_name!("href"))
5555 })
5556 })
5557 }
5558
5559 fn Forms(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5561 self.forms.or_init(|| {
5562 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5563 element.is::<HTMLFormElement>()
5564 })
5565 })
5566 }
5567
5568 fn Scripts(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5570 self.scripts.or_init(|| {
5571 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5572 element.is::<HTMLScriptElement>()
5573 })
5574 })
5575 }
5576
5577 fn Anchors(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5579 self.anchors.or_init(|| {
5580 HTMLCollection::new_with_filter_fn(cx, &self.window, self.upcast(), |element, _| {
5581 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5582 })
5583 })
5584 }
5585
5586 fn Applets(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5588 self.applets
5589 .or_init(|| HTMLCollection::always_empty(cx, &self.window, self.upcast()))
5590 }
5591
5592 fn GetLocation(&self, cx: &mut js::context::JSContext) -> Option<DomRoot<Location>> {
5594 if self.is_fully_active() {
5595 Some(self.window.Location(cx))
5596 } else {
5597 None
5598 }
5599 }
5600
5601 fn Children(&self, cx: &mut js::context::JSContext) -> DomRoot<HTMLCollection> {
5603 HTMLCollection::children(cx, &self.window, self.upcast())
5604 }
5605
5606 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5608 self.upcast::<Node>().child_elements().next()
5609 }
5610
5611 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5613 self.upcast::<Node>()
5614 .rev_children()
5615 .find_map(DomRoot::downcast)
5616 }
5617
5618 fn ChildElementCount(&self) -> u32 {
5620 self.upcast::<Node>().child_elements().count() as u32
5621 }
5622
5623 fn Prepend(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5625 self.upcast::<Node>().prepend(cx, nodes)
5626 }
5627
5628 fn Append(&self, cx: &mut js::context::JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
5630 self.upcast::<Node>().append(cx, nodes)
5631 }
5632
5633 fn ReplaceChildren(
5635 &self,
5636 cx: &mut js::context::JSContext,
5637 nodes: Vec<NodeOrString>,
5638 ) -> ErrorResult {
5639 self.upcast::<Node>().replace_children(cx, nodes)
5640 }
5641
5642 fn MoveBefore(
5644 &self,
5645 cx: &mut js::context::JSContext,
5646 node: &Node,
5647 child: Option<&Node>,
5648 ) -> ErrorResult {
5649 self.upcast::<Node>().move_before(cx, node, child)
5650 }
5651
5652 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5654 self.upcast::<Node>().query_selector(selectors)
5655 }
5656
5657 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5659 self.upcast::<Node>().query_selector_all(selectors)
5660 }
5661
5662 fn ReadyState(&self) -> DocumentReadyState {
5664 self.ready_state.get()
5665 }
5666
5667 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5669 if self.has_browsing_context {
5670 Some(DomRoot::from_ref(&*self.window))
5671 } else {
5672 None
5673 }
5674 }
5675
5676 fn GetCookie(&self) -> Fallible<DOMString> {
5678 if self.is_cookie_averse() {
5679 return Ok(DOMString::new());
5680 }
5681
5682 if !self.origin().is_tuple() {
5683 return Err(Error::Security(None));
5684 }
5685
5686 let url = self.url();
5687 let (tx, rx) =
5688 profile_generic_channel::channel(self.global().time_profiler_chan().clone()).unwrap();
5689 let _ = self
5690 .window
5691 .as_global_scope()
5692 .resource_threads()
5693 .send(GetCookieStringForUrl(url, tx, NonHTTP));
5694 let cookies = rx.recv().unwrap();
5695 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5696 }
5697
5698 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5700 if self.is_cookie_averse() {
5701 return Ok(());
5702 }
5703
5704 if !self.origin().is_tuple() {
5705 return Err(Error::Security(None));
5706 }
5707
5708 if !cookie.is_valid_for_cookie() {
5709 return Ok(());
5710 }
5711
5712 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5713 vec![cookie]
5714 } else {
5715 vec![]
5716 };
5717
5718 let _ = self
5719 .window
5720 .as_global_scope()
5721 .resource_threads()
5722 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5723 Ok(())
5724 }
5725
5726 fn BgColor(&self) -> DOMString {
5728 self.get_body_attribute(&local_name!("bgcolor"))
5729 }
5730
5731 fn SetBgColor(&self, cx: &mut js::context::JSContext, value: DOMString) {
5733 self.set_body_attribute(cx, &local_name!("bgcolor"), value)
5734 }
5735
5736 fn FgColor(&self) -> DOMString {
5738 self.get_body_attribute(&local_name!("text"))
5739 }
5740
5741 fn SetFgColor(&self, cx: &mut js::context::JSContext, value: DOMString) {
5743 self.set_body_attribute(cx, &local_name!("text"), value)
5744 }
5745
5746 fn NamedGetter(
5748 &self,
5749 cx: &mut js::context::JSContext,
5750 name: DOMString,
5751 ) -> Option<NamedPropertyValue> {
5752 if name.is_empty() {
5753 return None;
5754 }
5755 let name = Atom::from(name);
5756
5757 let elements_with_name = self.get_elements_with_name(&name);
5760 let name_iter = elements_with_name
5761 .iter()
5762 .filter(|elem| is_named_element_with_name_attribute(elem));
5763 let elements_with_id = self.get_elements_with_id(&name);
5764 let id_iter = elements_with_id
5765 .iter()
5766 .filter(|elem| is_named_element_with_id_attribute(elem));
5767 let mut elements = name_iter.chain(id_iter);
5768
5769 let first = elements.next()?;
5776 if elements.all(|other| first == other) {
5777 if let Some(nested_window_proxy) = first
5778 .downcast::<HTMLIFrameElement>()
5779 .and_then(|iframe| iframe.GetContentWindow())
5780 {
5781 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5782 }
5783
5784 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5786 }
5787
5788 #[derive(JSTraceable, MallocSizeOf)]
5791 struct DocumentNamedGetter {
5792 #[no_trace]
5793 name: Atom,
5794 }
5795 impl CollectionFilter for DocumentNamedGetter {
5796 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5797 let type_ = match elem.upcast::<Node>().type_id() {
5798 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5799 _ => return false,
5800 };
5801 match type_ {
5802 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5803 elem.get_name().as_ref() == Some(&self.name)
5804 },
5805 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5806 name == *self.name ||
5807 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5808 }),
5809 _ => false,
5813 }
5814 }
5815 }
5816 let collection = HTMLCollection::create(
5817 cx,
5818 self.window(),
5819 self.upcast(),
5820 Box::new(DocumentNamedGetter { name }),
5821 );
5822 Some(NamedPropertyValue::HTMLCollection(collection))
5823 }
5824
5825 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5827 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5828
5829 let name_map = self.name_map.borrow();
5830 for (name, elements) in &(name_map).0 {
5831 if name.is_empty() {
5832 continue;
5833 }
5834 let mut name_iter = elements
5835 .iter()
5836 .filter(|elem| is_named_element_with_name_attribute(elem));
5837 if let Some(first) = name_iter.next() {
5838 names_with_first_named_element_map.insert(name, first);
5839 }
5840 }
5841 let id_map = self.id_map.borrow();
5842 for (id, elements) in &(id_map).0 {
5843 if id.is_empty() {
5844 continue;
5845 }
5846 let mut id_iter = elements
5847 .iter()
5848 .filter(|elem| is_named_element_with_id_attribute(elem));
5849 if let Some(first) = id_iter.next() {
5850 match names_with_first_named_element_map.entry(id) {
5851 Vacant(entry) => drop(entry.insert(first)),
5852 Occupied(mut entry) => {
5853 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5854 *entry.get_mut() = first;
5855 }
5856 },
5857 }
5858 }
5859 }
5860
5861 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5862 names_with_first_named_element_map
5863 .iter()
5864 .map(|(k, v)| (*k, *v))
5865 .collect();
5866 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5867 if a.1 == b.1 {
5868 a.0.cmp(b.0)
5871 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5872 Ordering::Less
5873 } else {
5874 Ordering::Greater
5875 }
5876 });
5877
5878 names_with_first_named_element_vec
5879 .iter()
5880 .map(|(k, _v)| DOMString::from(&***k))
5881 .collect()
5882 }
5883
5884 fn Clear(&self) {
5886 }
5888
5889 fn CaptureEvents(&self) {
5891 }
5893
5894 fn ReleaseEvents(&self) {
5896 }
5898
5899 global_event_handlers!();
5901
5902 event_handler!(
5904 readystatechange,
5905 GetOnreadystatechange,
5906 SetOnreadystatechange
5907 );
5908
5909 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5911 self.document_or_shadow_root.element_from_point(
5912 x,
5913 y,
5914 self.GetDocumentElement(),
5915 self.has_browsing_context,
5916 )
5917 }
5918
5919 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5921 self.document_or_shadow_root.elements_from_point(
5922 x,
5923 y,
5924 self.GetDocumentElement(),
5925 self.has_browsing_context,
5926 )
5927 }
5928
5929 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5931 if self.quirks_mode() == QuirksMode::Quirks {
5933 if let Some(ref body) = self.GetBody() {
5935 let e = body.upcast::<Element>();
5936 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5940 return Some(DomRoot::from_ref(e));
5941 }
5942 }
5943
5944 return None;
5946 }
5947
5948 self.GetDocumentElement()
5951 }
5952
5953 fn Open(
5955 &self,
5956 cx: &mut js::context::JSContext,
5957 _unused1: Option<DOMString>,
5958 _unused2: Option<DOMString>,
5959 ) -> Fallible<DomRoot<Document>> {
5960 if !self.is_html_document() {
5962 return Err(Error::InvalidState(None));
5963 }
5964
5965 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5967 return Err(Error::InvalidState(None));
5968 }
5969
5970 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5972
5973 if !self
5975 .origin()
5976 .same_origin(&entry_responsible_document.origin())
5977 {
5978 return Err(Error::Security(None));
5979 }
5980
5981 if self
5983 .get_current_parser()
5984 .is_some_and(|parser| parser.is_active())
5985 {
5986 return Ok(DomRoot::from_ref(self));
5987 }
5988
5989 if self.is_prompting_or_unloading() {
5991 return Ok(DomRoot::from_ref(self));
5992 }
5993
5994 if self.active_parser_was_aborted.get() {
5996 return Ok(DomRoot::from_ref(self));
5997 }
5998
5999 self.window().set_navigation_start();
6003
6004 if self.has_browsing_context() {
6007 self.abort(cx);
6010 }
6011
6012 for node in self
6014 .upcast::<Node>()
6015 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
6016 {
6017 node.upcast::<EventTarget>().remove_all_listeners();
6018 }
6019
6020 if self.window.Document() == DomRoot::from_ref(self) {
6022 self.window.upcast::<EventTarget>().remove_all_listeners();
6023 }
6024
6025 Node::replace_all(cx, None, self.upcast::<Node>());
6027
6028 if self.is_fully_active() {
6035 let mut new_url = entry_responsible_document.url();
6037
6038 if entry_responsible_document != DomRoot::from_ref(self) {
6040 new_url.set_fragment(None);
6041 }
6042
6043 self.set_url(new_url);
6046 }
6047
6048 self.is_initial_about_blank.set(false);
6050
6051 self.set_quirks_mode(QuirksMode::NoQuirks);
6057
6058 let resource_threads = self.window.as_global_scope().resource_threads().clone();
6064 *self.loader.borrow_mut() =
6065 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
6066 ServoParser::parse_html_script_input(self, self.url());
6067
6068 self.ready_state.set(DocumentReadyState::Loading);
6074
6075 Ok(DomRoot::from_ref(self))
6077 }
6078
6079 fn Open_(
6081 &self,
6082 cx: &mut js::context::JSContext,
6083 url: USVString,
6084 target: DOMString,
6085 features: DOMString,
6086 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
6087 self.browsing_context()
6088 .ok_or(Error::InvalidAccess(None))?
6089 .open(cx, url, target, features)
6090 }
6091
6092 fn Write(
6094 &self,
6095 cx: &mut js::context::JSContext,
6096 text: Vec<TrustedHTMLOrString>,
6097 ) -> ErrorResult {
6098 self.write(cx, text, false, "Document", "write")
6101 }
6102
6103 fn Writeln(
6105 &self,
6106 cx: &mut js::context::JSContext,
6107 text: Vec<TrustedHTMLOrString>,
6108 ) -> ErrorResult {
6109 self.write(cx, text, true, "Document", "writeln")
6112 }
6113
6114 fn Close(&self, cx: &mut js::context::JSContext) -> ErrorResult {
6116 if !self.is_html_document() {
6117 return Err(Error::InvalidState(None));
6119 }
6120
6121 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
6124 return Err(Error::InvalidState(None));
6125 }
6126
6127 let parser = match self.get_current_parser() {
6129 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
6130 _ => {
6131 return Ok(());
6132 },
6133 };
6134
6135 parser.close(cx);
6137
6138 Ok(())
6139 }
6140
6141 fn ExecCommand(
6143 &self,
6144 cx: &mut js::context::JSContext,
6145 command_id: DOMString,
6146 _show_ui: bool,
6147 value: TrustedHTMLOrString,
6148 ) -> Fallible<bool> {
6149 let value = if command_id == "insertHTML" {
6150 TrustedHTML::get_trusted_type_compliant_string(
6151 cx,
6152 self.window.as_global_scope(),
6153 value,
6154 "Document execCommand",
6155 )?
6156 } else {
6157 match value {
6158 TrustedHTMLOrString::TrustedHTML(trusted_html) => trusted_html.data().clone(),
6159 TrustedHTMLOrString::String(value) => value,
6160 }
6161 };
6162
6163 Ok(self.exec_command_for_command_id(cx, command_id, value))
6164 }
6165
6166 fn QueryCommandEnabled(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6168 self.check_support_and_enabled(cx, &command_id).is_some()
6170 }
6171
6172 fn QueryCommandSupported(&self, command_id: DOMString) -> bool {
6174 self.is_command_supported(command_id)
6178 }
6179
6180 fn QueryCommandIndeterm(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6182 self.is_command_indeterminate(cx, command_id)
6183 }
6184
6185 fn QueryCommandState(&self, cx: &mut js::context::JSContext, command_id: DOMString) -> bool {
6187 self.command_state_for_command(cx, command_id)
6188 }
6189
6190 fn QueryCommandValue(
6192 &self,
6193 cx: &mut js::context::JSContext,
6194 command_id: DOMString,
6195 ) -> DOMString {
6196 self.command_value_for_command(cx, command_id)
6197 }
6198
6199 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
6201
6202 event_handler!(
6204 fullscreenchange,
6205 GetOnfullscreenchange,
6206 SetOnfullscreenchange
6207 );
6208
6209 fn FullscreenEnabled(&self) -> bool {
6211 self.get_allow_fullscreen()
6212 }
6213
6214 fn Fullscreen(&self) -> bool {
6216 self.fullscreen_element.get().is_some()
6217 }
6218
6219 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6221 DocumentOrShadowRoot::get_fullscreen_element(&self.node, self.fullscreen_element.get())
6222 }
6223
6224 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6226 self.exit_fullscreen(can_gc)
6227 }
6228
6229 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6233 match self.media_controls.borrow().get(&*id.str()) {
6234 Some(m) => Ok(DomRoot::from_ref(m)),
6235 None => Err(Error::InvalidAccess(None)),
6236 }
6237 }
6238
6239 fn GetSelection(&self, cx: &mut js::context::JSContext) -> Option<DomRoot<Selection>> {
6241 if self.has_browsing_context {
6242 Some(self.selection.or_init(|| Selection::new(cx, self)))
6243 } else {
6244 None
6245 }
6246 }
6247
6248 fn Fonts(&self, cx: &mut js::context::JSContext) -> DomRoot<FontFaceSet> {
6250 self.fonts
6251 .or_init(|| FontFaceSet::new(cx, &self.global(), None))
6252 }
6253
6254 fn Hidden(&self) -> bool {
6256 self.visibility_state.get() == DocumentVisibilityState::Hidden
6257 }
6258
6259 fn VisibilityState(&self) -> DocumentVisibilityState {
6261 self.visibility_state.get()
6262 }
6263
6264 fn CreateExpression(
6265 &self,
6266 expression: DOMString,
6267 resolver: Option<Rc<XPathNSResolver>>,
6268 can_gc: CanGc,
6269 ) -> Fallible<DomRoot<crate::dom::types::XPathExpression>> {
6270 let parsed_expression =
6271 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6272 Ok(XPathExpression::new(
6273 &self.window,
6274 None,
6275 can_gc,
6276 parsed_expression,
6277 ))
6278 }
6279
6280 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6281 let global = self.global();
6282 let window = global.as_window();
6283 let evaluator = XPathEvaluator::new(window, None, can_gc);
6284 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6285 }
6286
6287 fn Evaluate(
6288 &self,
6289 expression: DOMString,
6290 context_node: &Node,
6291 resolver: Option<Rc<XPathNSResolver>>,
6292 result_type: u16,
6293 result: Option<&crate::dom::types::XPathResult>,
6294 can_gc: CanGc,
6295 ) -> Fallible<DomRoot<crate::dom::types::XPathResult>> {
6296 let parsed_expression =
6297 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6298 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6299 context_node,
6300 result_type,
6301 result,
6302 can_gc,
6303 )
6304 }
6305
6306 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6308 self.adopted_stylesheets_frozen_types.get_or_init(
6309 || {
6310 self.adopted_stylesheets
6311 .borrow()
6312 .clone()
6313 .iter()
6314 .map(|sheet| sheet.as_rooted())
6315 .collect()
6316 },
6317 context,
6318 retval,
6319 can_gc,
6320 );
6321 }
6322
6323 fn SetAdoptedStyleSheets(
6325 &self,
6326 context: JSContext,
6327 val: HandleValue,
6328 can_gc: CanGc,
6329 ) -> ErrorResult {
6330 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6331 context,
6332 self.adopted_stylesheets.borrow_mut().as_mut(),
6333 val,
6334 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6335 can_gc,
6336 );
6337
6338 if result.is_ok() {
6340 self.adopted_stylesheets_frozen_types.clear()
6341 }
6342
6343 result
6344 }
6345
6346 fn Timeline(&self) -> DomRoot<DocumentTimeline> {
6347 self.timeline.as_rooted()
6348 }
6349}
6350
6351fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6352 if marker.get().is_none() {
6353 marker.set(Some(CrossProcessInstant::now()))
6354 }
6355}
6356
6357#[derive(JSTraceable, MallocSizeOf)]
6358pub(crate) enum AnimationFrameCallback {
6359 DevtoolsFramerateTick {
6360 actor_name: String,
6361 },
6362 FrameRequestCallback {
6363 #[conditional_malloc_size_of]
6364 callback: Rc<FrameRequestCallback>,
6365 },
6366}
6367
6368impl AnimationFrameCallback {
6369 fn call(&self, cx: &mut js::context::JSContext, document: &Document, now: f64) {
6370 match *self {
6371 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6372 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6373 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6374 devtools_sender.send(msg).unwrap();
6375 },
6376 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6377 let _ = callback.Call__(cx, Finite::wrap(now), ExceptionHandling::Report);
6380 },
6381 }
6382 }
6383}
6384
6385#[derive(Default, JSTraceable, MallocSizeOf)]
6386#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6387struct PendingInOrderScriptVec {
6388 scripts: DomRefCell<VecDeque<PendingScript>>,
6389}
6390
6391impl PendingInOrderScriptVec {
6392 fn is_empty(&self) -> bool {
6393 self.scripts.borrow().is_empty()
6394 }
6395
6396 fn push(&self, element: &HTMLScriptElement) {
6397 self.scripts
6398 .borrow_mut()
6399 .push_back(PendingScript::new(element));
6400 }
6401
6402 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6403 let mut scripts = self.scripts.borrow_mut();
6404 let entry = scripts
6405 .iter_mut()
6406 .find(|entry| &*entry.element == element)
6407 .unwrap();
6408 entry.loaded(result);
6409 }
6410
6411 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6412 let mut scripts = self.scripts.borrow_mut();
6413 let pair = scripts.front_mut()?.take_result()?;
6414 scripts.pop_front();
6415 Some(pair)
6416 }
6417
6418 fn clear(&self) {
6419 *self.scripts.borrow_mut() = Default::default();
6420 }
6421}
6422
6423#[derive(JSTraceable, MallocSizeOf)]
6424#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6425struct PendingScript {
6426 element: Dom<HTMLScriptElement>,
6427 load: Option<ScriptResult>,
6429}
6430
6431impl PendingScript {
6432 fn new(element: &HTMLScriptElement) -> Self {
6433 Self {
6434 element: Dom::from_ref(element),
6435 load: None,
6436 }
6437 }
6438
6439 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6440 Self {
6441 element: Dom::from_ref(element),
6442 load,
6443 }
6444 }
6445
6446 fn loaded(&mut self, result: ScriptResult) {
6447 assert!(self.load.is_none());
6448 self.load = Some(result);
6449 }
6450
6451 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6452 self.load
6453 .take()
6454 .map(|result| (DomRoot::from_ref(&*self.element), result))
6455 }
6456}
6457
6458fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6459 let type_ = match elem.upcast::<Node>().type_id() {
6460 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6461 _ => return false,
6462 };
6463 match type_ {
6464 HTMLElementTypeId::HTMLFormElement |
6465 HTMLElementTypeId::HTMLIFrameElement |
6466 HTMLElementTypeId::HTMLImageElement => true,
6467 _ => false,
6471 }
6472}
6473
6474fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6475 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6479}
6480
6481impl DocumentHelpers for Document {
6482 fn ensure_safe_to_run_script_or_layout(&self) {
6483 Document::ensure_safe_to_run_script_or_layout(self)
6484 }
6485}
6486
6487pub(crate) struct SameoriginAncestorNavigablesIterator {
6491 document: DomRoot<Document>,
6492}
6493
6494impl SameoriginAncestorNavigablesIterator {
6495 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6496 Self { document }
6497 }
6498}
6499
6500impl Iterator for SameoriginAncestorNavigablesIterator {
6501 type Item = DomRoot<Document>;
6502
6503 fn next(&mut self) -> Option<Self::Item> {
6504 let window_proxy = self.document.browsing_context()?;
6505 self.document = window_proxy.parent()?.document()?;
6506 Some(self.document.clone())
6507 }
6508}
6509
6510pub(crate) struct SameOriginDescendantNavigablesIterator {
6515 stack: Vec<Box<dyn Iterator<Item = DomRoot<HTMLIFrameElement>>>>,
6516}
6517
6518impl SameOriginDescendantNavigablesIterator {
6519 pub(crate) fn new(document: DomRoot<Document>) -> Self {
6520 let iframes: Vec<DomRoot<HTMLIFrameElement>> = document.iframes().iter().collect();
6521 Self {
6522 stack: vec![Box::new(iframes.into_iter())],
6523 }
6524 }
6525
6526 fn get_next_iframe(&mut self) -> Option<DomRoot<HTMLIFrameElement>> {
6527 let mut cur_iframe = self.stack.last_mut()?.next();
6528 while cur_iframe.is_none() {
6529 self.stack.pop();
6530 cur_iframe = self.stack.last_mut()?.next();
6531 }
6532 cur_iframe
6533 }
6534}
6535
6536impl Iterator for SameOriginDescendantNavigablesIterator {
6537 type Item = DomRoot<Document>;
6538
6539 fn next(&mut self) -> Option<Self::Item> {
6540 while let Some(iframe) = self.get_next_iframe() {
6541 let Some(pipeline_id) = iframe.pipeline_id() else {
6542 continue;
6543 };
6544
6545 if let Some(document) = ScriptThread::find_document(pipeline_id) {
6546 let child_iframes: Vec<DomRoot<HTMLIFrameElement>> =
6547 document.iframes().iter().collect();
6548 self.stack.push(Box::new(child_iframes.into_iter()));
6549 return Some(document);
6550 } else {
6551 continue;
6552 };
6553 }
6554 None
6555 }
6556}