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::rc::Rc;
11use std::str::FromStr;
12use std::sync::{LazyLock, Mutex};
13use std::time::Duration;
14
15use base::cross_process_instant::CrossProcessInstant;
16use base::id::WebViewId;
17use base::{Epoch, IpcSend, generic_channel};
18use bitflags::bitflags;
19use chrono::Local;
20use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
21use content_security_policy::sandboxing_directive::SandboxingFlagSet;
22use content_security_policy::{CspList, PolicyDisposition};
23use cookie::Cookie;
24use data_url::mime::Mime;
25use devtools_traits::ScriptToDevtoolsControlMsg;
26use dom_struct::dom_struct;
27use embedder_traits::{
28 AllowOrDeny, AnimationState, EmbedderMsg, FocusSequenceNumber, Image, LoadStatus,
29};
30use encoding_rs::{Encoding, UTF_8};
31use html5ever::{LocalName, Namespace, QualName, local_name, ns};
32use hyper_serde::Serde;
33use js::rust::{HandleObject, HandleValue, MutableHandleValue};
34use layout_api::{
35 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
36 TrustedNodeAddress,
37};
38use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
39use net_traits::CookieSource::NonHTTP;
40use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
41use net_traits::ReferrerPolicy;
42use net_traits::policy_container::PolicyContainer;
43use net_traits::pub_domains::is_pub_domain;
44use net_traits::request::{InsecureRequestsPolicy, PreloadedResources, RequestBuilder};
45use net_traits::response::HttpsState;
46use percent_encoding::percent_decode;
47use profile_traits::ipc as profile_ipc;
48use profile_traits::time::TimerMetadataFrameType;
49use regex::bytes::Regex;
50use rustc_hash::{FxBuildHasher, FxHashMap};
51use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
52use script_bindings::interfaces::DocumentHelpers;
53use script_bindings::script_runtime::JSContext;
54use script_traits::{DocumentActivity, ProgressiveWebMetricType};
55use servo_arc::Arc;
56use servo_config::pref;
57use servo_media::{ClientContextId, ServoMedia};
58use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
59use style::attr::AttrValue;
60use style::context::QuirksMode;
61use style::invalidation::element::restyle_hints::RestyleHint;
62use style::selector_parser::Snapshot;
63use style::shared_lock::SharedRwLock as StyleSharedRwLock;
64use style::str::{split_html_space_chars, str_join};
65use style::stylesheet_set::DocumentStylesheetSet;
66use style::stylesheets::{Origin, OriginSet, Stylesheet};
67use stylo_atoms::Atom;
68use url::Host;
69
70use crate::animation_timeline::AnimationTimeline;
71use crate::animations::Animations;
72use crate::document_loader::{DocumentLoader, LoadType};
73use crate::dom::attr::Attr;
74use crate::dom::beforeunloadevent::BeforeUnloadEvent;
75use crate::dom::bindings::callback::ExceptionHandling;
76use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
77use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
78use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
79 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
80};
81use crate::dom::bindings::codegen::Bindings::ElementBinding::{
82 ScrollIntoViewContainer, ScrollIntoViewOptions, ScrollLogicalPosition,
83};
84use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
85use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
86use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
87use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
88use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
89use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
90use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
91use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
92use crate::dom::bindings::codegen::Bindings::WindowBinding::{
93 FrameRequestCallback, ScrollBehavior, ScrollOptions, WindowMethods,
94};
95use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
96use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
97use crate::dom::bindings::codegen::UnionTypes::{
98 BooleanOrScrollIntoViewOptions, NodeOrString, StringOrElementCreationOptions,
99 TrustedHTMLOrString,
100};
101use crate::dom::bindings::domname::{
102 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
103};
104use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
105use crate::dom::bindings::frozenarray::CachedFrozenArray;
106use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
107use crate::dom::bindings::num::Finite;
108use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
109use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
110use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
111use crate::dom::bindings::str::{DOMString, USVString};
112use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
113use crate::dom::bindings::weakref::DOMTracker;
114use crate::dom::bindings::xmlname::matches_name_production;
115use crate::dom::cdatasection::CDATASection;
116use crate::dom::comment::Comment;
117use crate::dom::compositionevent::CompositionEvent;
118use crate::dom::css::cssstylesheet::CSSStyleSheet;
119use crate::dom::css::fontfaceset::FontFaceSet;
120use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
121use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack};
122use crate::dom::customevent::CustomEvent;
123use crate::dom::document_embedder_controls::DocumentEmbedderControls;
124use crate::dom::document_event_handler::DocumentEventHandler;
125use crate::dom::documentfragment::DocumentFragment;
126use crate::dom::documentorshadowroot::{
127 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
128};
129use crate::dom::documenttype::DocumentType;
130use crate::dom::domimplementation::DOMImplementation;
131use crate::dom::element::{
132 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
133 ElementPerformFullscreenExit,
134};
135use crate::dom::event::{Event, EventBubbles, EventCancelable};
136use crate::dom::eventtarget::EventTarget;
137use crate::dom::focusevent::FocusEvent;
138use crate::dom::globalscope::GlobalScope;
139use crate::dom::hashchangeevent::HashChangeEvent;
140use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
141use crate::dom::html::htmlareaelement::HTMLAreaElement;
142use crate::dom::html::htmlbaseelement::HTMLBaseElement;
143use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
144use crate::dom::html::htmlelement::HTMLElement;
145use crate::dom::html::htmlembedelement::HTMLEmbedElement;
146use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
147use crate::dom::html::htmlheadelement::HTMLHeadElement;
148use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
149use crate::dom::html::htmliframeelement::HTMLIFrameElement;
150use crate::dom::html::htmlimageelement::HTMLImageElement;
151use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
152use crate::dom::html::htmltitleelement::HTMLTitleElement;
153use crate::dom::htmldetailselement::DetailsNameGroups;
154use crate::dom::intersectionobserver::IntersectionObserver;
155use crate::dom::keyboardevent::KeyboardEvent;
156use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
157use crate::dom::location::{Location, NavigationType};
158use crate::dom::messageevent::MessageEvent;
159use crate::dom::mouseevent::MouseEvent;
160use crate::dom::node::{
161 CloneChildrenFlag, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding,
162};
163use crate::dom::nodeiterator::NodeIterator;
164use crate::dom::nodelist::NodeList;
165use crate::dom::pagetransitionevent::PageTransitionEvent;
166use crate::dom::performance::performanceentry::PerformanceEntry;
167use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
168use crate::dom::processinginstruction::ProcessingInstruction;
169use crate::dom::promise::Promise;
170use crate::dom::range::Range;
171use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
172use crate::dom::scrolling_box::ScrollingBox;
173use crate::dom::selection::Selection;
174use crate::dom::servoparser::ServoParser;
175use crate::dom::shadowroot::ShadowRoot;
176use crate::dom::storageevent::StorageEvent;
177use crate::dom::text::Text;
178use crate::dom::touchevent::TouchEvent as DomTouchEvent;
179use crate::dom::touchlist::TouchList;
180use crate::dom::treewalker::TreeWalker;
181use crate::dom::trustedhtml::TrustedHTML;
182use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
183use crate::dom::uievent::UIEvent;
184use crate::dom::virtualmethods::vtable_for;
185use crate::dom::websocket::WebSocket;
186use crate::dom::window::Window;
187use crate::dom::windowproxy::WindowProxy;
188use crate::dom::xpathevaluator::XPathEvaluator;
189use crate::dom::xpathexpression::XPathExpression;
190use crate::fetch::FetchCanceller;
191use crate::iframe_collection::IFrameCollection;
192use crate::image_animation::ImageAnimationManager;
193use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
194use crate::mime::{APPLICATION, CHARSET};
195use crate::network_listener::{FetchResponseListener, NetworkListener};
196use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
197use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
198use crate::script_thread::ScriptThread;
199use crate::stylesheet_set::StylesheetSetRef;
200use crate::task::NonSendTaskBox;
201use crate::task_source::TaskSourceName;
202use crate::timers::OneshotTimerCallback;
203use crate::xpath::parse_expression;
204
205#[derive(Clone, Copy, PartialEq)]
206pub(crate) enum FireMouseEventType {
207 Move,
208 Over,
209 Out,
210 Enter,
211 Leave,
212}
213
214impl FireMouseEventType {
215 pub(crate) fn as_str(&self) -> &str {
216 match *self {
217 FireMouseEventType::Move => "mousemove",
218 FireMouseEventType::Over => "mouseover",
219 FireMouseEventType::Out => "mouseout",
220 FireMouseEventType::Enter => "mouseenter",
221 FireMouseEventType::Leave => "mouseleave",
222 }
223 }
224}
225
226#[derive(JSTraceable, MallocSizeOf)]
227pub(crate) struct RefreshRedirectDue {
228 #[no_trace]
229 pub(crate) url: ServoUrl,
230 #[ignore_malloc_size_of = "non-owning"]
231 pub(crate) window: DomRoot<Window>,
232}
233impl RefreshRedirectDue {
234 pub(crate) fn invoke(self, can_gc: CanGc) {
235 self.window.Location().navigate(
236 self.url.clone(),
237 NavigationHistoryBehavior::Replace,
238 NavigationType::DeclarativeRefresh,
239 can_gc,
240 );
241 }
242}
243
244#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
245pub(crate) enum IsHTMLDocument {
246 HTMLDocument,
247 NonHTMLDocument,
248}
249
250#[derive(JSTraceable, MallocSizeOf)]
251#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
252struct FocusTransaction {
253 element: Option<Dom<Element>>,
255 has_focus: bool,
257 focus_options: FocusOptions,
259}
260
261#[derive(JSTraceable, MallocSizeOf)]
263pub(crate) enum DeclarativeRefresh {
264 PendingLoad {
265 #[no_trace]
266 url: ServoUrl,
267 time: u64,
268 },
269 CreatedAfterLoad,
270}
271
272#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
275pub(crate) struct RenderingUpdateReason(u8);
276
277bitflags! {
278 impl RenderingUpdateReason: u8 {
279 const ResizeObserverStartedObservingTarget = 1 << 0;
282 const IntersectionObserverStartedObservingTarget = 1 << 1;
285 const FontReadyPromiseFulfilled = 1 << 2;
289 }
290}
291
292#[dom_struct]
294pub(crate) struct Document {
295 node: Node,
296 document_or_shadow_root: DocumentOrShadowRoot,
297 window: Dom<Window>,
298 implementation: MutNullableDom<DOMImplementation>,
299 #[ignore_malloc_size_of = "type from external crate"]
300 #[no_trace]
301 content_type: Mime,
302 last_modified: Option<String>,
303 #[no_trace]
304 encoding: Cell<&'static Encoding>,
305 has_browsing_context: bool,
306 is_html_document: bool,
307 #[no_trace]
308 activity: Cell<DocumentActivity>,
309 #[no_trace]
310 url: DomRefCell<ServoUrl>,
311 #[ignore_malloc_size_of = "defined in selectors"]
312 #[no_trace]
313 quirks_mode: Cell<QuirksMode>,
314 event_handler: DocumentEventHandler,
316 embedder_controls: DocumentEmbedderControls,
318 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
321 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
322 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
323 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
324 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
325 images: MutNullableDom<HTMLCollection>,
326 embeds: MutNullableDom<HTMLCollection>,
327 links: MutNullableDom<HTMLCollection>,
328 forms: MutNullableDom<HTMLCollection>,
329 scripts: MutNullableDom<HTMLCollection>,
330 anchors: MutNullableDom<HTMLCollection>,
331 applets: MutNullableDom<HTMLCollection>,
332 iframes: RefCell<IFrameCollection>,
334 #[no_trace]
337 style_shared_lock: StyleSharedRwLock,
338 #[custom_trace]
340 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
341 stylesheet_list: MutNullableDom<StyleSheetList>,
342 ready_state: Cell<DocumentReadyState>,
343 domcontentloaded_dispatched: Cell<bool>,
345 focus_transaction: DomRefCell<Option<FocusTransaction>>,
347 focused: MutNullableDom<Element>,
349 #[no_trace]
351 focus_sequence: Cell<FocusSequenceNumber>,
352 has_focus: Cell<bool>,
356 current_script: MutNullableDom<HTMLScriptElement>,
358 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
360 script_blocking_stylesheets_count: Cell<u32>,
362 render_blocking_element_count: Cell<u32>,
365 deferred_scripts: PendingInOrderScriptVec,
367 asap_in_order_scripts_list: PendingInOrderScriptVec,
369 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
371 animation_frame_ident: Cell<u32>,
374 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
377 running_animation_callbacks: Cell<bool>,
382 loader: DomRefCell<DocumentLoader>,
384 current_parser: MutNullableDom<ServoParser>,
386 base_element: MutNullableDom<HTMLBaseElement>,
388 appropriate_template_contents_owner_document: MutNullableDom<Document>,
391 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
394 #[no_trace]
398 needs_restyle: Cell<RestyleReason>,
399 #[no_trace]
402 dom_interactive: Cell<Option<CrossProcessInstant>>,
403 #[no_trace]
404 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
405 #[no_trace]
406 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
407 #[no_trace]
408 dom_complete: Cell<Option<CrossProcessInstant>>,
409 #[no_trace]
410 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
411 #[no_trace]
412 load_event_start: Cell<Option<CrossProcessInstant>>,
413 #[no_trace]
414 load_event_end: Cell<Option<CrossProcessInstant>>,
415 #[no_trace]
416 unload_event_start: Cell<Option<CrossProcessInstant>>,
417 #[no_trace]
418 unload_event_end: Cell<Option<CrossProcessInstant>>,
419 #[no_trace]
421 https_state: Cell<HttpsState>,
422 #[no_trace]
424 origin: MutableOrigin,
425 referrer: Option<String>,
427 target_element: MutNullableDom<Element>,
429 #[no_trace]
431 policy_container: DomRefCell<PolicyContainer>,
432 #[no_trace]
434 #[conditional_malloc_size_of]
435 preloaded_resources: PreloadedResources,
436 ignore_destructive_writes_counter: Cell<u32>,
438 ignore_opens_during_unload_counter: Cell<u32>,
440 spurious_animation_frames: Cell<u8>,
444
445 dom_count: Cell<u32>,
451 fullscreen_element: MutNullableDom<Element>,
453 form_id_listener_map:
460 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
461 #[no_trace]
462 interactive_time: DomRefCell<ProgressiveWebMetrics>,
463 #[no_trace]
464 tti_window: DomRefCell<InteractiveWindow>,
465 canceller: FetchCanceller,
467 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
469 page_showing: Cell<bool>,
471 salvageable: Cell<bool>,
473 active_parser_was_aborted: Cell<bool>,
475 fired_unload: Cell<bool>,
477 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
479 redirect_count: Cell<u16>,
481 script_and_layout_blockers: Cell<u32>,
483 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
485 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
486 completely_loaded: Cell<bool>,
488 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
490 shadow_roots_styles_changed: Cell<bool>,
492 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
498 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
501 has_pending_animated_image_update: Cell<bool>,
503 selection: MutNullableDom<Selection>,
505 animation_timeline: DomRefCell<AnimationTimeline>,
508 animations: Animations,
510 image_animation_manager: DomRefCell<ImageAnimationManager>,
512 dirty_root: MutNullableDom<Element>,
514 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
516 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
525 fonts: MutNullableDom<FontFaceSet>,
528 visibility_state: Cell<DocumentVisibilityState>,
530 status_code: Option<u16>,
532 is_initial_about_blank: Cell<bool>,
534 allow_declarative_shadow_roots: Cell<bool>,
536 #[no_trace]
538 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
539 has_trustworthy_ancestor_origin: Cell<bool>,
541 intersection_observer_task_queued: Cell<bool>,
543 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
555 highlighted_dom_node: MutNullableDom<Node>,
557 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
560 #[ignore_malloc_size_of = "mozjs"]
562 adopted_stylesheets_frozen_types: CachedFrozenArray,
563 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
565 rendering_update_reasons: Cell<RenderingUpdateReason>,
567 waiting_on_canvas_image_updates: Cell<bool>,
571 #[no_trace]
579 current_rendering_epoch: Cell<Epoch>,
580 #[conditional_malloc_size_of]
582 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
583 #[no_trace]
584 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
586 #[no_trace]
587 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
594 #[no_trace]
596 #[ignore_malloc_size_of = "TODO: unimplemented on Image"]
597 favicon: RefCell<Option<Image>>,
598
599 websockets: DOMTracker<WebSocket>,
601
602 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
604}
605
606impl Document {
607 fn unloading_cleanup_steps(&self) {
609 if self.close_outstanding_websockets() {
612 self.salvageable.set(false);
614 }
615
616 if !self.salvageable.get() {
621 let global_scope = self.window.as_global_scope();
622
623 global_scope.close_event_sources();
625
626 let msg = ScriptToConstellationMessage::DiscardDocument;
631 let _ = global_scope.script_to_constellation_chan().send(msg);
632 }
633 }
634
635 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
636 self.websockets.track(websocket);
637 }
638
639 fn close_outstanding_websockets(&self) -> bool {
640 let mut closed_any_websocket = false;
641 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
642 if websocket.make_disappear() {
643 closed_any_websocket = true;
644 }
645 });
646 closed_any_websocket
647 }
648
649 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
650 debug_assert!(*node.owner_doc() == *self);
651 if !node.is_connected() {
652 return;
653 }
654
655 let parent = match node.parent_in_flat_tree() {
656 Some(parent) => parent,
657 None => {
658 let document_element = match self.GetDocumentElement() {
661 Some(element) => element,
662 None => return,
663 };
664 if let Some(dirty_root) = self.dirty_root.get() {
665 for ancestor in dirty_root
668 .upcast::<Node>()
669 .inclusive_ancestors_in_flat_tree()
670 {
671 if ancestor.is::<Element>() {
672 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
673 }
674 }
675 }
676 self.dirty_root.set(Some(&document_element));
677 return;
678 },
679 };
680
681 if parent.is::<Element>() {
682 if !parent.is_styled() {
683 return;
684 }
685
686 if parent.is_display_none() {
687 return;
688 }
689 }
690
691 let element_parent: DomRoot<Element>;
692 let element = match node.downcast::<Element>() {
693 Some(element) => element,
694 None => {
695 match DomRoot::downcast::<Element>(parent) {
698 Some(parent) => {
699 element_parent = parent;
700 &element_parent
701 },
702 None => {
703 return;
707 },
708 }
709 },
710 };
711
712 let dirty_root = match self.dirty_root.get() {
713 None => {
714 element
715 .upcast::<Node>()
716 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
717 self.dirty_root.set(Some(element));
718 return;
719 },
720 Some(root) => root,
721 };
722
723 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
724 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
725 return;
726 }
727
728 if ancestor.is::<Element>() {
729 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
730 }
731 }
732
733 let new_dirty_root = element
734 .upcast::<Node>()
735 .common_ancestor_in_flat_tree(dirty_root.upcast())
736 .expect("Couldn't find common ancestor");
737
738 let mut has_dirty_descendants = true;
739 for ancestor in dirty_root
740 .upcast::<Node>()
741 .inclusive_ancestors_in_flat_tree()
742 {
743 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
744 has_dirty_descendants &= *ancestor != *new_dirty_root;
745 }
746
747 self.dirty_root
748 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
749 }
750
751 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
752 self.dirty_root.take()
753 }
754
755 #[inline]
756 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
757 self.loader.borrow()
758 }
759
760 #[inline]
761 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
762 self.loader.borrow_mut()
763 }
764
765 #[inline]
766 pub(crate) fn has_browsing_context(&self) -> bool {
767 self.has_browsing_context
768 }
769
770 #[inline]
772 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
773 if self.has_browsing_context {
774 self.window.undiscarded_window_proxy()
775 } else {
776 None
777 }
778 }
779
780 pub(crate) fn webview_id(&self) -> WebViewId {
781 self.window.webview_id()
782 }
783
784 #[inline]
785 pub(crate) fn window(&self) -> &Window {
786 &self.window
787 }
788
789 #[inline]
790 pub(crate) fn is_html_document(&self) -> bool {
791 self.is_html_document
792 }
793
794 pub(crate) fn is_xhtml_document(&self) -> bool {
795 self.content_type.matches(APPLICATION, "xhtml+xml")
796 }
797
798 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
799 self.https_state.set(https_state);
800 }
801
802 pub(crate) fn is_fully_active(&self) -> bool {
803 self.activity.get() == DocumentActivity::FullyActive
804 }
805
806 pub(crate) fn is_active(&self) -> bool {
807 self.activity.get() != DocumentActivity::Inactive
808 }
809
810 #[inline]
811 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
812 self.current_rendering_epoch.get()
813 }
814
815 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
816 assert!(self.has_browsing_context);
818 if activity == self.activity.get() {
819 return;
820 }
821
822 self.activity.set(activity);
824 let media = ServoMedia::get();
825 let pipeline_id = self.window().pipeline_id();
826 let client_context_id =
827 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
828
829 if activity != DocumentActivity::FullyActive {
830 self.window().suspend(can_gc);
831 media.suspend(&client_context_id);
832 return;
833 }
834
835 self.title_changed();
836 self.notify_embedder_favicon();
837 self.dirty_all_nodes();
838 self.window().resume(can_gc);
839 media.resume(&client_context_id);
840
841 if self.ready_state.get() != DocumentReadyState::Complete {
842 return;
843 }
844
845 let document = Trusted::new(self);
849 self.owner_global()
850 .task_manager()
851 .dom_manipulation_task_source()
852 .queue(task!(fire_pageshow_event: move || {
853 let document = document.root();
854 let window = document.window();
855 if document.page_showing.get() {
857 return;
858 }
859 document.page_showing.set(true);
861 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
863 let event = PageTransitionEvent::new(
866 window,
867 atom!("pageshow"),
868 false, false, true, CanGc::note(),
872 );
873 let event = event.upcast::<Event>();
874 event.set_trusted(true);
875 window.dispatch_event_with_target_override(event, CanGc::note());
876 }))
877 }
878
879 pub(crate) fn origin(&self) -> &MutableOrigin {
880 &self.origin
881 }
882
883 pub(crate) fn url(&self) -> ServoUrl {
885 self.url.borrow().clone()
886 }
887
888 pub(crate) fn set_url(&self, url: ServoUrl) {
889 *self.url.borrow_mut() = url;
890 }
891
892 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
894 let document_url = self.url();
896 if document_url.as_str() == "about:srcdoc" {
897 let base_url = self
898 .browsing_context()
899 .and_then(|browsing_context| browsing_context.creator_base_url());
900
901 if base_url.is_none() {
903 error!("about:srcdoc page should always have a creator base URL");
904 }
905
906 return base_url.unwrap_or(document_url);
908 }
909
910 if document_url.matches_about_blank() {
913 return self
914 .browsing_context()
915 .and_then(|browsing_context| browsing_context.creator_base_url())
916 .unwrap_or(document_url);
917 }
918
919 document_url
921 }
922
923 pub(crate) fn base_url(&self) -> ServoUrl {
925 match self.base_element() {
926 None => self.fallback_base_url(),
928 Some(base) => base.frozen_base_url(),
930 }
931 }
932
933 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
934 self.needs_restyle.set(self.needs_restyle.get() | reason)
935 }
936
937 pub(crate) fn clear_restyle_reasons(&self) {
938 self.needs_restyle.set(RestyleReason::empty());
939 }
940
941 pub(crate) fn restyle_reason(&self) -> RestyleReason {
942 let mut condition = self.needs_restyle.get();
943 if self.stylesheets.borrow().has_changed() {
944 condition.insert(RestyleReason::StylesheetsChanged);
945 }
946
947 if let Some(root) = self.GetDocumentElement() {
951 if root.upcast::<Node>().has_dirty_descendants() {
952 condition.insert(RestyleReason::DOMChanged);
953 }
954 }
955
956 if !self.pending_restyles.borrow().is_empty() {
957 condition.insert(RestyleReason::PendingRestyles);
958 }
959
960 condition
961 }
962
963 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
965 self.base_element.get()
966 }
967
968 pub(crate) fn refresh_base_element(&self) {
971 let base = self
972 .upcast::<Node>()
973 .traverse_preorder(ShadowIncluding::No)
974 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
975 .find(|element| {
976 element
977 .upcast::<Element>()
978 .has_attribute(&local_name!("href"))
979 });
980 self.base_element.set(base.as_deref());
981 }
982
983 pub(crate) fn dom_count(&self) -> u32 {
984 self.dom_count.get()
985 }
986
987 pub(crate) fn increment_dom_count(&self) {
991 self.dom_count.set(self.dom_count.get() + 1);
992 }
993
994 pub(crate) fn decrement_dom_count(&self) {
996 self.dom_count.set(self.dom_count.get() - 1);
997 }
998
999 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1000 self.quirks_mode.get()
1001 }
1002
1003 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1004 let old_mode = self.quirks_mode.replace(new_mode);
1005
1006 if old_mode != new_mode {
1007 self.window.layout_mut().set_quirks_mode(new_mode);
1008 }
1009 }
1010
1011 pub(crate) fn encoding(&self) -> &'static Encoding {
1012 self.encoding.get()
1013 }
1014
1015 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1016 self.encoding.set(encoding);
1017 }
1018
1019 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1020 if node.is_connected() {
1021 node.note_dirty_descendants();
1022 }
1023
1024 node.dirty(NodeDamage::ContentOrHeritage);
1027 }
1028
1029 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1031 self.document_or_shadow_root
1032 .unregister_named_element(&self.id_map, to_unregister, &id);
1033 self.reset_form_owner_for_listeners(&id, can_gc);
1034 }
1035
1036 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1038 let root = self.GetDocumentElement().expect(
1039 "The element is in the document, so there must be a document \
1040 element.",
1041 );
1042 self.document_or_shadow_root.register_named_element(
1043 &self.id_map,
1044 element,
1045 &id,
1046 DomRoot::from_ref(root.upcast::<Node>()),
1047 );
1048 self.reset_form_owner_for_listeners(&id, can_gc);
1049 }
1050
1051 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1053 self.document_or_shadow_root
1054 .unregister_named_element(&self.name_map, to_unregister, &name);
1055 }
1056
1057 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1059 let root = self.GetDocumentElement().expect(
1060 "The element is in the document, so there must be a document \
1061 element.",
1062 );
1063 self.document_or_shadow_root.register_named_element(
1064 &self.name_map,
1065 element,
1066 &name,
1067 DomRoot::from_ref(root.upcast::<Node>()),
1068 );
1069 }
1070
1071 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1072 &self,
1073 id: DOMString,
1074 listener: &T,
1075 ) {
1076 let mut map = self.form_id_listener_map.borrow_mut();
1077 let listener = listener.to_element();
1078 let set = map.entry(Atom::from(id)).or_default();
1079 set.insert(Dom::from_ref(listener));
1080 }
1081
1082 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1083 &self,
1084 id: DOMString,
1085 listener: &T,
1086 ) {
1087 let mut map = self.form_id_listener_map.borrow_mut();
1088 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1089 entry
1090 .get_mut()
1091 .remove(&Dom::from_ref(listener.to_element()));
1092 if entry.get().is_empty() {
1093 entry.remove();
1094 }
1095 }
1096 }
1097
1098 pub(crate) fn find_fragment_node(&self, fragid: &str) -> Option<DomRoot<Element>> {
1101 percent_decode(fragid.as_bytes())
1105 .decode_utf8()
1106 .ok()
1107 .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
1109 .or_else(|| self.get_anchor_by_name(fragid))
1111 }
1113
1114 pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) {
1118 let target = self.find_fragment_node(fragment);
1119
1120 self.set_target_element(target.as_deref());
1122
1123 let point = target
1124 .as_ref()
1125 .map(|element| {
1126 let rect = element.upcast::<Node>().border_box().unwrap_or_default();
1131
1132 let device_pixel_ratio = self.window.device_pixel_ratio().get();
1137 (
1138 rect.origin.x.to_nearest_pixel(device_pixel_ratio),
1139 rect.origin.y.to_nearest_pixel(device_pixel_ratio),
1140 )
1141 })
1142 .or_else(|| {
1143 if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
1144 Some((0.0, 0.0))
1147 } else {
1148 None
1149 }
1150 });
1151
1152 if let Some((x, y)) = point {
1153 self.window.scroll(x, y, ScrollBehavior::Instant)
1154 }
1155 }
1156
1157 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1158 let name = Atom::from(name);
1159 self.name_map.borrow().get(&name).and_then(|elements| {
1160 elements
1161 .iter()
1162 .find(|e| e.is::<HTMLAnchorElement>())
1163 .map(|e| DomRoot::from_ref(&**e))
1164 })
1165 }
1166
1167 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1169 match state {
1170 DocumentReadyState::Loading => {
1171 if self.window().is_top_level() {
1172 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1173 self.webview_id(),
1174 LoadStatus::Started,
1175 ));
1176 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1177 }
1178 },
1179 DocumentReadyState::Complete => {
1180 if self.window().is_top_level() {
1181 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1182 self.webview_id(),
1183 LoadStatus::Complete,
1184 ));
1185 }
1186 update_with_current_instant(&self.dom_complete);
1187 },
1188 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1189 };
1190
1191 self.ready_state.set(state);
1192
1193 self.upcast::<EventTarget>()
1194 .fire_event(atom!("readystatechange"), can_gc);
1195 }
1196
1197 pub(crate) fn scripting_enabled(&self) -> bool {
1200 self.has_browsing_context() &&
1203 !self.has_active_sandboxing_flag(
1207 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1208 )
1209 }
1210
1211 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1214 self.focused.get()
1215 }
1216
1217 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1222 self.focus_sequence.get()
1223 }
1224
1225 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1227 self.focus_sequence.set(FocusSequenceNumber(
1228 self.focus_sequence
1229 .get()
1230 .0
1231 .checked_add(1)
1232 .expect("too many focus messages have been sent"),
1233 ));
1234 self.focus_sequence.get()
1235 }
1236
1237 pub(crate) fn has_focus_transaction(&self) -> bool {
1238 self.focus_transaction.borrow().is_some()
1239 }
1240
1241 pub(crate) fn begin_focus_transaction(&self) {
1244 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1246 element: self.focused.get().as_deref().map(Dom::from_ref),
1247 has_focus: self.has_focus.get(),
1248 focus_options: FocusOptions {
1249 preventScroll: true,
1250 },
1251 });
1252 }
1253
1254 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1256 if Some(not_focusable) != self.focused.get().as_deref() {
1259 return;
1260 }
1261
1262 let implicit_transaction = self.focus_transaction.borrow().is_none();
1263
1264 if implicit_transaction {
1265 self.begin_focus_transaction();
1266 }
1267
1268 {
1271 let mut focus_transaction = self.focus_transaction.borrow_mut();
1272 focus_transaction.as_mut().unwrap().element = None;
1273 }
1274
1275 if implicit_transaction {
1276 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1277 }
1278 }
1279
1280 pub(crate) fn request_focus(
1283 &self,
1284 elem: Option<&Element>,
1285 focus_initiator: FocusInitiator,
1286 can_gc: CanGc,
1287 ) {
1288 self.request_focus_with_options(
1289 elem,
1290 focus_initiator,
1291 FocusOptions {
1292 preventScroll: true,
1293 },
1294 can_gc,
1295 );
1296 }
1297
1298 pub(crate) fn request_focus_with_options(
1304 &self,
1305 elem: Option<&Element>,
1306 focus_initiator: FocusInitiator,
1307 focus_options: FocusOptions,
1308 can_gc: CanGc,
1309 ) {
1310 if elem.is_some_and(|e| !e.is_focusable_area()) {
1313 return;
1314 }
1315
1316 let implicit_transaction = self.focus_transaction.borrow().is_none();
1317
1318 if implicit_transaction {
1319 self.begin_focus_transaction();
1320 }
1321
1322 {
1323 let mut focus_transaction = self.focus_transaction.borrow_mut();
1324 let focus_transaction = focus_transaction.as_mut().unwrap();
1325 focus_transaction.element = elem.map(Dom::from_ref);
1326 focus_transaction.has_focus = true;
1327 focus_transaction.focus_options = focus_options;
1328 }
1329
1330 if implicit_transaction {
1331 self.commit_focus_transaction(focus_initiator, can_gc);
1332 }
1333 }
1334
1335 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1339 if self.window().parent_info().is_none() {
1340 warn!("Top-level document cannot be unfocused");
1341 return;
1342 }
1343
1344 assert!(
1347 self.focus_transaction.borrow().is_none(),
1348 "there mustn't be an in-progress focus transaction at this point"
1349 );
1350
1351 self.begin_focus_transaction();
1353
1354 {
1356 let mut focus_transaction = self.focus_transaction.borrow_mut();
1357 focus_transaction.as_mut().unwrap().has_focus = false;
1358 }
1359
1360 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1362 }
1363
1364 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1367 let (mut new_focused, new_focus_state, prevent_scroll) = {
1368 let focus_transaction = self.focus_transaction.borrow();
1369 let focus_transaction = focus_transaction
1370 .as_ref()
1371 .expect("no focus transaction in progress");
1372 (
1373 focus_transaction
1374 .element
1375 .as_ref()
1376 .map(|e| DomRoot::from_ref(&**e)),
1377 focus_transaction.has_focus,
1378 focus_transaction.focus_options.preventScroll,
1379 )
1380 };
1381 *self.focus_transaction.borrow_mut() = None;
1382
1383 if !new_focus_state {
1384 if new_focused.take().is_some() {
1387 trace!(
1388 "Forgetting the document's focused area because the \
1389 document's container was removed from the top-level BC's \
1390 focus chain"
1391 );
1392 }
1393 }
1394
1395 let old_focused = self.focused.get();
1396 let old_focus_state = self.has_focus.get();
1397
1398 debug!(
1399 "Committing focus transaction: {:?} → {:?}",
1400 (&old_focused, old_focus_state),
1401 (&new_focused, new_focus_state),
1402 );
1403
1404 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1407 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1408
1409 let trace_focus_chain = |name, element, doc| {
1410 trace!(
1411 "{} local focus chain: {}",
1412 name,
1413 match (element, doc) {
1414 (Some(e), _) => format!("[{:?}, document]", e),
1415 (None, true) => "[document]".to_owned(),
1416 (None, false) => "[]".to_owned(),
1417 }
1418 );
1419 };
1420
1421 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1422 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1423
1424 if old_focused_filtered != new_focused_filtered {
1425 if let Some(elem) = &old_focused_filtered {
1426 let node = elem.upcast::<Node>();
1427 elem.set_focus_state(false);
1428 if node.is_connected() {
1430 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1431 }
1432 }
1433 }
1434
1435 if old_focus_state != new_focus_state && !new_focus_state {
1436 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1437 }
1438
1439 self.focused.set(new_focused.as_deref());
1440 self.has_focus.set(new_focus_state);
1441
1442 if old_focus_state != new_focus_state && new_focus_state {
1443 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1444 }
1445
1446 if old_focused_filtered != new_focused_filtered {
1447 if let Some(elem) = &new_focused_filtered {
1448 elem.set_focus_state(true);
1449 let node = elem.upcast::<Node>();
1450 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1452
1453 if !prevent_scroll {
1457 elem.ScrollIntoView(BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(
1458 ScrollIntoViewOptions {
1459 parent: ScrollOptions {
1460 behavior: ScrollBehavior::Smooth,
1461 },
1462 block: ScrollLogicalPosition::Center,
1463 inline: ScrollLogicalPosition::Center,
1464 container: ScrollIntoViewContainer::All,
1465 },
1466 ));
1467 }
1468 }
1469 }
1470
1471 if focus_initiator != FocusInitiator::Local {
1472 return;
1473 }
1474
1475 match (old_focus_state, new_focus_state) {
1478 (_, true) => {
1479 let child_browsing_context_id = new_focused
1500 .as_ref()
1501 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1502 .and_then(|iframe| iframe.browsing_context_id());
1503
1504 let sequence = self.increment_fetch_focus_sequence();
1505
1506 debug!(
1507 "Advertising the focus request to the constellation \
1508 with sequence number {} and child BC ID {}",
1509 sequence,
1510 child_browsing_context_id
1511 .as_ref()
1512 .map(|id| id as &dyn std::fmt::Display)
1513 .unwrap_or(&"(none)"),
1514 );
1515
1516 self.window()
1517 .send_to_constellation(ScriptToConstellationMessage::Focus(
1518 child_browsing_context_id,
1519 sequence,
1520 ));
1521 },
1522 (false, false) => {
1523 },
1526 (true, false) => {
1527 unreachable!(
1528 "Can't lose the document's focus without specifying \
1529 another one to focus"
1530 );
1531 },
1532 }
1533 }
1534
1535 pub(crate) fn title_changed(&self) {
1537 if self.browsing_context().is_some() {
1538 self.send_title_to_embedder();
1539 let title = String::from(self.Title());
1540 self.window
1541 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1542 self.window.pipeline_id(),
1543 title.clone(),
1544 ));
1545 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1546 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1547 self.window.pipeline_id(),
1548 title,
1549 ));
1550 }
1551 }
1552 }
1553
1554 fn title(&self) -> Option<DOMString> {
1558 let title = self.GetDocumentElement().and_then(|root| {
1559 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1560 root.upcast::<Node>()
1562 .child_elements()
1563 .find(|node| {
1564 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1565 })
1566 .map(DomRoot::upcast::<Node>)
1567 } else {
1568 root.upcast::<Node>()
1570 .traverse_preorder(ShadowIncluding::No)
1571 .find(|node| node.is::<HTMLTitleElement>())
1572 }
1573 });
1574
1575 title.map(|title| {
1576 let value = title.child_text_content();
1578 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1579 })
1580 }
1581
1582 pub(crate) fn send_title_to_embedder(&self) {
1584 let window = self.window();
1585 if window.is_top_level() {
1586 let title = self.title().map(String::from);
1587 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1588 }
1589 }
1590
1591 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1592 let window = self.window();
1593 window.send_to_embedder(msg);
1594 }
1595
1596 pub(crate) fn dirty_all_nodes(&self) {
1597 let root = match self.GetDocumentElement() {
1598 Some(root) => root,
1599 None => return,
1600 };
1601 for node in root
1602 .upcast::<Node>()
1603 .traverse_preorder(ShadowIncluding::Yes)
1604 {
1605 node.dirty(NodeDamage::Other)
1606 }
1607 }
1608
1609 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1611 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1623 for target in notify_list.iter() {
1624 if target.downcast::<Document>().is_some() {
1625 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1628 } else if target.downcast::<Element>().is_some() {
1629 target.fire_event(Atom::from("scroll"), can_gc);
1632 }
1633 }
1634
1635 }
1639
1640 pub(crate) fn handle_viewport_scroll_event(&self) {
1644 let target = self.upcast::<EventTarget>();
1653 if self
1654 .pending_scroll_event_targets
1655 .borrow()
1656 .iter()
1657 .any(|other_target| *other_target == target)
1658 {
1659 return;
1660 }
1661
1662 self.pending_scroll_event_targets
1665 .borrow_mut()
1666 .push(Dom::from_ref(target));
1667 }
1668
1669 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1673 let target = element.upcast::<EventTarget>();
1683 if self
1684 .pending_scroll_event_targets
1685 .borrow()
1686 .iter()
1687 .any(|other_target| *other_target == target)
1688 {
1689 return;
1690 }
1691
1692 self.pending_scroll_event_targets
1695 .borrow_mut()
1696 .push(Dom::from_ref(target));
1697 }
1698
1699 pub(crate) fn node_from_nodes_and_strings(
1701 &self,
1702 mut nodes: Vec<NodeOrString>,
1703 can_gc: CanGc,
1704 ) -> Fallible<DomRoot<Node>> {
1705 if nodes.len() == 1 {
1706 Ok(match nodes.pop().unwrap() {
1707 NodeOrString::Node(node) => node,
1708 NodeOrString::String(string) => {
1709 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1710 },
1711 })
1712 } else {
1713 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1714 for node in nodes {
1715 match node {
1716 NodeOrString::Node(node) => {
1717 fragment.AppendChild(&node, can_gc)?;
1718 },
1719 NodeOrString::String(string) => {
1720 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1721 fragment.AppendChild(&node, can_gc).unwrap();
1724 },
1725 }
1726 }
1727 Ok(fragment)
1728 }
1729 }
1730
1731 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1732 match self.GetBody() {
1733 Some(ref body) if body.is_body_element() => {
1734 body.upcast::<Element>().get_string_attribute(local_name)
1735 },
1736 _ => DOMString::new(),
1737 }
1738 }
1739
1740 pub(crate) fn set_body_attribute(
1741 &self,
1742 local_name: &LocalName,
1743 value: DOMString,
1744 can_gc: CanGc,
1745 ) {
1746 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1747 let body = body.upcast::<Element>();
1748 let value = body.parse_attribute(&ns!(), local_name, value);
1749 body.set_attribute(local_name, value, can_gc);
1750 }
1751 }
1752
1753 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1754 self.current_script.set(script);
1755 }
1756
1757 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1758 self.script_blocking_stylesheets_count.get()
1759 }
1760
1761 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1762 let count_cell = &self.script_blocking_stylesheets_count;
1763 count_cell.set(count_cell.get() + 1);
1764 }
1765
1766 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1767 let count_cell = &self.script_blocking_stylesheets_count;
1768 assert!(count_cell.get() > 0);
1769 count_cell.set(count_cell.get() - 1);
1770 }
1771
1772 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1773 self.render_blocking_element_count.get()
1774 }
1775
1776 pub(crate) fn increment_render_blocking_element_count(&self) {
1777 let count_cell = &self.render_blocking_element_count;
1778 count_cell.set(count_cell.get() + 1);
1779 }
1780
1781 pub(crate) fn decrement_render_blocking_element_count(&self) {
1782 let count_cell = &self.render_blocking_element_count;
1783 assert!(count_cell.get() > 0);
1784 count_cell.set(count_cell.get() - 1);
1785 }
1786
1787 pub(crate) fn invalidate_stylesheets(&self) {
1788 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1789
1790 if let Some(element) = self.GetDocumentElement() {
1794 element.upcast::<Node>().dirty(NodeDamage::Style);
1795 }
1796 }
1797
1798 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1801 !self.animation_frame_list.borrow().is_empty()
1802 }
1803
1804 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1806 let ident = self.animation_frame_ident.get() + 1;
1807 self.animation_frame_ident.set(ident);
1808
1809 let had_animation_frame_callbacks;
1810 {
1811 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1812 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1813 animation_frame_list.push_back((ident, Some(callback)));
1814 }
1815
1816 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1822 self.window().send_to_constellation(
1823 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1824 AnimationState::AnimationCallbacksPresent,
1825 ),
1826 );
1827 }
1828
1829 ident
1830 }
1831
1832 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1834 let mut list = self.animation_frame_list.borrow_mut();
1835 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1836 pair.1 = None;
1837 }
1838 }
1839
1840 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1842 let _realm = enter_realm(self);
1843
1844 self.running_animation_callbacks.set(true);
1845 let timing = self.global().performance().Now();
1846
1847 let num_callbacks = self.animation_frame_list.borrow().len();
1848 for _ in 0..num_callbacks {
1849 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1850 if let Some(callback) = maybe_callback {
1851 callback.call(self, *timing, can_gc);
1852 }
1853 }
1854 self.running_animation_callbacks.set(false);
1855
1856 if self.animation_frame_list.borrow().is_empty() {
1857 self.window().send_to_constellation(
1858 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1859 AnimationState::NoAnimationCallbacksPresent,
1860 ),
1861 );
1862 }
1863 }
1864
1865 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1866 self.policy_container.borrow()
1867 }
1868
1869 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1870 *self.policy_container.borrow_mut() = policy_container;
1871 }
1872
1873 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1874 self.policy_container.borrow_mut().set_csp_list(csp_list);
1875 }
1876
1877 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1878 self.policy_container.borrow().csp_list.clone()
1879 }
1880
1881 pub(crate) fn preloaded_resources(&self) -> PreloadedResources {
1882 self.preloaded_resources.clone()
1883 }
1884
1885 pub(crate) fn prepare_request(&self, request: RequestBuilder) -> RequestBuilder {
1889 request
1890 .policy_container(self.policy_container().to_owned())
1891 .https_state(self.https_state.get())
1892 }
1893
1894 pub(crate) fn fetch<Listener: FetchResponseListener>(
1895 &self,
1896 load: LoadType,
1897 mut request: RequestBuilder,
1898 listener: Listener,
1899 ) {
1900 request = request
1901 .insecure_requests_policy(self.insecure_requests_policy())
1902 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1903 let callback = NetworkListener {
1904 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1905 task_source: self
1906 .owner_global()
1907 .task_manager()
1908 .networking_task_source()
1909 .into(),
1910 }
1911 .into_callback();
1912 self.loader_mut()
1913 .fetch_async_with_callback(load, request, callback);
1914 }
1915
1916 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1917 &self,
1918 mut request: RequestBuilder,
1919 listener: Listener,
1920 ) {
1921 request = request
1922 .insecure_requests_policy(self.insecure_requests_policy())
1923 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1924 let callback = NetworkListener {
1925 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1926 task_source: self
1927 .owner_global()
1928 .task_manager()
1929 .networking_task_source()
1930 .into(),
1931 }
1932 .into_callback();
1933 self.loader_mut().fetch_async_background(request, callback);
1934 }
1935
1936 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
1939 debug!("Document got finish_load: {:?}", load);
1941 self.loader.borrow_mut().finish_load(&load);
1942
1943 match load {
1944 LoadType::Stylesheet(_) => {
1945 self.process_pending_parsing_blocking_script(can_gc);
1948
1949 self.process_deferred_scripts(can_gc);
1951 },
1952 LoadType::PageSource(_) => {
1953 if self.has_browsing_context && self.is_fully_active() {
1956 self.window().allow_layout_if_necessary();
1957 }
1958
1959 self.process_deferred_scripts(can_gc);
1964 },
1965 _ => {},
1966 }
1967
1968 let loader = self.loader.borrow();
1975
1976 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1978 update_with_current_instant(&self.top_level_dom_complete);
1979 }
1980
1981 if loader.is_blocked() || loader.events_inhibited() {
1982 return;
1984 }
1985
1986 ScriptThread::mark_document_with_no_blocked_loads(self);
1987 }
1988
1989 pub(crate) fn prompt_to_unload(&self, recursive_flag: bool, can_gc: CanGc) -> bool {
1991 self.incr_ignore_opens_during_unload_counter();
1994 let beforeunload_event = BeforeUnloadEvent::new(
1996 &self.window,
1997 atom!("beforeunload"),
1998 EventBubbles::Bubbles,
1999 EventCancelable::Cancelable,
2000 can_gc,
2001 );
2002 let event = beforeunload_event.upcast::<Event>();
2003 event.set_trusted(true);
2004 let event_target = self.window.upcast::<EventTarget>();
2005 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2006 self.window
2007 .dispatch_event_with_target_override(event, can_gc);
2008 if has_listeners {
2011 self.salvageable.set(false);
2012 }
2013 let mut can_unload = true;
2014 let default_prevented = event.DefaultPrevented();
2016 let return_value_not_empty = !event
2017 .downcast::<BeforeUnloadEvent>()
2018 .unwrap()
2019 .ReturnValue()
2020 .is_empty();
2021 if default_prevented || return_value_not_empty {
2022 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2023 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2024 self.send_to_embedder(msg);
2025 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2026 }
2027 if !recursive_flag {
2029 let iframes: Vec<_> = self.iframes().iter().collect();
2032 for iframe in &iframes {
2033 let document = iframe.owner_document();
2035 can_unload = document.prompt_to_unload(true, can_gc);
2036 if !document.salvageable() {
2037 self.salvageable.set(false);
2038 }
2039 if !can_unload {
2040 break;
2041 }
2042 }
2043 }
2044 self.decr_ignore_opens_during_unload_counter();
2046 can_unload
2047 }
2048
2049 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2051 self.incr_ignore_opens_during_unload_counter();
2054 if self.page_showing.get() {
2056 self.page_showing.set(false);
2058 let event = PageTransitionEvent::new(
2061 &self.window,
2062 atom!("pagehide"),
2063 false, false, self.salvageable.get(), can_gc,
2067 );
2068 let event = event.upcast::<Event>();
2069 event.set_trusted(true);
2070 self.window
2071 .dispatch_event_with_target_override(event, can_gc);
2072 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2074 }
2075 if !self.fired_unload.get() {
2077 let event = Event::new(
2078 self.window.upcast(),
2079 atom!("unload"),
2080 EventBubbles::Bubbles,
2081 EventCancelable::Cancelable,
2082 can_gc,
2083 );
2084 event.set_trusted(true);
2085 let event_target = self.window.upcast::<EventTarget>();
2086 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2087 self.window
2088 .dispatch_event_with_target_override(&event, can_gc);
2089 self.fired_unload.set(true);
2090 if has_listeners {
2092 self.salvageable.set(false);
2093 }
2094 }
2095 if !recursive_flag {
2099 let iframes: Vec<_> = self.iframes().iter().collect();
2102 for iframe in &iframes {
2103 let document = iframe.owner_document();
2105 document.unload(true, can_gc);
2106 if !document.salvageable() {
2107 self.salvageable.set(false);
2108 }
2109 }
2110 }
2111
2112 self.unloading_cleanup_steps();
2114
2115 self.window.as_global_scope().clean_up_all_file_resources();
2117
2118 self.decr_ignore_opens_during_unload_counter();
2120 }
2121
2122 pub(crate) fn maybe_queue_document_completion(&self) {
2124 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2126 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2127 None => false,
2128 };
2129
2130 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2135 !self.is_fully_active() ||
2136 is_in_delaying_load_events_mode;
2137
2138 if not_ready_for_load {
2139 return;
2141 }
2142
2143 assert!(!self.loader.borrow().events_inhibited());
2144 self.loader.borrow_mut().inhibit_events();
2145
2146 debug!("Document loads are complete.");
2149 let document = Trusted::new(self);
2150 self.owner_global()
2151 .task_manager()
2152 .dom_manipulation_task_source()
2153 .queue(task!(fire_load_event: move || {
2154 let document = document.root();
2155 let window = document.window();
2156 if !window.is_alive() {
2157 return;
2158 }
2159
2160 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2162
2163 if document.browsing_context().is_none() {
2165 return;
2166 }
2167 let event = Event::new(
2168 window.upcast(),
2169 atom!("load"),
2170 EventBubbles::DoesNotBubble,
2171 EventCancelable::NotCancelable,
2172 CanGc::note(),
2173 );
2174 event.set_trusted(true);
2175
2176 update_with_current_instant(&document.load_event_start);
2178
2179 debug!("About to dispatch load for {:?}", document.url());
2180 window.dispatch_event_with_target_override(&event, CanGc::note());
2181
2182 update_with_current_instant(&document.load_event_end);
2184
2185 if let Some(fragment) = document.url().fragment() {
2186 document.check_and_scroll_fragment(fragment);
2187 }
2188 }));
2189
2190 let document = Trusted::new(self);
2192 if document.root().browsing_context().is_some() {
2193 self.owner_global()
2194 .task_manager()
2195 .dom_manipulation_task_source()
2196 .queue(task!(fire_pageshow_event: move || {
2197 let document = document.root();
2198 let window = document.window();
2199 if document.page_showing.get() || !window.is_alive() {
2200 return;
2201 }
2202
2203 document.page_showing.set(true);
2204
2205 let event = PageTransitionEvent::new(
2206 window,
2207 atom!("pageshow"),
2208 false, false, false, CanGc::note(),
2212 );
2213 let event = event.upcast::<Event>();
2214 event.set_trusted(true);
2215
2216 window.dispatch_event_with_target_override(event, CanGc::note());
2217 }));
2218 }
2219
2220 #[cfg(feature = "webxr")]
2235 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2236 self.window.Navigator().Xr().dispatch_sessionavailable();
2237 }
2238
2239 let document = Trusted::new(self);
2243 if document.root().browsing_context().is_some() {
2244 self.owner_global()
2245 .task_manager()
2246 .dom_manipulation_task_source()
2247 .queue(task!(completely_loaded: move || {
2248 let document = document.root();
2249 document.completely_loaded.set(true);
2250 if let Some(DeclarativeRefresh::PendingLoad {
2251 url,
2252 time
2253 }) = &*document.declarative_refresh.borrow() {
2254 document.window.as_global_scope().schedule_callback(
2256 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2257 window: DomRoot::from_ref(document.window()),
2258 url: url.clone(),
2259 }),
2260 Duration::from_secs(*time),
2261 );
2262 }
2263 document.notify_constellation_load();
2266 }));
2267 }
2268 }
2269
2270 pub(crate) fn completely_loaded(&self) -> bool {
2271 self.completely_loaded.get()
2272 }
2273
2274 pub(crate) fn set_pending_parsing_blocking_script(
2276 &self,
2277 script: &HTMLScriptElement,
2278 load: Option<ScriptResult>,
2279 ) {
2280 assert!(!self.has_pending_parsing_blocking_script());
2281 *self.pending_parsing_blocking_script.borrow_mut() =
2282 Some(PendingScript::new_with_load(script, load));
2283 }
2284
2285 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2287 self.pending_parsing_blocking_script.borrow().is_some()
2288 }
2289
2290 pub(crate) fn pending_parsing_blocking_script_loaded(
2292 &self,
2293 element: &HTMLScriptElement,
2294 result: ScriptResult,
2295 can_gc: CanGc,
2296 ) {
2297 {
2298 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2299 let entry = blocking_script.as_mut().unwrap();
2300 assert!(&*entry.element == element);
2301 entry.loaded(result);
2302 }
2303 self.process_pending_parsing_blocking_script(can_gc);
2304 }
2305
2306 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2307 if self.script_blocking_stylesheets_count.get() > 0 {
2308 return;
2309 }
2310 let pair = self
2311 .pending_parsing_blocking_script
2312 .borrow_mut()
2313 .as_mut()
2314 .and_then(PendingScript::take_result);
2315 if let Some((element, result)) = pair {
2316 *self.pending_parsing_blocking_script.borrow_mut() = None;
2317 self.get_current_parser()
2318 .unwrap()
2319 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2320 }
2321 }
2322
2323 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2325 self.asap_scripts_set
2326 .borrow_mut()
2327 .push(Dom::from_ref(script));
2328 }
2329
2330 pub(crate) fn asap_script_loaded(
2333 &self,
2334 element: &HTMLScriptElement,
2335 result: ScriptResult,
2336 can_gc: CanGc,
2337 ) {
2338 {
2339 let mut scripts = self.asap_scripts_set.borrow_mut();
2340 let idx = scripts
2341 .iter()
2342 .position(|entry| &**entry == element)
2343 .unwrap();
2344 scripts.swap_remove(idx);
2345 }
2346 element.execute(result, can_gc);
2347 }
2348
2349 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2351 self.asap_in_order_scripts_list.push(script);
2352 }
2353
2354 pub(crate) fn asap_in_order_script_loaded(
2357 &self,
2358 element: &HTMLScriptElement,
2359 result: ScriptResult,
2360 can_gc: CanGc,
2361 ) {
2362 self.asap_in_order_scripts_list.loaded(element, result);
2363 while let Some((element, result)) = self
2364 .asap_in_order_scripts_list
2365 .take_next_ready_to_be_executed()
2366 {
2367 element.execute(result, can_gc);
2368 }
2369 }
2370
2371 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2373 self.deferred_scripts.push(script);
2374 }
2375
2376 pub(crate) fn deferred_script_loaded(
2379 &self,
2380 element: &HTMLScriptElement,
2381 result: ScriptResult,
2382 can_gc: CanGc,
2383 ) {
2384 self.deferred_scripts.loaded(element, result);
2385 self.process_deferred_scripts(can_gc);
2386 }
2387
2388 fn process_deferred_scripts(&self, can_gc: CanGc) {
2390 if self.ready_state.get() != DocumentReadyState::Interactive {
2391 return;
2392 }
2393 loop {
2395 if self.script_blocking_stylesheets_count.get() > 0 {
2396 return;
2397 }
2398 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2399 {
2400 element.execute(result, can_gc);
2401 } else {
2402 break;
2403 }
2404 }
2405 if self.deferred_scripts.is_empty() {
2406 self.maybe_dispatch_dom_content_loaded();
2408 }
2409 }
2410
2411 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2413 if self.domcontentloaded_dispatched.get() {
2414 return;
2415 }
2416 self.domcontentloaded_dispatched.set(true);
2417 assert_ne!(
2418 self.ReadyState(),
2419 DocumentReadyState::Complete,
2420 "Complete before DOMContentLoaded?"
2421 );
2422
2423 update_with_current_instant(&self.dom_content_loaded_event_start);
2424
2425 let document = Trusted::new(self);
2427 self.owner_global()
2428 .task_manager()
2429 .dom_manipulation_task_source()
2430 .queue(
2431 task!(fire_dom_content_loaded_event: move || {
2432 let document = document.root();
2433 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2434 update_with_current_instant(&document.dom_content_loaded_event_end);
2435 })
2436 );
2437
2438 self.interactive_time
2440 .borrow()
2441 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2442
2443 }
2446
2447 pub(crate) fn abort(&self, can_gc: CanGc) {
2449 self.loader.borrow_mut().inhibit_events();
2451
2452 for iframe in self.iframes().iter() {
2454 if let Some(document) = iframe.GetContentDocument() {
2455 document.abort(can_gc);
2457 }
2459 }
2460
2461 self.script_blocking_stylesheets_count.set(0);
2463 *self.pending_parsing_blocking_script.borrow_mut() = None;
2464 *self.asap_scripts_set.borrow_mut() = vec![];
2465 self.asap_in_order_scripts_list.clear();
2466 self.deferred_scripts.clear();
2467 let loads_cancelled = self.loader.borrow_mut().cancel_all_loads();
2468 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2469 if loads_cancelled || event_sources_canceled {
2470 self.salvageable.set(false);
2472 };
2473
2474 self.owner_global()
2479 .task_manager()
2480 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2481
2482 if let Some(parser) = self.get_current_parser() {
2484 self.active_parser_was_aborted.set(true);
2485 parser.abort(can_gc);
2486 self.salvageable.set(false);
2487 }
2488 }
2489
2490 pub(crate) fn notify_constellation_load(&self) {
2491 self.window()
2492 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2493 }
2494
2495 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2496 self.current_parser.set(script);
2497 }
2498
2499 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2500 self.current_parser.get()
2501 }
2502
2503 pub(crate) fn get_current_parser_line(&self) -> u32 {
2504 self.get_current_parser()
2505 .map(|parser| parser.get_current_line())
2506 .unwrap_or(0)
2507 }
2508
2509 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2512 self.iframes.borrow_mut().validate(self);
2513 self.iframes.borrow()
2514 }
2515
2516 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2519 self.iframes.borrow_mut().validate(self);
2520 self.iframes.borrow_mut()
2521 }
2522
2523 pub(crate) fn invalidate_iframes_collection(&self) {
2524 self.iframes.borrow_mut().invalidate();
2525 }
2526
2527 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2528 self.dom_interactive.get()
2529 }
2530
2531 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2532 self.interactive_time
2533 .borrow_mut()
2534 .set_navigation_start(navigation_start);
2535 }
2536
2537 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2538 self.interactive_time.borrow()
2539 }
2540
2541 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2542 self.get_interactive_metrics().get_tti().is_some()
2543 }
2544
2545 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2546 self.dom_content_loaded_event_start.get()
2547 }
2548
2549 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2550 self.dom_content_loaded_event_end.get()
2551 }
2552
2553 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2554 self.dom_complete.get()
2555 }
2556
2557 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2558 self.top_level_dom_complete.get()
2559 }
2560
2561 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2562 self.load_event_start.get()
2563 }
2564
2565 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2566 self.load_event_end.get()
2567 }
2568
2569 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2570 self.unload_event_start.get()
2571 }
2572
2573 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2574 self.unload_event_end.get()
2575 }
2576
2577 pub(crate) fn start_tti(&self) {
2578 if self.get_interactive_metrics().needs_tti() {
2579 self.tti_window.borrow_mut().start_window();
2580 }
2581 }
2582
2583 pub(crate) fn record_tti_if_necessary(&self) {
2587 if self.has_recorded_tti_metric() {
2588 return;
2589 }
2590 if self.tti_window.borrow().needs_check() {
2591 self.get_interactive_metrics()
2592 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2593 self.tti_window.borrow().get_start(),
2594 ));
2595 }
2596 }
2597
2598 fn fire_focus_event(
2600 &self,
2601 focus_event_type: FocusEventType,
2602 event_target: &EventTarget,
2603 related_target: Option<&EventTarget>,
2604 can_gc: CanGc,
2605 ) {
2606 let (event_name, does_bubble) = match focus_event_type {
2607 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2608 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2609 };
2610 let event = FocusEvent::new(
2611 &self.window,
2612 event_name,
2613 does_bubble,
2614 EventCancelable::NotCancelable,
2615 Some(&self.window),
2616 0i32,
2617 related_target,
2618 can_gc,
2619 );
2620 let event = event.upcast::<Event>();
2621 event.set_trusted(true);
2622 event.fire(event_target, can_gc);
2623 }
2624
2625 pub(crate) fn is_cookie_averse(&self) -> bool {
2627 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2628 }
2629
2630 pub(crate) fn lookup_custom_element_definition(
2632 &self,
2633 namespace: &Namespace,
2634 local_name: &LocalName,
2635 is: Option<&LocalName>,
2636 ) -> Option<Rc<CustomElementDefinition>> {
2637 if !pref!(dom_customelements_enabled) {
2638 return None;
2639 }
2640
2641 if *namespace != ns!(html) {
2643 return None;
2644 }
2645
2646 if !self.has_browsing_context {
2648 return None;
2649 }
2650
2651 let registry = self.window.CustomElements();
2653
2654 registry.lookup_definition(local_name, is)
2655 }
2656
2657 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2658 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2659 self.throw_on_dynamic_markup_insertion_counter
2660 .set(counter + 1);
2661 }
2662
2663 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2664 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2665 self.throw_on_dynamic_markup_insertion_counter
2666 .set(counter - 1);
2667 }
2668
2669 pub(crate) fn react_to_environment_changes(&self) {
2670 for image in self.responsive_images.borrow().iter() {
2671 image.react_to_environment_changes();
2672 }
2673 }
2674
2675 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2676 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2677 }
2678
2679 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2680 let index = self
2681 .responsive_images
2682 .borrow()
2683 .iter()
2684 .position(|x| **x == *img);
2685 if let Some(i) = index {
2686 self.responsive_images.borrow_mut().remove(i);
2687 }
2688 }
2689
2690 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
2691 let did_have_these_media_controls = self
2692 .media_controls
2693 .borrow_mut()
2694 .insert(id.to_string(), Dom::from_ref(controls))
2695 .is_some();
2696 debug_assert!(
2697 !did_have_these_media_controls,
2698 "Trying to register known media controls"
2699 );
2700 }
2701
2702 pub(crate) fn unregister_media_controls(&self, id: &str) {
2703 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2704 debug_assert!(
2705 did_have_these_media_controls,
2706 "Trying to unregister unknown media controls"
2707 );
2708 }
2709
2710 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
2711 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
2712 if dirty_canvases
2713 .iter()
2714 .any(|dirty_canvas| dirty_canvas == canvas)
2715 {
2716 return;
2717 }
2718 dirty_canvases.push(canvas.clone());
2719 }
2720
2721 pub(crate) fn needs_rendering_update(&self) -> bool {
2725 if !self.is_fully_active() {
2726 return false;
2727 }
2728 if !self.window().layout_blocked() &&
2729 (!self.restyle_reason().is_empty() ||
2730 self.window().layout().needs_new_display_list())
2731 {
2732 return true;
2733 }
2734 if !self.rendering_update_reasons.get().is_empty() {
2735 return true;
2736 }
2737 if self.event_handler.has_pending_input_events() {
2738 return true;
2739 }
2740 if self.has_pending_scroll_events() {
2741 return true;
2742 }
2743 if self.window().has_unhandled_resize_event() {
2744 return true;
2745 }
2746 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
2747 {
2748 return true;
2749 }
2750
2751 false
2752 }
2753
2754 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
2762 if self.render_blocking_element_count() > 0 {
2763 return Default::default();
2764 }
2765
2766 let mut results = ReflowPhasesRun::empty();
2767 if self.has_pending_animated_image_update.get() {
2768 self.image_animation_manager
2769 .borrow()
2770 .update_active_frames(&self.window, self.current_animation_timeline_value());
2771 self.has_pending_animated_image_update.set(false);
2772 results.insert(ReflowPhasesRun::UpdatedImageData);
2773 }
2774
2775 self.current_rendering_epoch
2776 .set(self.current_rendering_epoch.get().next());
2777 let current_rendering_epoch = self.current_rendering_epoch.get();
2778
2779 let image_keys: Vec<_> = self
2781 .dirty_canvases
2782 .borrow_mut()
2783 .drain(..)
2784 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
2785 .collect();
2786
2787 let pipeline_id = self.window().pipeline_id();
2790 if !image_keys.is_empty() {
2791 results.insert(ReflowPhasesRun::UpdatedImageData);
2792 self.waiting_on_canvas_image_updates.set(true);
2793 self.window().compositor_api().delay_new_frame_for_canvas(
2794 self.window().pipeline_id(),
2795 current_rendering_epoch,
2796 image_keys,
2797 );
2798 }
2799
2800 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
2801
2802 self.window().compositor_api().update_epoch(
2803 self.webview_id(),
2804 pipeline_id,
2805 current_rendering_epoch,
2806 );
2807
2808 results
2809 }
2810
2811 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2812 self.waiting_on_canvas_image_updates.set(false);
2813 }
2814
2815 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2816 self.waiting_on_canvas_image_updates.get()
2817 }
2818
2819 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2829 if !self.is_fully_active() {
2830 return false;
2831 }
2832
2833 let fonts = self.Fonts(can_gc);
2834 if !fonts.waiting_to_fullfill_promise() {
2835 return false;
2836 }
2837 if self.window().font_context().web_fonts_still_loading() != 0 {
2838 return false;
2839 }
2840 if self.ReadyState() != DocumentReadyState::Complete {
2841 return false;
2842 }
2843 if !self.restyle_reason().is_empty() {
2844 return false;
2845 }
2846 if !self.rendering_update_reasons.get().is_empty() {
2847 return false;
2848 }
2849
2850 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
2851
2852 if result {
2856 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
2857 }
2858
2859 result
2860 }
2861
2862 pub(crate) fn id_map(
2863 &self,
2864 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2865 self.id_map.borrow()
2866 }
2867
2868 pub(crate) fn name_map(
2869 &self,
2870 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2871 self.name_map.borrow()
2872 }
2873
2874 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
2876 self.resize_observers
2877 .borrow_mut()
2878 .push(Dom::from_ref(resize_observer));
2879 }
2880
2881 pub(crate) fn has_resize_observers(&self) -> bool {
2883 !self.resize_observers.borrow().is_empty()
2884 }
2885
2886 pub(crate) fn gather_active_resize_observations_at_depth(
2889 &self,
2890 depth: &ResizeObservationDepth,
2891 ) -> bool {
2892 let mut has_active_resize_observations = false;
2893 for observer in self.resize_observers.borrow_mut().iter_mut() {
2894 observer.gather_active_resize_observations_at_depth(
2895 depth,
2896 &mut has_active_resize_observations,
2897 );
2898 }
2899 has_active_resize_observations
2900 }
2901
2902 pub(crate) fn broadcast_active_resize_observations(
2904 &self,
2905 can_gc: CanGc,
2906 ) -> ResizeObservationDepth {
2907 let mut shallowest = ResizeObservationDepth::max();
2908 let iterator: Vec<DomRoot<ResizeObserver>> = self
2912 .resize_observers
2913 .borrow()
2914 .iter()
2915 .cloned()
2916 .map(|obs| DomRoot::from_ref(&*obs))
2917 .collect();
2918 for observer in iterator {
2919 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
2920 }
2921 shallowest
2922 }
2923
2924 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
2926 self.resize_observers
2927 .borrow()
2928 .iter()
2929 .any(|observer| observer.has_skipped_resize_observations())
2930 }
2931
2932 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
2934 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
2935 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
2936 ..Default::default()
2937 };
2938 self.window
2939 .as_global_scope()
2940 .report_an_error(error_info, HandleValue::null(), can_gc);
2941 }
2942
2943 pub(crate) fn status_code(&self) -> Option<u16> {
2944 self.status_code
2945 }
2946
2947 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
2949 let encoding = self.encoding.get();
2955
2956 let base_url = self.base_url();
2962
2963 url::Url::options()
2965 .base_url(Some(base_url.as_url()))
2966 .encoding_override(Some(&|input| {
2967 servo_url::encoding::encode_as_url_query_string(input, encoding)
2968 }))
2969 .parse(url)
2970 .map(ServoUrl::from)
2971 }
2972
2973 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
2975 if !self.has_browsing_context {
2977 return false;
2978 }
2979
2980 if !self.is_fully_active() {
2982 return false;
2983 }
2984
2985 true
2991 }
2992
2993 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
2996 self.intersection_observers
2997 .borrow_mut()
2998 .push(Dom::from_ref(intersection_observer));
2999 }
3000
3001 pub(crate) fn remove_intersection_observer(
3005 &self,
3006 intersection_observer: &IntersectionObserver,
3007 ) {
3008 self.intersection_observers
3009 .borrow_mut()
3010 .retain(|observer| *observer != intersection_observer)
3011 }
3012
3013 pub(crate) fn update_intersection_observer_steps(
3015 &self,
3016 time: CrossProcessInstant,
3017 can_gc: CanGc,
3018 ) {
3019 for intersection_observer in &*self.intersection_observers.borrow() {
3021 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3022 }
3023 }
3024
3025 fn update_single_intersection_observer_steps(
3027 &self,
3028 intersection_observer: &IntersectionObserver,
3029 time: CrossProcessInstant,
3030 can_gc: CanGc,
3031 ) {
3032 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3035
3036 intersection_observer.update_intersection_observations_steps(
3040 self,
3041 time,
3042 root_bounds,
3043 can_gc,
3044 );
3045 }
3046
3047 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3049 self.intersection_observer_task_queued.set(false);
3052
3053 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3058
3059 for intersection_observer in notify_list.iter() {
3062 intersection_observer.invoke_callback_if_necessary(can_gc);
3064 }
3065 }
3066
3067 pub(crate) fn queue_an_intersection_observer_task(&self) {
3069 if self.intersection_observer_task_queued.get() {
3072 return;
3073 }
3074
3075 self.intersection_observer_task_queued.set(true);
3078
3079 let document = Trusted::new(self);
3083 self.owner_global()
3084 .task_manager()
3085 .intersection_observer_task_source()
3086 .queue(task!(notify_intersection_observers: move || {
3087 document.root().notify_intersection_observers(CanGc::note());
3088 }));
3089 }
3090
3091 pub(crate) fn handle_paint_metric(
3092 &self,
3093 metric_type: ProgressiveWebMetricType,
3094 metric_value: CrossProcessInstant,
3095 first_reflow: bool,
3096 can_gc: CanGc,
3097 ) {
3098 let metrics = self.interactive_time.borrow();
3099 match metric_type {
3100 ProgressiveWebMetricType::FirstPaint |
3101 ProgressiveWebMetricType::FirstContentfulPaint => {
3102 let binding = PerformancePaintTiming::new(
3103 self.window.as_global_scope(),
3104 metric_type,
3105 metric_value,
3106 can_gc,
3107 );
3108 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3109 let entry = binding.upcast::<PerformanceEntry>();
3110 self.window.Performance().queue_entry(entry, can_gc);
3111 },
3112 ProgressiveWebMetricType::LargestContentfulPaint { area, lcp_type } => {
3113 let binding = LargestContentfulPaint::new(
3114 self.window.as_global_scope(),
3115 metric_type,
3116 metric_value,
3117 can_gc,
3118 );
3119 metrics.set_largest_contentful_paint(metric_value, area, lcp_type);
3120 let entry = binding.upcast::<PerformanceEntry>();
3121 self.window.Performance().queue_entry(entry, can_gc);
3122 },
3123 ProgressiveWebMetricType::TimeToInteractive => {
3124 unreachable!("Unexpected non-paint metric.")
3125 },
3126 }
3127 }
3128
3129 fn write(
3131 &self,
3132 text: Vec<TrustedHTMLOrString>,
3133 line_feed: bool,
3134 containing_class: &str,
3135 field: &str,
3136 can_gc: CanGc,
3137 ) -> ErrorResult {
3138 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3140 let mut is_trusted = true;
3142 for value in text {
3144 match value {
3145 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3147 strings.push(trusted_html.to_string().to_owned());
3148 },
3149 TrustedHTMLOrString::String(str_) => {
3150 is_trusted = false;
3152 strings.push(str_.into());
3154 },
3155 };
3156 }
3157 let mut string = itertools::join(strings, "");
3158 if !is_trusted {
3162 string = TrustedHTML::get_trusted_script_compliant_string(
3163 &self.global(),
3164 TrustedHTMLOrString::String(string.into()),
3165 &format!("{} {}", containing_class, field),
3166 can_gc,
3167 )?
3168 .str()
3169 .to_owned();
3170 }
3171 if line_feed {
3173 string.push('\n');
3174 }
3175 if !self.is_html_document() {
3177 return Err(Error::InvalidState(None));
3178 }
3179
3180 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3183 return Err(Error::InvalidState(None));
3184 }
3185
3186 if !self.is_active() || self.active_parser_was_aborted.get() {
3188 return Ok(());
3189 }
3190
3191 let parser = match self.get_current_parser() {
3192 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3193 _ => {
3195 if self.is_prompting_or_unloading() ||
3198 self.ignore_destructive_writes_counter.get() > 0
3199 {
3200 return Ok(());
3201 }
3202 self.Open(None, None, can_gc)?;
3204 self.get_current_parser().unwrap()
3205 },
3206 };
3207
3208 parser.write(string.into(), can_gc);
3210
3211 Ok(())
3212 }
3213
3214 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3215 RefMut::map(
3216 self.details_name_groups.borrow_mut(),
3217 |details_name_groups| details_name_groups.get_or_insert_default(),
3218 )
3219 }
3220}
3221
3222#[derive(MallocSizeOf, PartialEq)]
3223pub(crate) enum DocumentSource {
3224 FromParser,
3225 NotFromParser,
3226}
3227
3228pub(crate) trait LayoutDocumentHelpers<'dom> {
3229 fn is_html_document_for_layout(&self) -> bool;
3230 fn quirks_mode(self) -> QuirksMode;
3231 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3232 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3233 fn shadow_roots_styles_changed(self) -> bool;
3234 fn flush_shadow_roots_stylesheets(self);
3235}
3236
3237#[expect(unsafe_code)]
3238impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3239 #[inline]
3240 fn is_html_document_for_layout(&self) -> bool {
3241 self.unsafe_get().is_html_document
3242 }
3243
3244 #[inline]
3245 fn quirks_mode(self) -> QuirksMode {
3246 self.unsafe_get().quirks_mode.get()
3247 }
3248
3249 #[inline]
3250 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3251 self.unsafe_get().style_shared_lock()
3252 }
3253
3254 #[inline]
3255 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3256 unsafe {
3261 self.unsafe_get()
3262 .shadow_roots
3263 .borrow_for_layout()
3264 .iter()
3265 .map(|sr| sr.to_layout())
3266 .collect()
3267 }
3268 }
3269
3270 #[inline]
3271 fn shadow_roots_styles_changed(self) -> bool {
3272 self.unsafe_get().shadow_roots_styles_changed.get()
3273 }
3274
3275 #[inline]
3276 fn flush_shadow_roots_stylesheets(self) {
3277 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3278 }
3279}
3280
3281fn get_registrable_domain_suffix_of_or_is_equal_to(
3285 host_suffix_string: &DOMString,
3286 original_host: Host,
3287) -> Option<Host> {
3288 if host_suffix_string.is_empty() {
3290 return None;
3291 }
3292
3293 let host = match Host::parse(&host_suffix_string.str()) {
3295 Ok(host) => host,
3296 Err(_) => return None,
3297 };
3298
3299 if host != original_host {
3301 let host = match host {
3303 Host::Domain(ref host) => host,
3304 _ => return None,
3305 };
3306 let original_host = match original_host {
3307 Host::Domain(ref original_host) => original_host,
3308 _ => return None,
3309 };
3310
3311 let index = original_host.len().checked_sub(host.len())?;
3313 let (prefix, suffix) = original_host.split_at(index);
3314
3315 if !prefix.ends_with('.') {
3316 return None;
3317 }
3318 if suffix != host {
3319 return None;
3320 }
3321
3322 if is_pub_domain(host) {
3324 return None;
3325 }
3326 }
3327
3328 Some(host)
3330}
3331
3332fn url_has_network_scheme(url: &ServoUrl) -> bool {
3334 matches!(url.scheme(), "ftp" | "http" | "https")
3335}
3336
3337#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3338pub(crate) enum HasBrowsingContext {
3339 No,
3340 Yes,
3341}
3342
3343impl Document {
3344 #[allow(clippy::too_many_arguments)]
3345 pub(crate) fn new_inherited(
3346 window: &Window,
3347 has_browsing_context: HasBrowsingContext,
3348 url: Option<ServoUrl>,
3349 origin: MutableOrigin,
3350 is_html_document: IsHTMLDocument,
3351 content_type: Option<Mime>,
3352 last_modified: Option<String>,
3353 activity: DocumentActivity,
3354 source: DocumentSource,
3355 doc_loader: DocumentLoader,
3356 referrer: Option<String>,
3357 status_code: Option<u16>,
3358 canceller: FetchCanceller,
3359 is_initial_about_blank: bool,
3360 allow_declarative_shadow_roots: bool,
3361 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3362 has_trustworthy_ancestor_origin: bool,
3363 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3364 creation_sandboxing_flag_set: SandboxingFlagSet,
3365 ) -> Document {
3366 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3367
3368 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3369 (DocumentReadyState::Loading, false)
3370 } else {
3371 (DocumentReadyState::Complete, true)
3372 };
3373
3374 let frame_type = match window.is_top_level() {
3375 true => TimerMetadataFrameType::RootWindow,
3376 false => TimerMetadataFrameType::IFrame,
3377 };
3378 let interactive_time = ProgressiveWebMetrics::new(
3379 window.time_profiler_chan().clone(),
3380 url.clone(),
3381 frame_type,
3382 );
3383
3384 let content_type = content_type.unwrap_or_else(|| {
3385 match is_html_document {
3386 IsHTMLDocument::HTMLDocument => "text/html",
3388 IsHTMLDocument::NonHTMLDocument => "application/xml",
3390 }
3391 .parse()
3392 .unwrap()
3393 });
3394
3395 let encoding = content_type
3396 .get_parameter(CHARSET)
3397 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3398 .unwrap_or(UTF_8);
3399
3400 let has_focus = window.parent_info().is_none();
3401
3402 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3403
3404 Document {
3405 node: Node::new_document_node(),
3406 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3407 window: Dom::from_ref(window),
3408 has_browsing_context,
3409 implementation: Default::default(),
3410 content_type,
3411 last_modified,
3412 url: DomRefCell::new(url),
3413 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3415 event_handler: DocumentEventHandler::new(window),
3416 embedder_controls: DocumentEmbedderControls::new(window),
3417 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3418 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3419 encoding: Cell::new(encoding),
3421 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3422 activity: Cell::new(activity),
3423 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3424 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3425 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3426 images: Default::default(),
3427 embeds: Default::default(),
3428 links: Default::default(),
3429 forms: Default::default(),
3430 scripts: Default::default(),
3431 anchors: Default::default(),
3432 applets: Default::default(),
3433 iframes: RefCell::new(IFrameCollection::new()),
3434 style_shared_lock: {
3435 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3442 LazyLock::new(StyleSharedRwLock::new);
3443
3444 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3445 },
3447 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3448 stylesheet_list: MutNullableDom::new(None),
3449 ready_state: Cell::new(ready_state),
3450 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3451 focus_transaction: DomRefCell::new(None),
3452 focused: Default::default(),
3453 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3454 has_focus: Cell::new(has_focus),
3455 current_script: Default::default(),
3456 pending_parsing_blocking_script: Default::default(),
3457 script_blocking_stylesheets_count: Default::default(),
3458 render_blocking_element_count: Default::default(),
3459 deferred_scripts: Default::default(),
3460 asap_in_order_scripts_list: Default::default(),
3461 asap_scripts_set: Default::default(),
3462 animation_frame_ident: Cell::new(0),
3463 animation_frame_list: DomRefCell::new(VecDeque::new()),
3464 running_animation_callbacks: Cell::new(false),
3465 loader: DomRefCell::new(doc_loader),
3466 current_parser: Default::default(),
3467 base_element: Default::default(),
3468 appropriate_template_contents_owner_document: Default::default(),
3469 pending_restyles: DomRefCell::new(FxHashMap::default()),
3470 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3471 dom_interactive: Cell::new(Default::default()),
3472 dom_content_loaded_event_start: Cell::new(Default::default()),
3473 dom_content_loaded_event_end: Cell::new(Default::default()),
3474 dom_complete: Cell::new(Default::default()),
3475 top_level_dom_complete: Cell::new(Default::default()),
3476 load_event_start: Cell::new(Default::default()),
3477 load_event_end: Cell::new(Default::default()),
3478 unload_event_start: Cell::new(Default::default()),
3479 unload_event_end: Cell::new(Default::default()),
3480 https_state: Cell::new(HttpsState::None),
3481 origin,
3482 referrer,
3483 target_element: MutNullableDom::new(None),
3484 policy_container: DomRefCell::new(PolicyContainer::default()),
3485 preloaded_resources: Default::default(),
3486 ignore_destructive_writes_counter: Default::default(),
3487 ignore_opens_during_unload_counter: Default::default(),
3488 spurious_animation_frames: Cell::new(0),
3489 dom_count: Cell::new(1),
3490 fullscreen_element: MutNullableDom::new(None),
3491 form_id_listener_map: Default::default(),
3492 interactive_time: DomRefCell::new(interactive_time),
3493 tti_window: DomRefCell::new(InteractiveWindow::default()),
3494 canceller,
3495 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3496 page_showing: Cell::new(false),
3497 salvageable: Cell::new(true),
3498 active_parser_was_aborted: Cell::new(false),
3499 fired_unload: Cell::new(false),
3500 responsive_images: Default::default(),
3501 redirect_count: Cell::new(0),
3502 completely_loaded: Cell::new(false),
3503 script_and_layout_blockers: Cell::new(0),
3504 delayed_tasks: Default::default(),
3505 shadow_roots: DomRefCell::new(HashSet::new()),
3506 shadow_roots_styles_changed: Cell::new(false),
3507 media_controls: DomRefCell::new(HashMap::new()),
3508 dirty_canvases: DomRefCell::new(Default::default()),
3509 has_pending_animated_image_update: Cell::new(false),
3510 selection: MutNullableDom::new(None),
3511 animation_timeline: if pref!(layout_animations_test_enabled) {
3512 DomRefCell::new(AnimationTimeline::new_for_testing())
3513 } else {
3514 DomRefCell::new(AnimationTimeline::new())
3515 },
3516 animations: Animations::new(),
3517 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3518 dirty_root: Default::default(),
3519 declarative_refresh: Default::default(),
3520 resize_observers: Default::default(),
3521 fonts: Default::default(),
3522 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3523 status_code,
3524 is_initial_about_blank: Cell::new(is_initial_about_blank),
3525 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3526 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3527 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3528 intersection_observer_task_queued: Cell::new(false),
3529 intersection_observers: Default::default(),
3530 highlighted_dom_node: Default::default(),
3531 adopted_stylesheets: Default::default(),
3532 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3533 pending_scroll_event_targets: Default::default(),
3534 rendering_update_reasons: Default::default(),
3535 waiting_on_canvas_image_updates: Cell::new(false),
3536 current_rendering_epoch: Default::default(),
3537 custom_element_reaction_stack,
3538 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3539 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3540 favicon: RefCell::new(None),
3541 websockets: DOMTracker::new(),
3542 details_name_groups: Default::default(),
3543 }
3544 }
3545
3546 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3548 if let Some(csp_list) = self.get_csp_list() {
3549 for policy in &csp_list.0 {
3550 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3551 policy.disposition == PolicyDisposition::Enforce
3552 {
3553 return InsecureRequestsPolicy::Upgrade;
3554 }
3555 }
3556 }
3557
3558 self.inherited_insecure_requests_policy
3559 .get()
3560 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3561 }
3562
3563 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3565 &self.event_handler
3566 }
3567
3568 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3570 &self.embedder_controls
3571 }
3572
3573 fn has_pending_scroll_events(&self) -> bool {
3576 !self.pending_scroll_event_targets.borrow().is_empty()
3577 }
3578
3579 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3582 self.rendering_update_reasons
3583 .set(self.rendering_update_reasons.get().union(reason));
3584 }
3585
3586 pub(crate) fn clear_rendering_update_reasons(&self) {
3588 self.rendering_update_reasons
3589 .set(RenderingUpdateReason::empty())
3590 }
3591
3592 pub(crate) fn add_script_and_layout_blocker(&self) {
3599 self.script_and_layout_blockers
3600 .set(self.script_and_layout_blockers.get() + 1);
3601 }
3602
3603 pub(crate) fn remove_script_and_layout_blocker(&self) {
3607 assert!(self.script_and_layout_blockers.get() > 0);
3608 self.script_and_layout_blockers
3609 .set(self.script_and_layout_blockers.get() - 1);
3610 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3611 {
3612 let task = self.delayed_tasks.borrow_mut().remove(0);
3613 task.run_box();
3614 }
3615 }
3616
3617 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3619 self.delayed_tasks.borrow_mut().push(Box::new(task));
3620 }
3621
3622 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3625 assert_eq!(
3626 self.script_and_layout_blockers.get(),
3627 0,
3628 "Attempt to use script or layout while DOM not in a stable state"
3629 );
3630 }
3631
3632 #[allow(clippy::too_many_arguments)]
3633 pub(crate) fn new(
3634 window: &Window,
3635 has_browsing_context: HasBrowsingContext,
3636 url: Option<ServoUrl>,
3637 origin: MutableOrigin,
3638 doctype: IsHTMLDocument,
3639 content_type: Option<Mime>,
3640 last_modified: Option<String>,
3641 activity: DocumentActivity,
3642 source: DocumentSource,
3643 doc_loader: DocumentLoader,
3644 referrer: Option<String>,
3645 status_code: Option<u16>,
3646 canceller: FetchCanceller,
3647 is_initial_about_blank: bool,
3648 allow_declarative_shadow_roots: bool,
3649 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3650 has_trustworthy_ancestor_origin: bool,
3651 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3652 creation_sandboxing_flag_set: SandboxingFlagSet,
3653 can_gc: CanGc,
3654 ) -> DomRoot<Document> {
3655 Self::new_with_proto(
3656 window,
3657 None,
3658 has_browsing_context,
3659 url,
3660 origin,
3661 doctype,
3662 content_type,
3663 last_modified,
3664 activity,
3665 source,
3666 doc_loader,
3667 referrer,
3668 status_code,
3669 canceller,
3670 is_initial_about_blank,
3671 allow_declarative_shadow_roots,
3672 inherited_insecure_requests_policy,
3673 has_trustworthy_ancestor_origin,
3674 custom_element_reaction_stack,
3675 creation_sandboxing_flag_set,
3676 can_gc,
3677 )
3678 }
3679
3680 #[allow(clippy::too_many_arguments)]
3681 fn new_with_proto(
3682 window: &Window,
3683 proto: Option<HandleObject>,
3684 has_browsing_context: HasBrowsingContext,
3685 url: Option<ServoUrl>,
3686 origin: MutableOrigin,
3687 doctype: IsHTMLDocument,
3688 content_type: Option<Mime>,
3689 last_modified: Option<String>,
3690 activity: DocumentActivity,
3691 source: DocumentSource,
3692 doc_loader: DocumentLoader,
3693 referrer: Option<String>,
3694 status_code: Option<u16>,
3695 canceller: FetchCanceller,
3696 is_initial_about_blank: bool,
3697 allow_declarative_shadow_roots: bool,
3698 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3699 has_trustworthy_ancestor_origin: bool,
3700 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3701 creation_sandboxing_flag_set: SandboxingFlagSet,
3702 can_gc: CanGc,
3703 ) -> DomRoot<Document> {
3704 let document = reflect_dom_object_with_proto(
3705 Box::new(Document::new_inherited(
3706 window,
3707 has_browsing_context,
3708 url,
3709 origin,
3710 doctype,
3711 content_type,
3712 last_modified,
3713 activity,
3714 source,
3715 doc_loader,
3716 referrer,
3717 status_code,
3718 canceller,
3719 is_initial_about_blank,
3720 allow_declarative_shadow_roots,
3721 inherited_insecure_requests_policy,
3722 has_trustworthy_ancestor_origin,
3723 custom_element_reaction_stack,
3724 creation_sandboxing_flag_set,
3725 )),
3726 window,
3727 proto,
3728 can_gc,
3729 );
3730 {
3731 let node = document.upcast::<Node>();
3732 node.set_owner_doc(&document);
3733 }
3734 document
3735 }
3736
3737 pub(crate) fn get_redirect_count(&self) -> u16 {
3738 self.redirect_count.get()
3739 }
3740
3741 pub(crate) fn set_redirect_count(&self, count: u16) {
3742 self.redirect_count.set(count)
3743 }
3744
3745 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3746 if name.is_empty() {
3747 return 0;
3748 }
3749 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3750 }
3751
3752 pub(crate) fn nth_element_by_name(
3753 &self,
3754 index: u32,
3755 name: &DOMString,
3756 ) -> Option<DomRoot<Node>> {
3757 if name.is_empty() {
3758 return None;
3759 }
3760 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3761 }
3762
3763 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3766 let element = match node.downcast::<Element>() {
3767 Some(element) => element,
3768 None => return false,
3769 };
3770 if element.namespace() != &ns!(html) {
3771 return false;
3772 }
3773 element.get_name().is_some_and(|n| &*n == name)
3774 }
3775
3776 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3777 let doc = self.GetDocumentElement();
3778 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3779 maybe_node
3780 .iter()
3781 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3782 .filter(|node| callback(node))
3783 .count() as u32
3784 }
3785
3786 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3787 &self,
3788 index: u32,
3789 callback: F,
3790 ) -> Option<DomRoot<Node>> {
3791 let doc = self.GetDocumentElement();
3792 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3793 maybe_node
3794 .iter()
3795 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3796 .filter(|node| callback(node))
3797 .nth(index as usize)
3798 .map(|n| DomRoot::from_ref(&*n))
3799 }
3800
3801 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3802 self.GetDocumentElement().and_then(DomRoot::downcast)
3803 }
3804
3805 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3807 &self.style_shared_lock
3808 }
3809
3810 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3812 let mut stylesheets = self.stylesheets.borrow_mut();
3819 let have_changed = stylesheets.has_changed();
3820 stylesheets.flush_without_invalidation();
3821 have_changed
3822 }
3823
3824 pub(crate) fn salvageable(&self) -> bool {
3825 self.salvageable.get()
3826 }
3827
3828 pub(crate) fn appropriate_template_contents_owner_document(
3830 &self,
3831 can_gc: CanGc,
3832 ) -> DomRoot<Document> {
3833 self.appropriate_template_contents_owner_document
3834 .or_init(|| {
3835 let doctype = if self.is_html_document {
3836 IsHTMLDocument::HTMLDocument
3837 } else {
3838 IsHTMLDocument::NonHTMLDocument
3839 };
3840 let new_doc = Document::new(
3841 self.window(),
3842 HasBrowsingContext::No,
3843 None,
3844 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3846 doctype,
3847 None,
3848 None,
3849 DocumentActivity::Inactive,
3850 DocumentSource::NotFromParser,
3851 DocumentLoader::new(&self.loader()),
3852 None,
3853 None,
3854 Default::default(),
3855 false,
3856 self.allow_declarative_shadow_roots(),
3857 Some(self.insecure_requests_policy()),
3858 self.has_trustworthy_ancestor_or_current_origin(),
3859 self.custom_element_reaction_stack.clone(),
3860 self.creation_sandboxing_flag_set(),
3861 can_gc,
3862 );
3863 new_doc
3864 .appropriate_template_contents_owner_document
3865 .set(Some(&new_doc));
3866 new_doc
3867 })
3868 }
3869
3870 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
3871 self.id_map
3872 .borrow()
3873 .get(id)
3874 .map(|elements| DomRoot::from_ref(&*elements[0]))
3875 }
3876
3877 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
3878 let map = self.pending_restyles.borrow_mut();
3879 RefMut::map(map, |m| {
3880 &mut m
3881 .entry(Dom::from_ref(el))
3882 .or_insert_with(|| NoTrace(PendingRestyle::default()))
3883 .0
3884 })
3885 }
3886
3887 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
3888 let mut entry = self.ensure_pending_restyle(el);
3894 if entry.snapshot.is_none() {
3895 entry.snapshot = Some(Snapshot::new());
3896 }
3897 if attr.local_name() == &local_name!("style") {
3898 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
3899 }
3900
3901 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
3902 entry.hint.insert(RestyleHint::RESTYLE_SELF);
3903 }
3904
3905 let snapshot = entry.snapshot.as_mut().unwrap();
3906 if attr.local_name() == &local_name!("id") {
3907 if snapshot.id_changed {
3908 return;
3909 }
3910 snapshot.id_changed = true;
3911 } else if attr.local_name() == &local_name!("class") {
3912 if snapshot.class_changed {
3913 return;
3914 }
3915 snapshot.class_changed = true;
3916 } else {
3917 snapshot.other_attributes_changed = true;
3918 }
3919 let local_name = style::LocalName::cast(attr.local_name());
3920 if !snapshot.changed_attrs.contains(local_name) {
3921 snapshot.changed_attrs.push(local_name.clone());
3922 }
3923 if snapshot.attrs.is_none() {
3924 let attrs = el
3925 .attrs()
3926 .iter()
3927 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
3928 .collect();
3929 snapshot.attrs = Some(attrs);
3930 }
3931 }
3932
3933 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
3934 self.policy_container
3935 .borrow_mut()
3936 .set_referrer_policy(policy);
3937 }
3938
3939 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
3940 self.policy_container.borrow().get_referrer_policy()
3941 }
3942
3943 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
3944 if let Some(ref element) = self.target_element.get() {
3945 element.set_target_state(false);
3946 }
3947
3948 self.target_element.set(node);
3949
3950 if let Some(ref element) = self.target_element.get() {
3951 element.set_target_state(true);
3952 }
3953 }
3954
3955 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
3956 self.ignore_destructive_writes_counter
3957 .set(self.ignore_destructive_writes_counter.get() + 1);
3958 }
3959
3960 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
3961 self.ignore_destructive_writes_counter
3962 .set(self.ignore_destructive_writes_counter.get() - 1);
3963 }
3964
3965 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
3966 self.ignore_opens_during_unload_counter.get() > 0
3967 }
3968
3969 fn incr_ignore_opens_during_unload_counter(&self) {
3970 self.ignore_opens_during_unload_counter
3971 .set(self.ignore_opens_during_unload_counter.get() + 1);
3972 }
3973
3974 fn decr_ignore_opens_during_unload_counter(&self) {
3975 self.ignore_opens_during_unload_counter
3976 .set(self.ignore_opens_during_unload_counter.get() - 1);
3977 }
3978
3979 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
3981 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
3983 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
3984 let mut error = false;
3985
3986 match *pending.namespace() {
3989 ns!(mathml) => {
3990 if pending.local_name().as_ref() != "math" {
3991 error = true;
3992 }
3993 },
3994 ns!(svg) => {
3995 if pending.local_name().as_ref() != "svg" {
3996 error = true;
3997 }
3998 },
3999 ns!(html) => (),
4000 _ => error = true,
4001 }
4002 if !pending.fullscreen_element_ready_check() {
4004 error = true;
4005 }
4006
4007 if pref!(dom_fullscreen_test) {
4008 info!("Tests don't really enter fullscreen.");
4011 } else {
4012 warn!("Fullscreen not supported yet");
4015 }
4016
4017 let window = self.window();
4020 if !error {
4022 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4023 self.send_to_embedder(event);
4024 }
4025
4026 let pipeline_id = self.window().pipeline_id();
4027
4028 let trusted_pending = Trusted::new(pending);
4030 let trusted_promise = TrustedPromise::new(promise.clone());
4031 let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
4032 let script_msg = CommonScriptMsg::Task(
4035 ScriptThreadEventCategory::EnterFullscreen,
4036 handler,
4037 Some(pipeline_id),
4038 TaskSourceName::DOMManipulation,
4039 );
4040 let msg = MainThreadScriptMsg::Common(script_msg);
4041 window.main_thread_script_chan().send(msg).unwrap();
4042
4043 promise
4044 }
4045
4046 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4048 let global = self.global();
4049 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4051 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4052 if self.fullscreen_element.get().is_none() {
4054 promise.reject_error(Error::Type(String::from("fullscreen is null")), can_gc);
4055 return promise;
4056 }
4057 let element = self.fullscreen_element.get().unwrap();
4059
4060 let window = self.window();
4063 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4065 self.send_to_embedder(event);
4066
4067 let trusted_element = Trusted::new(&*element);
4069 let trusted_promise = TrustedPromise::new(promise.clone());
4070 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4071 let pipeline_id = Some(global.pipeline_id());
4072 let script_msg = CommonScriptMsg::Task(
4075 ScriptThreadEventCategory::ExitFullscreen,
4076 handler,
4077 pipeline_id,
4078 TaskSourceName::DOMManipulation,
4079 );
4080 let msg = MainThreadScriptMsg::Common(script_msg);
4081 window.main_thread_script_chan().send(msg).unwrap();
4082
4083 promise
4084 }
4085
4086 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4087 self.fullscreen_element.set(element);
4088 }
4089
4090 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4091 match self.browsing_context() {
4093 None => false,
4095 Some(_) => {
4096 let window = self.window();
4098 if window.is_top_level() {
4099 true
4100 } else {
4101 window
4103 .GetFrameElement()
4104 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4105 }
4106 },
4107 }
4108 }
4109
4110 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4111 let map = self.form_id_listener_map.borrow();
4112 if let Some(listeners) = map.get(id) {
4113 for listener in listeners {
4114 listener
4115 .as_maybe_form_control()
4116 .expect("Element must be a form control")
4117 .reset_form_owner(can_gc);
4118 }
4119 }
4120 }
4121
4122 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4123 self.shadow_roots
4124 .borrow_mut()
4125 .insert(Dom::from_ref(shadow_root));
4126 self.invalidate_shadow_roots_stylesheets();
4127 }
4128
4129 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4130 let mut shadow_roots = self.shadow_roots.borrow_mut();
4131 shadow_roots.remove(&Dom::from_ref(shadow_root));
4132 }
4133
4134 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4135 self.shadow_roots_styles_changed.set(true);
4136 }
4137
4138 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4139 self.shadow_roots_styles_changed.get()
4140 }
4141
4142 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4143 if !self.shadow_roots_styles_changed.get() {
4144 return;
4145 }
4146 self.shadow_roots_styles_changed.set(false);
4147 }
4148
4149 pub(crate) fn stylesheet_count(&self) -> usize {
4150 self.stylesheets.borrow().len()
4151 }
4152
4153 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4154 let stylesheets = self.stylesheets.borrow();
4155
4156 stylesheets
4157 .get(Origin::Author, index)
4158 .and_then(|s| s.owner.get_cssom_object())
4159 }
4160
4161 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4168 let stylesheets = &mut *self.stylesheets.borrow_mut();
4169
4170 let insertion_point = stylesheets
4172 .iter()
4173 .map(|(sheet, _origin)| sheet)
4174 .find(|sheet_in_doc| {
4175 match &sheet_in_doc.owner {
4176 StylesheetSource::Element(other_node) => {
4177 owner_node.upcast::<Node>().is_before(other_node.upcast())
4178 },
4179 StylesheetSource::Constructed(_) => true,
4182 }
4183 })
4184 .cloned();
4185
4186 if self.has_browsing_context() {
4187 self.window.layout_mut().add_stylesheet(
4188 sheet.clone(),
4189 insertion_point.as_ref().map(|s| s.sheet.clone()),
4190 );
4191 }
4192
4193 DocumentOrShadowRoot::add_stylesheet(
4194 StylesheetSource::Element(Dom::from_ref(owner_node)),
4195 StylesheetSetRef::Document(stylesheets),
4196 sheet,
4197 insertion_point,
4198 self.style_shared_lock(),
4199 );
4200 }
4201
4202 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4207 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4208 debug_assert!(cssom_stylesheet.is_constructed());
4209
4210 let stylesheets = &mut *self.stylesheets.borrow_mut();
4211 let sheet = cssom_stylesheet.style_stylesheet().clone();
4212
4213 let insertion_point = stylesheets
4214 .iter()
4215 .last()
4216 .map(|(sheet, _origin)| sheet)
4217 .cloned();
4218
4219 if self.has_browsing_context() {
4220 self.window.layout_mut().add_stylesheet(
4221 sheet.clone(),
4222 insertion_point.as_ref().map(|s| s.sheet.clone()),
4223 );
4224 }
4225
4226 DocumentOrShadowRoot::add_stylesheet(
4227 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4228 StylesheetSetRef::Document(stylesheets),
4229 sheet,
4230 insertion_point,
4231 self.style_shared_lock(),
4232 );
4233 }
4234
4235 pub(crate) fn load_web_fonts_from_stylesheet(&self, stylesheet: &Arc<Stylesheet>) {
4237 self.window
4238 .layout()
4239 .load_web_fonts_from_stylesheet(stylesheet);
4240 }
4241
4242 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4245 if self.has_browsing_context() {
4246 self.window
4247 .layout_mut()
4248 .remove_stylesheet(stylesheet.clone());
4249 }
4250
4251 DocumentOrShadowRoot::remove_stylesheet(
4252 owner,
4253 stylesheet,
4254 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4255 )
4256 }
4257
4258 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4259 Ref::map(self.id_map.borrow(), |map| {
4260 map.get(id).map(|vec| &**vec).unwrap_or_default()
4261 })
4262 }
4263
4264 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4265 Ref::map(self.name_map.borrow(), |map| {
4266 map.get(name).map(|vec| &**vec).unwrap_or_default()
4267 })
4268 }
4269
4270 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4271 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4272 self.pending_restyles
4273 .borrow_mut()
4274 .drain()
4275 .filter_map(|(elem, restyle)| {
4276 let node = elem.upcast::<Node>();
4277 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4278 return None;
4279 }
4280 node.note_dirty_descendants();
4281 Some((node.to_trusted_node_address(), restyle.0))
4282 })
4283 .collect()
4284 }
4285
4286 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4287 self.animation_timeline.borrow_mut().advance_specific(delta);
4288 let current_timeline_value = self.current_animation_timeline_value();
4289 self.animations
4290 .update_for_new_timeline_value(&self.window, current_timeline_value);
4291 }
4292
4293 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4294 let current_timeline_value = self.current_animation_timeline_value();
4295 self.animations
4296 .mark_animating_nodes_as_dirty(current_timeline_value);
4297 }
4298
4299 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4300 self.animation_timeline.borrow().current_value()
4301 }
4302
4303 pub(crate) fn animations(&self) -> &Animations {
4304 &self.animations
4305 }
4306
4307 pub(crate) fn update_animations_post_reflow(&self) {
4308 self.animations
4309 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4310 self.image_animation_manager
4311 .borrow()
4312 .maybe_schedule_update_after_layout(
4313 &self.window,
4314 self.current_animation_timeline_value(),
4315 );
4316 }
4317
4318 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4319 self.animations.cancel_animations_for_node(node);
4320 self.image_animation_manager
4321 .borrow()
4322 .cancel_animations_for_node(node);
4323 }
4324
4325 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4327 if !pref!(layout_animations_test_enabled) {
4329 self.animation_timeline.borrow_mut().update();
4330 }
4331
4332 let current_timeline_value = self.current_animation_timeline_value();
4339 self.animations
4340 .update_for_new_timeline_value(&self.window, current_timeline_value);
4341 self.maybe_mark_animating_nodes_as_dirty();
4342
4343 self.window().perform_a_microtask_checkpoint(can_gc);
4345
4346 let _realm = enter_realm(self);
4348 self.animations().send_pending_events(self.window(), can_gc);
4349 }
4350
4351 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4352 self.image_animation_manager.borrow()
4353 }
4354
4355 pub(crate) fn set_has_pending_animated_image_update(&self) {
4356 self.has_pending_animated_image_update.set(true);
4357 }
4358
4359 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4361 if self.will_declaratively_refresh() {
4363 return;
4364 }
4365
4366 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4368 Regex::new(
4372 r#"(?xs)
4373 ^
4374 \s* # 3
4375 ((?<time>[0-9]+)|\.) # 5-6
4376 [0-9.]* # 8
4377 (
4378 (
4379 (\s*;|\s*,|\s) # 10.3
4380 \s* # 10.4
4381 )
4382 (
4383 (
4384 (U|u)(R|r)(L|l) # 11.2-11.4
4385 \s*=\s* # 11.5-11.7
4386 )?
4387 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4388 |
4389 (?<url4>(?s-u:.)*)
4390 )
4391 )?
4392 $
4393 "#,
4394 )
4395 .unwrap()
4396 });
4397
4398 let mut url_record = self.url();
4400 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4401 captures
4402 } else {
4403 return;
4404 };
4405 let time = if let Some(time_string) = captures.name("time") {
4406 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4407 } else {
4408 0
4409 };
4410 let captured_url = captures.name("url1").or(captures
4411 .name("url2")
4412 .or(captures.name("url3").or(captures.name("url4"))));
4413
4414 if let Some(url_match) = captured_url {
4416 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4417 Some(&url_record),
4418 &String::from_utf8_lossy(url_match.as_bytes()),
4419 ) {
4420 info!("Refresh to {}", url.debug_compact());
4421 url
4422 } else {
4423 return;
4425 }
4426 }
4427 if self.completely_loaded() {
4429 self.window.as_global_scope().schedule_callback(
4431 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4432 window: DomRoot::from_ref(self.window()),
4433 url: url_record,
4434 }),
4435 Duration::from_secs(time),
4436 );
4437 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4438 } else {
4439 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4440 url: url_record,
4441 time,
4442 });
4443 }
4444 }
4445
4446 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4447 self.declarative_refresh.borrow().is_some()
4448 }
4449 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4450 *self.declarative_refresh.borrow_mut() = Some(refresh);
4451 }
4452
4453 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4455 if self.visibility_state.get() == visibility_state {
4457 return;
4458 }
4459 self.visibility_state.set(visibility_state);
4461 let entry = VisibilityStateEntry::new(
4464 &self.global(),
4465 visibility_state,
4466 CrossProcessInstant::now(),
4467 can_gc,
4468 );
4469 self.window
4470 .Performance()
4471 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
4472
4473 if visibility_state == DocumentVisibilityState::Hidden {
4484 self.window
4485 .Navigator()
4486 .GetGamepads()
4487 .iter_mut()
4488 .for_each(|gamepad| {
4489 if let Some(g) = gamepad {
4490 g.vibration_actuator().handle_visibility_change();
4491 }
4492 });
4493 }
4494
4495 self.upcast::<EventTarget>()
4497 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4498 }
4499
4500 pub(crate) fn is_initial_about_blank(&self) -> bool {
4502 self.is_initial_about_blank.get()
4503 }
4504
4505 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4507 self.allow_declarative_shadow_roots.get()
4508 }
4509
4510 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4511 self.has_trustworthy_ancestor_origin.get()
4512 }
4513
4514 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4515 self.has_trustworthy_ancestor_origin.get() ||
4516 self.origin().immutable().is_potentially_trustworthy()
4517 }
4518
4519 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4520 self.highlighted_dom_node.set(node);
4521 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4522 }
4523
4524 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4525 self.highlighted_dom_node.get()
4526 }
4527
4528 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4529 self.custom_element_reaction_stack.clone()
4530 }
4531
4532 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4533 self.active_sandboxing_flag_set.get().contains(flag)
4534 }
4535
4536 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4537 self.active_sandboxing_flag_set.set(flags)
4538 }
4539
4540 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4541 self.creation_sandboxing_flag_set.get()
4542 }
4543
4544 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4545 &self,
4546 ) -> SandboxingFlagSet {
4547 self.window()
4548 .window_proxy()
4549 .frame_element()
4550 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4551 .map(HTMLIFrameElement::sandboxing_flag_set)
4552 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4553 }
4554
4555 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4556 self.window()
4557 .scrolling_box_query(None, flags)
4558 .expect("We should always have a ScrollingBox for the Viewport")
4559 }
4560
4561 pub(crate) fn notify_embedder_favicon(&self) {
4562 if let Some(ref image) = *self.favicon.borrow() {
4563 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4564 }
4565 }
4566
4567 pub(crate) fn set_favicon(&self, favicon: Image) {
4568 *self.favicon.borrow_mut() = Some(favicon);
4569 self.notify_embedder_favicon();
4570 }
4571}
4572
4573#[allow(non_snake_case)]
4574impl DocumentMethods<crate::DomTypeHolder> for Document {
4575 fn Constructor(
4577 window: &Window,
4578 proto: Option<HandleObject>,
4579 can_gc: CanGc,
4580 ) -> Fallible<DomRoot<Document>> {
4581 let doc = window.Document();
4582 let docloader = DocumentLoader::new(&doc.loader());
4583 Ok(Document::new_with_proto(
4584 window,
4585 proto,
4586 HasBrowsingContext::No,
4587 None,
4588 doc.origin().clone(),
4589 IsHTMLDocument::NonHTMLDocument,
4590 None,
4591 None,
4592 DocumentActivity::Inactive,
4593 DocumentSource::NotFromParser,
4594 docloader,
4595 None,
4596 None,
4597 Default::default(),
4598 false,
4599 doc.allow_declarative_shadow_roots(),
4600 Some(doc.insecure_requests_policy()),
4601 doc.has_trustworthy_ancestor_or_current_origin(),
4602 doc.custom_element_reaction_stack(),
4603 doc.active_sandboxing_flag_set.get(),
4604 can_gc,
4605 ))
4606 }
4607
4608 fn ParseHTMLUnsafe(
4610 window: &Window,
4611 s: TrustedHTMLOrString,
4612 can_gc: CanGc,
4613 ) -> Fallible<DomRoot<Self>> {
4614 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
4618 window.as_global_scope(),
4619 s,
4620 "Document parseHTMLUnsafe",
4621 can_gc,
4622 )?;
4623
4624 let url = window.get_url();
4625 let doc = window.Document();
4626 let loader = DocumentLoader::new(&doc.loader());
4627
4628 let content_type = "text/html"
4629 .parse()
4630 .expect("Supported type is not a MIME type");
4631 let document = Document::new(
4634 window,
4635 HasBrowsingContext::No,
4636 Some(ServoUrl::parse("about:blank").unwrap()),
4637 doc.origin().clone(),
4638 IsHTMLDocument::HTMLDocument,
4639 Some(content_type),
4640 None,
4641 DocumentActivity::Inactive,
4642 DocumentSource::FromParser,
4643 loader,
4644 None,
4645 None,
4646 Default::default(),
4647 false,
4648 true,
4649 Some(doc.insecure_requests_policy()),
4650 doc.has_trustworthy_ancestor_or_current_origin(),
4651 doc.custom_element_reaction_stack(),
4652 doc.creation_sandboxing_flag_set(),
4653 can_gc,
4654 );
4655 ServoParser::parse_html_document(&document, Some(compliant_html), url, can_gc);
4657 document.set_ready_state(DocumentReadyState::Complete, can_gc);
4659 Ok(document)
4660 }
4661
4662 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
4664 false
4665 }
4666
4667 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4669 self.stylesheet_list.or_init(|| {
4670 StyleSheetList::new(
4671 &self.window,
4672 StyleSheetListOwner::Document(Dom::from_ref(self)),
4673 can_gc,
4674 )
4675 })
4676 }
4677
4678 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4680 self.implementation
4681 .or_init(|| DOMImplementation::new(self, can_gc))
4682 }
4683
4684 fn URL(&self) -> USVString {
4686 USVString(String::from(self.url().as_str()))
4687 }
4688
4689 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4691 self.document_or_shadow_root.get_active_element(
4692 self.get_focused_element(),
4693 self.GetBody(),
4694 self.GetDocumentElement(),
4695 )
4696 }
4697
4698 fn HasFocus(&self) -> bool {
4700 if self.window().parent_info().is_none() {
4722 self.is_fully_active()
4724 } else {
4725 self.is_fully_active() && self.has_focus.get()
4727 }
4728 }
4729
4730 fn Domain(&self) -> DOMString {
4732 if !self.has_browsing_context {
4734 return DOMString::new();
4735 }
4736
4737 match self.origin.effective_domain() {
4739 None => DOMString::new(),
4741 Some(Host::Domain(domain)) => DOMString::from(domain),
4743 Some(host) => DOMString::from(host.to_string()),
4744 }
4745 }
4746
4747 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4749 if !self.has_browsing_context {
4751 return Err(Error::Security);
4752 }
4753
4754 if self.has_active_sandboxing_flag(
4757 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4758 ) {
4759 return Err(Error::Security);
4760 }
4761
4762 let effective_domain = match self.origin.effective_domain() {
4764 Some(effective_domain) => effective_domain,
4765 None => return Err(Error::Security),
4766 };
4767
4768 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
4770 None => return Err(Error::Security),
4771 Some(host) => host,
4772 };
4773
4774 self.origin.set_domain(host);
4776
4777 Ok(())
4778 }
4779
4780 fn Referrer(&self) -> DOMString {
4782 match self.referrer {
4783 Some(ref referrer) => DOMString::from(referrer.to_string()),
4784 None => DOMString::new(),
4785 }
4786 }
4787
4788 fn DocumentURI(&self) -> USVString {
4790 self.URL()
4791 }
4792
4793 fn CompatMode(&self) -> DOMString {
4795 DOMString::from(match self.quirks_mode.get() {
4796 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4797 QuirksMode::Quirks => "BackCompat",
4798 })
4799 }
4800
4801 fn CharacterSet(&self) -> DOMString {
4803 DOMString::from(self.encoding.get().name())
4804 }
4805
4806 fn Charset(&self) -> DOMString {
4808 self.CharacterSet()
4809 }
4810
4811 fn InputEncoding(&self) -> DOMString {
4813 self.CharacterSet()
4814 }
4815
4816 fn ContentType(&self) -> DOMString {
4818 DOMString::from(self.content_type.to_string())
4819 }
4820
4821 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4823 self.upcast::<Node>().children().find_map(DomRoot::downcast)
4824 }
4825
4826 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4828 self.upcast::<Node>().child_elements().next()
4829 }
4830
4831 fn GetElementsByTagName(
4833 &self,
4834 qualified_name: DOMString,
4835 can_gc: CanGc,
4836 ) -> DomRoot<HTMLCollection> {
4837 let qualified_name = LocalName::from(qualified_name);
4838 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4839 return DomRoot::from_ref(entry);
4840 }
4841 let result = HTMLCollection::by_qualified_name(
4842 &self.window,
4843 self.upcast(),
4844 qualified_name.clone(),
4845 can_gc,
4846 );
4847 self.tag_map
4848 .borrow_mut()
4849 .insert(qualified_name, Dom::from_ref(&*result));
4850 result
4851 }
4852
4853 fn GetElementsByTagNameNS(
4855 &self,
4856 maybe_ns: Option<DOMString>,
4857 tag_name: DOMString,
4858 can_gc: CanGc,
4859 ) -> DomRoot<HTMLCollection> {
4860 let ns = namespace_from_domstring(maybe_ns);
4861 let local = LocalName::from(tag_name);
4862 let qname = QualName::new(None, ns, local);
4863 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4864 return DomRoot::from_ref(collection);
4865 }
4866 let result =
4867 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4868 self.tagns_map
4869 .borrow_mut()
4870 .insert(qname, Dom::from_ref(&*result));
4871 result
4872 }
4873
4874 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4876 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4877 .map(Atom::from)
4878 .collect();
4879 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4880 return DomRoot::from_ref(collection);
4881 }
4882 let result = HTMLCollection::by_atomic_class_name(
4883 &self.window,
4884 self.upcast(),
4885 class_atoms.clone(),
4886 can_gc,
4887 );
4888 self.classes_map
4889 .borrow_mut()
4890 .insert(class_atoms, Dom::from_ref(&*result));
4891 result
4892 }
4893
4894 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4896 self.get_element_by_id(&Atom::from(id))
4897 }
4898
4899 fn CreateElement(
4901 &self,
4902 mut local_name: DOMString,
4903 options: StringOrElementCreationOptions,
4904 can_gc: CanGc,
4905 ) -> Fallible<DomRoot<Element>> {
4906 if !is_valid_element_local_name(&local_name.str()) {
4909 debug!("Not a valid element name");
4910 return Err(Error::InvalidCharacter(None));
4911 }
4912
4913 if self.is_html_document {
4914 local_name.make_ascii_lowercase();
4915 }
4916
4917 let ns = if self.is_html_document || self.is_xhtml_document() {
4918 ns!(html)
4919 } else {
4920 ns!()
4921 };
4922
4923 let name = QualName::new(None, ns, LocalName::from(local_name));
4924 let is = match options {
4925 StringOrElementCreationOptions::String(_) => None,
4926 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4927 options.is.as_ref().map(LocalName::from)
4928 },
4929 };
4930 Ok(Element::create(
4931 name,
4932 is,
4933 self,
4934 ElementCreator::ScriptCreated,
4935 CustomElementCreationMode::Synchronous,
4936 None,
4937 can_gc,
4938 ))
4939 }
4940
4941 fn CreateElementNS(
4943 &self,
4944 namespace: Option<DOMString>,
4945 qualified_name: DOMString,
4946 options: StringOrElementCreationOptions,
4947 can_gc: CanGc,
4948 ) -> Fallible<DomRoot<Element>> {
4949 let context = domname::Context::Element;
4952 let (namespace, prefix, local_name) =
4953 domname::validate_and_extract(namespace, &qualified_name, context)?;
4954
4955 let name = QualName::new(prefix, namespace, local_name);
4958 let is = match options {
4959 StringOrElementCreationOptions::String(_) => None,
4960 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4961 options.is.as_ref().map(LocalName::from)
4962 },
4963 };
4964
4965 Ok(Element::create(
4967 name,
4968 is,
4969 self,
4970 ElementCreator::ScriptCreated,
4971 CustomElementCreationMode::Synchronous,
4972 None,
4973 can_gc,
4974 ))
4975 }
4976
4977 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
4979 if !is_valid_attribute_local_name(&local_name.str()) {
4982 debug!("Not a valid attribute name");
4983 return Err(Error::InvalidCharacter(None));
4984 }
4985 if self.is_html_document {
4986 local_name.make_ascii_lowercase();
4987 }
4988 let name = LocalName::from(local_name);
4989 let value = AttrValue::String("".to_owned());
4990
4991 Ok(Attr::new(
4992 self,
4993 name.clone(),
4994 value,
4995 name,
4996 ns!(),
4997 None,
4998 None,
4999 can_gc,
5000 ))
5001 }
5002
5003 fn CreateAttributeNS(
5005 &self,
5006 namespace: Option<DOMString>,
5007 qualified_name: DOMString,
5008 can_gc: CanGc,
5009 ) -> Fallible<DomRoot<Attr>> {
5010 let context = domname::Context::Attribute;
5013 let (namespace, prefix, local_name) =
5014 domname::validate_and_extract(namespace, &qualified_name, context)?;
5015 let value = AttrValue::String("".to_owned());
5016 let qualified_name = LocalName::from(qualified_name);
5017 Ok(Attr::new(
5018 self,
5019 local_name,
5020 value,
5021 qualified_name,
5022 namespace,
5023 prefix,
5024 None,
5025 can_gc,
5026 ))
5027 }
5028
5029 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5031 DocumentFragment::new(self, can_gc)
5032 }
5033
5034 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5036 Text::new(data, self, can_gc)
5037 }
5038
5039 fn CreateCDATASection(
5041 &self,
5042 data: DOMString,
5043 can_gc: CanGc,
5044 ) -> Fallible<DomRoot<CDATASection>> {
5045 if self.is_html_document {
5047 return Err(Error::NotSupported);
5048 }
5049
5050 if data.contains("]]>") {
5052 return Err(Error::InvalidCharacter(None));
5053 }
5054
5055 Ok(CDATASection::new(data, self, can_gc))
5057 }
5058
5059 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5061 Comment::new(data, self, None, can_gc)
5062 }
5063
5064 fn CreateProcessingInstruction(
5066 &self,
5067 target: DOMString,
5068 data: DOMString,
5069 can_gc: CanGc,
5070 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5071 if !matches_name_production(&target.str()) {
5073 return Err(Error::InvalidCharacter(None));
5074 }
5075
5076 if data.contains("?>") {
5078 return Err(Error::InvalidCharacter(None));
5079 }
5080
5081 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5083 }
5084
5085 fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5087 if node.is::<Document>() || node.is::<ShadowRoot>() {
5089 return Err(Error::NotSupported);
5090 }
5091
5092 let clone_children = if deep {
5094 CloneChildrenFlag::CloneChildren
5095 } else {
5096 CloneChildrenFlag::DoNotCloneChildren
5097 };
5098
5099 Ok(Node::clone(node, Some(self), clone_children, can_gc))
5100 }
5101
5102 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5104 if node.is::<Document>() {
5106 return Err(Error::NotSupported);
5107 }
5108
5109 if node.is::<ShadowRoot>() {
5111 return Err(Error::HierarchyRequest(None));
5112 }
5113
5114 Node::adopt(node, self, can_gc);
5116
5117 Ok(DomRoot::from_ref(node))
5119 }
5120
5121 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5123 interface.make_ascii_lowercase();
5124 match &*interface.str() {
5125 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5126 &self.window,
5127 can_gc,
5128 ))),
5129 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5130 CompositionEvent::new_uninitialized(&self.window, can_gc),
5131 )),
5132 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5133 self.window.upcast(),
5134 can_gc,
5135 ))),
5136 "events" | "event" | "htmlevents" | "svgevents" => {
5139 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5140 },
5141 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5142 &self.window,
5143 can_gc,
5144 ))),
5145 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5146 &self.window,
5147 can_gc,
5148 ))),
5149 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5150 &self.window,
5151 can_gc,
5152 ))),
5153 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5154 self.window.upcast(),
5155 can_gc,
5156 ))),
5157 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5158 &self.window,
5159 can_gc,
5160 ))),
5161 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5162 &self.window,
5163 "".into(),
5164 can_gc,
5165 ))),
5166 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5167 &self.window,
5168 &TouchList::new(&self.window, &[], can_gc),
5169 &TouchList::new(&self.window, &[], can_gc),
5170 &TouchList::new(&self.window, &[], can_gc),
5171 can_gc,
5172 ))),
5173 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5174 &self.window,
5175 can_gc,
5176 ))),
5177 _ => Err(Error::NotSupported),
5178 }
5179 }
5180
5181 fn LastModified(&self) -> DOMString {
5183 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5184 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5190 }))
5191 }
5192
5193 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5195 Range::new_with_doc(self, None, can_gc)
5196 }
5197
5198 fn CreateNodeIterator(
5200 &self,
5201 root: &Node,
5202 what_to_show: u32,
5203 filter: Option<Rc<NodeFilter>>,
5204 can_gc: CanGc,
5205 ) -> DomRoot<NodeIterator> {
5206 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5207 }
5208
5209 fn CreateTreeWalker(
5211 &self,
5212 root: &Node,
5213 what_to_show: u32,
5214 filter: Option<Rc<NodeFilter>>,
5215 ) -> DomRoot<TreeWalker> {
5216 TreeWalker::new(self, root, what_to_show, filter)
5217 }
5218
5219 fn Title(&self) -> DOMString {
5221 self.title().unwrap_or_else(|| DOMString::from(""))
5222 }
5223
5224 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5226 let root = match self.GetDocumentElement() {
5227 Some(root) => root,
5228 None => return,
5229 };
5230
5231 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5232 let elem = root.upcast::<Node>().child_elements().find(|node| {
5233 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5234 });
5235 match elem {
5236 Some(elem) => DomRoot::upcast::<Node>(elem),
5237 None => {
5238 let name = QualName::new(None, ns!(svg), local_name!("title"));
5239 let elem = Element::create(
5240 name,
5241 None,
5242 self,
5243 ElementCreator::ScriptCreated,
5244 CustomElementCreationMode::Synchronous,
5245 None,
5246 can_gc,
5247 );
5248 let parent = root.upcast::<Node>();
5249 let child = elem.upcast::<Node>();
5250 parent
5251 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5252 .unwrap()
5253 },
5254 }
5255 } else if root.namespace() == &ns!(html) {
5256 let elem = root
5257 .upcast::<Node>()
5258 .traverse_preorder(ShadowIncluding::No)
5259 .find(|node| node.is::<HTMLTitleElement>());
5260 match elem {
5261 Some(elem) => elem,
5262 None => match self.GetHead() {
5263 Some(head) => {
5264 let name = QualName::new(None, ns!(html), local_name!("title"));
5265 let elem = Element::create(
5266 name,
5267 None,
5268 self,
5269 ElementCreator::ScriptCreated,
5270 CustomElementCreationMode::Synchronous,
5271 None,
5272 can_gc,
5273 );
5274 head.upcast::<Node>()
5275 .AppendChild(elem.upcast(), can_gc)
5276 .unwrap()
5277 },
5278 None => return,
5279 },
5280 }
5281 } else {
5282 return;
5283 };
5284
5285 node.set_text_content_for_element(Some(title), can_gc);
5286 }
5287
5288 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5290 self.get_html_element()
5291 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5292 }
5293
5294 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5296 self.current_script.get()
5297 }
5298
5299 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5301 self.get_html_element().and_then(|root| {
5302 let node = root.upcast::<Node>();
5303 node.children()
5304 .find(|child| {
5305 matches!(
5306 child.type_id(),
5307 NodeTypeId::Element(ElementTypeId::HTMLElement(
5308 HTMLElementTypeId::HTMLBodyElement,
5309 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5310 HTMLElementTypeId::HTMLFrameSetElement,
5311 ))
5312 )
5313 })
5314 .map(|node| DomRoot::downcast(node).unwrap())
5315 })
5316 }
5317
5318 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5320 let new_body = match new_body {
5322 Some(new_body) => new_body,
5323 None => return Err(Error::HierarchyRequest(None)),
5324 };
5325
5326 let node = new_body.upcast::<Node>();
5327 match node.type_id() {
5328 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5329 NodeTypeId::Element(ElementTypeId::HTMLElement(
5330 HTMLElementTypeId::HTMLFrameSetElement,
5331 )) => {},
5332 _ => return Err(Error::HierarchyRequest(None)),
5333 }
5334
5335 let old_body = self.GetBody();
5337 if old_body.as_deref() == Some(new_body) {
5338 return Ok(());
5339 }
5340
5341 match (self.GetDocumentElement(), &old_body) {
5342 (Some(ref root), Some(child)) => {
5344 let root = root.upcast::<Node>();
5345 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5346 .unwrap();
5347 },
5348
5349 (None, _) => return Err(Error::HierarchyRequest(None)),
5351
5352 (Some(ref root), &None) => {
5354 let root = root.upcast::<Node>();
5355 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5356 },
5357 }
5358 Ok(())
5359 }
5360
5361 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5363 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5364 }
5365
5366 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5368 self.images.or_init(|| {
5369 HTMLCollection::new_with_filter_fn(
5370 &self.window,
5371 self.upcast(),
5372 |element, _| element.is::<HTMLImageElement>(),
5373 can_gc,
5374 )
5375 })
5376 }
5377
5378 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5380 self.embeds.or_init(|| {
5381 HTMLCollection::new_with_filter_fn(
5382 &self.window,
5383 self.upcast(),
5384 |element, _| element.is::<HTMLEmbedElement>(),
5385 can_gc,
5386 )
5387 })
5388 }
5389
5390 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5392 self.Embeds(can_gc)
5393 }
5394
5395 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5397 self.links.or_init(|| {
5398 HTMLCollection::new_with_filter_fn(
5399 &self.window,
5400 self.upcast(),
5401 |element, _| {
5402 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5403 element.has_attribute(&local_name!("href"))
5404 },
5405 can_gc,
5406 )
5407 })
5408 }
5409
5410 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5412 self.forms.or_init(|| {
5413 HTMLCollection::new_with_filter_fn(
5414 &self.window,
5415 self.upcast(),
5416 |element, _| element.is::<HTMLFormElement>(),
5417 can_gc,
5418 )
5419 })
5420 }
5421
5422 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5424 self.scripts.or_init(|| {
5425 HTMLCollection::new_with_filter_fn(
5426 &self.window,
5427 self.upcast(),
5428 |element, _| element.is::<HTMLScriptElement>(),
5429 can_gc,
5430 )
5431 })
5432 }
5433
5434 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5436 self.anchors.or_init(|| {
5437 HTMLCollection::new_with_filter_fn(
5438 &self.window,
5439 self.upcast(),
5440 |element, _| {
5441 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5442 },
5443 can_gc,
5444 )
5445 })
5446 }
5447
5448 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5450 self.applets
5451 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5452 }
5453
5454 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5456 if self.is_fully_active() {
5457 Some(self.window.Location())
5458 } else {
5459 None
5460 }
5461 }
5462
5463 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5465 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5466 }
5467
5468 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5470 self.upcast::<Node>().child_elements().next()
5471 }
5472
5473 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5475 self.upcast::<Node>()
5476 .rev_children()
5477 .find_map(DomRoot::downcast)
5478 }
5479
5480 fn ChildElementCount(&self) -> u32 {
5482 self.upcast::<Node>().child_elements().count() as u32
5483 }
5484
5485 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5487 self.upcast::<Node>().prepend(nodes, can_gc)
5488 }
5489
5490 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5492 self.upcast::<Node>().append(nodes, can_gc)
5493 }
5494
5495 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5497 self.upcast::<Node>().replace_children(nodes, can_gc)
5498 }
5499
5500 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5502 let root = self.upcast::<Node>();
5503 root.query_selector(selectors)
5504 }
5505
5506 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5508 let root = self.upcast::<Node>();
5509 root.query_selector_all(selectors)
5510 }
5511
5512 fn ReadyState(&self) -> DocumentReadyState {
5514 self.ready_state.get()
5515 }
5516
5517 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5519 if self.has_browsing_context {
5520 Some(DomRoot::from_ref(&*self.window))
5521 } else {
5522 None
5523 }
5524 }
5525
5526 fn GetCookie(&self) -> Fallible<DOMString> {
5528 if self.is_cookie_averse() {
5529 return Ok(DOMString::new());
5530 }
5531
5532 if !self.origin.is_tuple() {
5533 return Err(Error::Security);
5534 }
5535
5536 let url = self.url();
5537 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5538 let _ = self
5539 .window
5540 .as_global_scope()
5541 .resource_threads()
5542 .send(GetCookiesForUrl(url, tx, NonHTTP));
5543 let cookies = rx.recv().unwrap();
5544 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5545 }
5546
5547 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5549 if self.is_cookie_averse() {
5550 return Ok(());
5551 }
5552
5553 if !self.origin.is_tuple() {
5554 return Err(Error::Security);
5555 }
5556
5557 if !cookie.is_valid_for_cookie() {
5558 return Ok(());
5559 }
5560
5561 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5562 vec![cookie]
5563 } else {
5564 vec![]
5565 };
5566
5567 let _ = self
5568 .window
5569 .as_global_scope()
5570 .resource_threads()
5571 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5572 Ok(())
5573 }
5574
5575 fn BgColor(&self) -> DOMString {
5577 self.get_body_attribute(&local_name!("bgcolor"))
5578 }
5579
5580 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5582 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5583 }
5584
5585 fn FgColor(&self) -> DOMString {
5587 self.get_body_attribute(&local_name!("text"))
5588 }
5589
5590 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5592 self.set_body_attribute(&local_name!("text"), value, can_gc)
5593 }
5594
5595 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5597 if name.is_empty() {
5598 return None;
5599 }
5600 let name = Atom::from(name);
5601
5602 let elements_with_name = self.get_elements_with_name(&name);
5605 let name_iter = elements_with_name
5606 .iter()
5607 .filter(|elem| is_named_element_with_name_attribute(elem));
5608 let elements_with_id = self.get_elements_with_id(&name);
5609 let id_iter = elements_with_id
5610 .iter()
5611 .filter(|elem| is_named_element_with_id_attribute(elem));
5612 let mut elements = name_iter.chain(id_iter);
5613
5614 let first = elements.next()?;
5621 if elements.all(|other| first == other) {
5622 if let Some(nested_window_proxy) = first
5623 .downcast::<HTMLIFrameElement>()
5624 .and_then(|iframe| iframe.GetContentWindow())
5625 {
5626 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5627 }
5628
5629 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5631 }
5632
5633 #[derive(JSTraceable, MallocSizeOf)]
5636 struct DocumentNamedGetter {
5637 #[no_trace]
5638 name: Atom,
5639 }
5640 impl CollectionFilter for DocumentNamedGetter {
5641 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5642 let type_ = match elem.upcast::<Node>().type_id() {
5643 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5644 _ => return false,
5645 };
5646 match type_ {
5647 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5648 elem.get_name().as_ref() == Some(&self.name)
5649 },
5650 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5651 name == *self.name ||
5652 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5653 }),
5654 _ => false,
5658 }
5659 }
5660 }
5661 let collection = HTMLCollection::create(
5662 self.window(),
5663 self.upcast(),
5664 Box::new(DocumentNamedGetter { name }),
5665 can_gc,
5666 );
5667 Some(NamedPropertyValue::HTMLCollection(collection))
5668 }
5669
5670 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5672 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5673
5674 let name_map = self.name_map.borrow();
5675 for (name, elements) in &(name_map).0 {
5676 if name.is_empty() {
5677 continue;
5678 }
5679 let mut name_iter = elements
5680 .iter()
5681 .filter(|elem| is_named_element_with_name_attribute(elem));
5682 if let Some(first) = name_iter.next() {
5683 names_with_first_named_element_map.insert(name, first);
5684 }
5685 }
5686 let id_map = self.id_map.borrow();
5687 for (id, elements) in &(id_map).0 {
5688 if id.is_empty() {
5689 continue;
5690 }
5691 let mut id_iter = elements
5692 .iter()
5693 .filter(|elem| is_named_element_with_id_attribute(elem));
5694 if let Some(first) = id_iter.next() {
5695 match names_with_first_named_element_map.entry(id) {
5696 Vacant(entry) => drop(entry.insert(first)),
5697 Occupied(mut entry) => {
5698 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5699 *entry.get_mut() = first;
5700 }
5701 },
5702 }
5703 }
5704 }
5705
5706 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5707 names_with_first_named_element_map
5708 .iter()
5709 .map(|(k, v)| (*k, *v))
5710 .collect();
5711 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5712 if a.1 == b.1 {
5713 a.0.cmp(b.0)
5716 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5717 Ordering::Less
5718 } else {
5719 Ordering::Greater
5720 }
5721 });
5722
5723 names_with_first_named_element_vec
5724 .iter()
5725 .map(|(k, _v)| DOMString::from(&***k))
5726 .collect()
5727 }
5728
5729 fn Clear(&self) {
5731 }
5733
5734 fn CaptureEvents(&self) {
5736 }
5738
5739 fn ReleaseEvents(&self) {
5741 }
5743
5744 global_event_handlers!();
5746
5747 event_handler!(
5749 readystatechange,
5750 GetOnreadystatechange,
5751 SetOnreadystatechange
5752 );
5753
5754 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5756 self.document_or_shadow_root.element_from_point(
5757 x,
5758 y,
5759 self.GetDocumentElement(),
5760 self.has_browsing_context,
5761 )
5762 }
5763
5764 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5766 self.document_or_shadow_root.elements_from_point(
5767 x,
5768 y,
5769 self.GetDocumentElement(),
5770 self.has_browsing_context,
5771 )
5772 }
5773
5774 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5776 if self.quirks_mode() == QuirksMode::Quirks {
5778 if let Some(ref body) = self.GetBody() {
5780 let e = body.upcast::<Element>();
5781 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5785 return Some(DomRoot::from_ref(e));
5786 }
5787 }
5788
5789 return None;
5791 }
5792
5793 self.GetDocumentElement()
5796 }
5797
5798 fn Open(
5800 &self,
5801 _unused1: Option<DOMString>,
5802 _unused2: Option<DOMString>,
5803 can_gc: CanGc,
5804 ) -> Fallible<DomRoot<Document>> {
5805 if !self.is_html_document() {
5807 return Err(Error::InvalidState(None));
5808 }
5809
5810 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5812 return Err(Error::InvalidState(None));
5813 }
5814
5815 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5817
5818 if !self.origin.same_origin(&entry_responsible_document.origin) {
5820 return Err(Error::Security);
5821 }
5822
5823 if self
5825 .get_current_parser()
5826 .is_some_and(|parser| parser.is_active())
5827 {
5828 return Ok(DomRoot::from_ref(self));
5829 }
5830
5831 if self.is_prompting_or_unloading() {
5833 return Ok(DomRoot::from_ref(self));
5834 }
5835
5836 if self.active_parser_was_aborted.get() {
5838 return Ok(DomRoot::from_ref(self));
5839 }
5840
5841 self.window().set_navigation_start();
5845
5846 if self.has_browsing_context() {
5849 self.abort(can_gc);
5852 }
5853
5854 for node in self
5856 .upcast::<Node>()
5857 .traverse_preorder(ShadowIncluding::Yes)
5858 {
5859 node.upcast::<EventTarget>().remove_all_listeners();
5860 }
5861
5862 if self.window.Document() == DomRoot::from_ref(self) {
5864 self.window.upcast::<EventTarget>().remove_all_listeners();
5865 }
5866
5867 Node::replace_all(None, self.upcast::<Node>(), can_gc);
5869
5870 if self.is_fully_active() {
5877 let mut new_url = entry_responsible_document.url();
5879
5880 if entry_responsible_document != DomRoot::from_ref(self) {
5882 new_url.set_fragment(None);
5883 }
5884
5885 self.set_url(new_url);
5888 }
5889
5890 self.is_initial_about_blank.set(false);
5892
5893 self.set_quirks_mode(QuirksMode::NoQuirks);
5899
5900 let resource_threads = self.window.as_global_scope().resource_threads().clone();
5906 *self.loader.borrow_mut() =
5907 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
5908 ServoParser::parse_html_script_input(self, self.url());
5909
5910 self.ready_state.set(DocumentReadyState::Loading);
5916
5917 Ok(DomRoot::from_ref(self))
5919 }
5920
5921 fn Open_(
5923 &self,
5924 url: USVString,
5925 target: DOMString,
5926 features: DOMString,
5927 can_gc: CanGc,
5928 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
5929 self.browsing_context()
5930 .ok_or(Error::InvalidAccess)?
5931 .open(url, target, features, can_gc)
5932 }
5933
5934 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5936 self.write(text, false, "Document", "write", can_gc)
5939 }
5940
5941 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5943 self.write(text, true, "Document", "writeln", can_gc)
5946 }
5947
5948 fn Close(&self, can_gc: CanGc) -> ErrorResult {
5950 if !self.is_html_document() {
5951 return Err(Error::InvalidState(None));
5953 }
5954
5955 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5957 return Err(Error::InvalidState(None));
5958 }
5959
5960 let parser = match self.get_current_parser() {
5961 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
5962 _ => {
5963 return Ok(());
5965 },
5966 };
5967
5968 parser.close(can_gc);
5970
5971 Ok(())
5972 }
5973
5974 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
5976
5977 event_handler!(
5979 fullscreenchange,
5980 GetOnfullscreenchange,
5981 SetOnfullscreenchange
5982 );
5983
5984 fn FullscreenEnabled(&self) -> bool {
5986 self.get_allow_fullscreen()
5987 }
5988
5989 fn Fullscreen(&self) -> bool {
5991 self.fullscreen_element.get().is_some()
5992 }
5993
5994 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
5996 self.fullscreen_element.get()
5998 }
5999
6000 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6002 self.exit_fullscreen(can_gc)
6003 }
6004
6005 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6009 match self.media_controls.borrow().get(&*id.str()) {
6010 Some(m) => Ok(DomRoot::from_ref(m)),
6011 None => Err(Error::InvalidAccess),
6012 }
6013 }
6014
6015 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6017 if self.has_browsing_context {
6018 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6019 } else {
6020 None
6021 }
6022 }
6023
6024 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6026 self.fonts
6027 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6028 }
6029
6030 fn Hidden(&self) -> bool {
6032 self.visibility_state.get() == DocumentVisibilityState::Hidden
6033 }
6034
6035 fn VisibilityState(&self) -> DocumentVisibilityState {
6037 self.visibility_state.get()
6038 }
6039
6040 fn CreateExpression(
6041 &self,
6042 expression: DOMString,
6043 resolver: Option<Rc<XPathNSResolver>>,
6044 can_gc: CanGc,
6045 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6046 let parsed_expression =
6047 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6048 Ok(XPathExpression::new(
6049 &self.window,
6050 None,
6051 can_gc,
6052 parsed_expression,
6053 ))
6054 }
6055
6056 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6057 let global = self.global();
6058 let window = global.as_window();
6059 let evaluator = XPathEvaluator::new(window, None, can_gc);
6060 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6061 }
6062
6063 fn Evaluate(
6064 &self,
6065 expression: DOMString,
6066 context_node: &Node,
6067 resolver: Option<Rc<XPathNSResolver>>,
6068 result_type: u16,
6069 result: Option<&super::types::XPathResult>,
6070 can_gc: CanGc,
6071 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6072 let parsed_expression =
6073 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6074 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6075 context_node,
6076 result_type,
6077 result,
6078 can_gc,
6079 )
6080 }
6081
6082 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6084 self.adopted_stylesheets_frozen_types.get_or_init(
6085 || {
6086 self.adopted_stylesheets
6087 .borrow()
6088 .clone()
6089 .iter()
6090 .map(|sheet| sheet.as_rooted())
6091 .collect()
6092 },
6093 context,
6094 retval,
6095 can_gc,
6096 );
6097 }
6098
6099 fn SetAdoptedStyleSheets(
6101 &self,
6102 context: JSContext,
6103 val: HandleValue,
6104 can_gc: CanGc,
6105 ) -> ErrorResult {
6106 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6107 context,
6108 self.adopted_stylesheets.borrow_mut().as_mut(),
6109 val,
6110 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6111 can_gc,
6112 );
6113
6114 if result.is_ok() {
6116 self.adopted_stylesheets_frozen_types.clear()
6117 }
6118
6119 result
6120 }
6121}
6122
6123fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6124 if marker.get().is_none() {
6125 marker.set(Some(CrossProcessInstant::now()))
6126 }
6127}
6128
6129#[derive(Clone, Copy, PartialEq)]
6131pub(crate) enum FocusType {
6132 Element, Parent, }
6135
6136#[derive(Clone, Copy, PartialEq)]
6138pub enum FocusInitiator {
6139 Local,
6142 Remote,
6145}
6146
6147pub(crate) enum FocusEventType {
6149 Focus, Blur, }
6152
6153#[derive(JSTraceable, MallocSizeOf)]
6154pub(crate) enum AnimationFrameCallback {
6155 DevtoolsFramerateTick {
6156 actor_name: String,
6157 },
6158 FrameRequestCallback {
6159 #[conditional_malloc_size_of]
6160 callback: Rc<FrameRequestCallback>,
6161 },
6162}
6163
6164impl AnimationFrameCallback {
6165 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6166 match *self {
6167 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6168 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6169 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6170 devtools_sender.send(msg).unwrap();
6171 },
6172 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6173 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6176 },
6177 }
6178 }
6179}
6180
6181#[derive(Default, JSTraceable, MallocSizeOf)]
6182#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6183struct PendingInOrderScriptVec {
6184 scripts: DomRefCell<VecDeque<PendingScript>>,
6185}
6186
6187impl PendingInOrderScriptVec {
6188 fn is_empty(&self) -> bool {
6189 self.scripts.borrow().is_empty()
6190 }
6191
6192 fn push(&self, element: &HTMLScriptElement) {
6193 self.scripts
6194 .borrow_mut()
6195 .push_back(PendingScript::new(element));
6196 }
6197
6198 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6199 let mut scripts = self.scripts.borrow_mut();
6200 let entry = scripts
6201 .iter_mut()
6202 .find(|entry| &*entry.element == element)
6203 .unwrap();
6204 entry.loaded(result);
6205 }
6206
6207 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6208 let mut scripts = self.scripts.borrow_mut();
6209 let pair = scripts.front_mut()?.take_result()?;
6210 scripts.pop_front();
6211 Some(pair)
6212 }
6213
6214 fn clear(&self) {
6215 *self.scripts.borrow_mut() = Default::default();
6216 }
6217}
6218
6219#[derive(JSTraceable, MallocSizeOf)]
6220#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6221struct PendingScript {
6222 element: Dom<HTMLScriptElement>,
6223 load: Option<ScriptResult>,
6225}
6226
6227impl PendingScript {
6228 fn new(element: &HTMLScriptElement) -> Self {
6229 Self {
6230 element: Dom::from_ref(element),
6231 load: None,
6232 }
6233 }
6234
6235 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6236 Self {
6237 element: Dom::from_ref(element),
6238 load,
6239 }
6240 }
6241
6242 fn loaded(&mut self, result: ScriptResult) {
6243 assert!(self.load.is_none());
6244 self.load = Some(result);
6245 }
6246
6247 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6248 self.load
6249 .take()
6250 .map(|result| (DomRoot::from_ref(&*self.element), result))
6251 }
6252}
6253
6254fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6255 let type_ = match elem.upcast::<Node>().type_id() {
6256 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6257 _ => return false,
6258 };
6259 match type_ {
6260 HTMLElementTypeId::HTMLFormElement |
6261 HTMLElementTypeId::HTMLIFrameElement |
6262 HTMLElementTypeId::HTMLImageElement => true,
6263 _ => false,
6267 }
6268}
6269
6270fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6271 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6275}
6276
6277impl DocumentHelpers for Document {
6278 fn ensure_safe_to_run_script_or_layout(&self) {
6279 Document::ensure_safe_to_run_script_or_layout(self)
6280 }
6281}