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 canvas_traits::canvas::CanvasId;
19use canvas_traits::webgl::{WebGLContextId, WebGLMsg};
20use chrono::Local;
21use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
22use content_security_policy::sandboxing_directive::SandboxingFlagSet;
23use content_security_policy::{CspList, PolicyDisposition};
24use cookie::Cookie;
25use data_url::mime::Mime;
26use devtools_traits::ScriptToDevtoolsControlMsg;
27use dom_struct::dom_struct;
28use embedder_traits::{
29 AllowOrDeny, AnimationState, EmbedderMsg, FocusSequenceNumber, Image, LoadStatus,
30};
31use encoding_rs::{Encoding, UTF_8};
32use euclid::Point2D;
33use euclid::default::{Rect, Size2D};
34use html5ever::{LocalName, Namespace, QualName, local_name, ns};
35use hyper_serde::Serde;
36use js::rust::{HandleObject, HandleValue, MutableHandleValue};
37use layout_api::{
38 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
39 TrustedNodeAddress,
40};
41use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
42use net_traits::CookieSource::NonHTTP;
43use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
44use net_traits::policy_container::PolicyContainer;
45use net_traits::pub_domains::is_pub_domain;
46use net_traits::request::{InsecureRequestsPolicy, RequestBuilder};
47use net_traits::response::HttpsState;
48use net_traits::{FetchResponseListener, ReferrerPolicy};
49use percent_encoding::percent_decode;
50use profile_traits::ipc as profile_ipc;
51use profile_traits::time::TimerMetadataFrameType;
52use regex::bytes::Regex;
53use rustc_hash::{FxBuildHasher, FxHashMap};
54use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
55use script_bindings::interfaces::DocumentHelpers;
56use script_bindings::script_runtime::JSContext;
57use script_traits::{DocumentActivity, ProgressiveWebMetricType};
58use servo_arc::Arc;
59use servo_config::pref;
60use servo_media::{ClientContextId, ServoMedia};
61use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
62use style::attr::AttrValue;
63use style::context::QuirksMode;
64use style::invalidation::element::restyle_hints::RestyleHint;
65use style::selector_parser::Snapshot;
66use style::shared_lock::SharedRwLock as StyleSharedRwLock;
67use style::str::{split_html_space_chars, str_join};
68use style::stylesheet_set::DocumentStylesheetSet;
69use style::stylesheets::{Origin, OriginSet, Stylesheet};
70use stylo_atoms::Atom;
71use url::Host;
72use uuid::Uuid;
73#[cfg(feature = "webgpu")]
74use webgpu_traits::WebGPUContextId;
75use webrender_api::units::DeviceIntRect;
76
77use crate::animation_timeline::AnimationTimeline;
78use crate::animations::Animations;
79use crate::canvas_context::CanvasContext as _;
80use crate::document_loader::{DocumentLoader, LoadType};
81use crate::dom::attr::Attr;
82use crate::dom::beforeunloadevent::BeforeUnloadEvent;
83use crate::dom::bindings::callback::ExceptionHandling;
84use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
85use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
86use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
87 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
88};
89use crate::dom::bindings::codegen::Bindings::ElementBinding::{
90 ScrollIntoViewContainer, ScrollIntoViewOptions, ScrollLogicalPosition,
91};
92use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
93use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
94use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
95use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
96use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
97use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
98use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
99use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
100use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
101use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
102use crate::dom::bindings::codegen::Bindings::WindowBinding::{
103 FrameRequestCallback, ScrollBehavior, ScrollOptions, WindowMethods,
104};
105use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
106use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
107use crate::dom::bindings::codegen::UnionTypes::{
108 BooleanOrScrollIntoViewOptions, NodeOrString, StringOrElementCreationOptions,
109 TrustedHTMLOrString,
110};
111use crate::dom::bindings::domname::{
112 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
113};
114use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
115use crate::dom::bindings::frozenarray::CachedFrozenArray;
116use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
117use crate::dom::bindings::num::Finite;
118use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
119use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
120use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
121use crate::dom::bindings::str::{DOMString, USVString};
122use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
123use crate::dom::bindings::xmlname::matches_name_production;
124use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
125use crate::dom::cdatasection::CDATASection;
126use crate::dom::comment::Comment;
127use crate::dom::compositionevent::CompositionEvent;
128use crate::dom::cssstylesheet::CSSStyleSheet;
129use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack};
130use crate::dom::customevent::CustomEvent;
131use crate::dom::document_embedder_controls::DocumentEmbedderControls;
132use crate::dom::document_event_handler::DocumentEventHandler;
133use crate::dom::documentfragment::DocumentFragment;
134use crate::dom::documentorshadowroot::{
135 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
136};
137use crate::dom::documenttype::DocumentType;
138use crate::dom::domimplementation::DOMImplementation;
139use crate::dom::element::{
140 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
141 ElementPerformFullscreenExit,
142};
143use crate::dom::event::{Event, EventBubbles, EventCancelable};
144use crate::dom::eventtarget::EventTarget;
145use crate::dom::focusevent::FocusEvent;
146use crate::dom::fontfaceset::FontFaceSet;
147use crate::dom::globalscope::GlobalScope;
148use crate::dom::hashchangeevent::HashChangeEvent;
149use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
150use crate::dom::html::htmlareaelement::HTMLAreaElement;
151use crate::dom::html::htmlbaseelement::HTMLBaseElement;
152use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
153use crate::dom::html::htmlelement::HTMLElement;
154use crate::dom::html::htmlembedelement::HTMLEmbedElement;
155use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
156use crate::dom::html::htmlheadelement::HTMLHeadElement;
157use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
158use crate::dom::html::htmliframeelement::HTMLIFrameElement;
159use crate::dom::html::htmlimageelement::HTMLImageElement;
160use crate::dom::html::htmlinputelement::HTMLInputElement;
161use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
162use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
163use crate::dom::html::htmltitleelement::HTMLTitleElement;
164use crate::dom::intersectionobserver::IntersectionObserver;
165use crate::dom::keyboardevent::KeyboardEvent;
166use crate::dom::location::{Location, NavigationType};
167use crate::dom::messageevent::MessageEvent;
168use crate::dom::mouseevent::MouseEvent;
169use crate::dom::node::{
170 CloneChildrenFlag, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding,
171};
172use crate::dom::nodeiterator::NodeIterator;
173use crate::dom::nodelist::NodeList;
174use crate::dom::pagetransitionevent::PageTransitionEvent;
175use crate::dom::performanceentry::PerformanceEntry;
176use crate::dom::performancepainttiming::PerformancePaintTiming;
177use crate::dom::processinginstruction::ProcessingInstruction;
178use crate::dom::promise::Promise;
179use crate::dom::range::Range;
180use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
181use crate::dom::scrolling_box::ScrollingBox;
182use crate::dom::selection::Selection;
183use crate::dom::servoparser::ServoParser;
184use crate::dom::shadowroot::ShadowRoot;
185use crate::dom::storageevent::StorageEvent;
186use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
187use crate::dom::text::Text;
188use crate::dom::touchevent::TouchEvent as DomTouchEvent;
189use crate::dom::touchlist::TouchList;
190use crate::dom::treewalker::TreeWalker;
191use crate::dom::trustedhtml::TrustedHTML;
192use crate::dom::types::VisibilityStateEntry;
193use crate::dom::uievent::UIEvent;
194use crate::dom::virtualmethods::vtable_for;
195use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
196#[cfg(feature = "webgpu")]
197use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext;
198use crate::dom::window::Window;
199use crate::dom::windowproxy::WindowProxy;
200use crate::dom::xpathevaluator::XPathEvaluator;
201use crate::fetch::FetchCanceller;
202use crate::iframe_collection::IFrameCollection;
203use crate::image_animation::ImageAnimationManager;
204use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
205use crate::mime::{APPLICATION, CHARSET};
206use crate::network_listener::{NetworkListener, PreInvoke};
207use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
208use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
209use crate::script_thread::ScriptThread;
210use crate::stylesheet_set::StylesheetSetRef;
211use crate::task::NonSendTaskBox;
212use crate::task_source::TaskSourceName;
213use crate::timers::OneshotTimerCallback;
214
215pub(crate) enum TouchEventResult {
216 Processed(bool),
217 Forwarded,
218}
219
220#[derive(Clone, Copy, PartialEq)]
221pub(crate) enum FireMouseEventType {
222 Move,
223 Over,
224 Out,
225 Enter,
226 Leave,
227}
228
229impl FireMouseEventType {
230 pub(crate) fn as_str(&self) -> &str {
231 match *self {
232 FireMouseEventType::Move => "mousemove",
233 FireMouseEventType::Over => "mouseover",
234 FireMouseEventType::Out => "mouseout",
235 FireMouseEventType::Enter => "mouseenter",
236 FireMouseEventType::Leave => "mouseleave",
237 }
238 }
239}
240
241#[derive(JSTraceable, MallocSizeOf)]
242pub(crate) struct RefreshRedirectDue {
243 #[no_trace]
244 pub(crate) url: ServoUrl,
245 #[ignore_malloc_size_of = "non-owning"]
246 pub(crate) window: DomRoot<Window>,
247}
248impl RefreshRedirectDue {
249 pub(crate) fn invoke(self, can_gc: CanGc) {
250 self.window.Location().navigate(
251 self.url.clone(),
252 NavigationHistoryBehavior::Replace,
253 NavigationType::DeclarativeRefresh,
254 can_gc,
255 );
256 }
257}
258
259#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
260pub(crate) enum IsHTMLDocument {
261 HTMLDocument,
262 NonHTMLDocument,
263}
264
265#[derive(JSTraceable, MallocSizeOf)]
266#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
267struct FocusTransaction {
268 element: Option<Dom<Element>>,
270 has_focus: bool,
272 focus_options: FocusOptions,
274}
275
276#[derive(JSTraceable, MallocSizeOf)]
278pub(crate) enum DeclarativeRefresh {
279 PendingLoad {
280 #[no_trace]
281 url: ServoUrl,
282 time: u64,
283 },
284 CreatedAfterLoad,
285}
286
287#[dom_struct]
289pub(crate) struct Document {
290 node: Node,
291 document_or_shadow_root: DocumentOrShadowRoot,
292 window: Dom<Window>,
293 implementation: MutNullableDom<DOMImplementation>,
294 #[ignore_malloc_size_of = "type from external crate"]
295 #[no_trace]
296 content_type: Mime,
297 last_modified: Option<String>,
298 #[no_trace]
299 encoding: Cell<&'static Encoding>,
300 has_browsing_context: bool,
301 is_html_document: bool,
302 #[no_trace]
303 activity: Cell<DocumentActivity>,
304 #[no_trace]
305 url: DomRefCell<ServoUrl>,
306 #[ignore_malloc_size_of = "defined in selectors"]
307 #[no_trace]
308 quirks_mode: Cell<QuirksMode>,
309 event_handler: DocumentEventHandler,
311 embedder_controls: DocumentEmbedderControls,
313 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
316 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
317 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
318 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
319 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
320 images: MutNullableDom<HTMLCollection>,
321 embeds: MutNullableDom<HTMLCollection>,
322 links: MutNullableDom<HTMLCollection>,
323 forms: MutNullableDom<HTMLCollection>,
324 scripts: MutNullableDom<HTMLCollection>,
325 anchors: MutNullableDom<HTMLCollection>,
326 applets: MutNullableDom<HTMLCollection>,
327 iframes: RefCell<IFrameCollection>,
329 #[no_trace]
332 style_shared_lock: StyleSharedRwLock,
333 #[custom_trace]
335 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
336 stylesheet_list: MutNullableDom<StyleSheetList>,
337 ready_state: Cell<DocumentReadyState>,
338 domcontentloaded_dispatched: Cell<bool>,
340 focus_transaction: DomRefCell<Option<FocusTransaction>>,
342 focused: MutNullableDom<Element>,
344 #[no_trace]
346 focus_sequence: Cell<FocusSequenceNumber>,
347 has_focus: Cell<bool>,
351 current_script: MutNullableDom<HTMLScriptElement>,
353 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
355 script_blocking_stylesheets_count: Cell<u32>,
357 render_blocking_element_count: Cell<u32>,
360 deferred_scripts: PendingInOrderScriptVec,
362 asap_in_order_scripts_list: PendingInOrderScriptVec,
364 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
366 animation_frame_ident: Cell<u32>,
369 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
372 running_animation_callbacks: Cell<bool>,
377 loader: DomRefCell<DocumentLoader>,
379 current_parser: MutNullableDom<ServoParser>,
381 base_element: MutNullableDom<HTMLBaseElement>,
383 appropriate_template_contents_owner_document: MutNullableDom<Document>,
386 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
389 #[no_trace]
393 needs_restyle: Cell<RestyleReason>,
394 #[no_trace]
397 dom_interactive: Cell<Option<CrossProcessInstant>>,
398 #[no_trace]
399 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
400 #[no_trace]
401 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
402 #[no_trace]
403 dom_complete: Cell<Option<CrossProcessInstant>>,
404 #[no_trace]
405 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
406 #[no_trace]
407 load_event_start: Cell<Option<CrossProcessInstant>>,
408 #[no_trace]
409 load_event_end: Cell<Option<CrossProcessInstant>>,
410 #[no_trace]
411 unload_event_start: Cell<Option<CrossProcessInstant>>,
412 #[no_trace]
413 unload_event_end: Cell<Option<CrossProcessInstant>>,
414 #[no_trace]
416 https_state: Cell<HttpsState>,
417 #[no_trace]
419 origin: MutableOrigin,
420 referrer: Option<String>,
422 target_element: MutNullableDom<Element>,
424 #[no_trace]
426 policy_container: DomRefCell<PolicyContainer>,
427 ignore_destructive_writes_counter: Cell<u32>,
429 ignore_opens_during_unload_counter: Cell<u32>,
431 spurious_animation_frames: Cell<u8>,
435
436 dom_count: Cell<u32>,
442 fullscreen_element: MutNullableDom<Element>,
444 form_id_listener_map:
451 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
452 #[no_trace]
453 interactive_time: DomRefCell<ProgressiveWebMetrics>,
454 #[no_trace]
455 tti_window: DomRefCell<InteractiveWindow>,
456 canceller: FetchCanceller,
458 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
460 page_showing: Cell<bool>,
462 salvageable: Cell<bool>,
464 active_parser_was_aborted: Cell<bool>,
466 fired_unload: Cell<bool>,
468 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
470 redirect_count: Cell<u16>,
472 script_and_layout_blockers: Cell<u32>,
474 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
476 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
477 completely_loaded: Cell<bool>,
479 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
481 shadow_roots_styles_changed: Cell<bool>,
483 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
489 dirty_2d_contexts:
491 DomRefCell<HashMapTracedValues<CanvasId, Dom<CanvasRenderingContext2D>, FxBuildHasher>>,
492 dirty_webgl_contexts:
494 DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>, FxBuildHasher>>,
495 has_pending_animated_image_update: Cell<bool>,
497 #[cfg(feature = "webgpu")]
499 dirty_webgpu_contexts:
500 DomRefCell<HashMapTracedValues<WebGPUContextId, Dom<GPUCanvasContext>, FxBuildHasher>>,
501 selection: MutNullableDom<Selection>,
503 animation_timeline: DomRefCell<AnimationTimeline>,
506 animations: DomRefCell<Animations>,
508 image_animation_manager: DomRefCell<ImageAnimationManager>,
510 dirty_root: MutNullableDom<Element>,
512 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
514 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
523 fonts: MutNullableDom<FontFaceSet>,
526 visibility_state: Cell<DocumentVisibilityState>,
528 status_code: Option<u16>,
530 is_initial_about_blank: Cell<bool>,
532 allow_declarative_shadow_roots: Cell<bool>,
534 #[no_trace]
536 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
537 has_trustworthy_ancestor_origin: Cell<bool>,
539 intersection_observer_task_queued: Cell<bool>,
541 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
553 highlighted_dom_node: MutNullableDom<Node>,
555 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
558 #[ignore_malloc_size_of = "mozjs"]
560 adopted_stylesheets_frozen_types: CachedFrozenArray,
561 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
563 resize_observer_started_observing_target: Cell<bool>,
566 waiting_on_canvas_image_updates: Cell<bool>,
570 #[no_trace]
578 current_rendering_epoch: Cell<Epoch>,
579 #[conditional_malloc_size_of]
581 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
582 #[no_trace]
583 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
585 #[no_trace]
586 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
593 #[no_trace]
595 #[ignore_malloc_size_of = "TODO: unimplemented on Image"]
596 favicon: RefCell<Option<Image>>,
597}
598
599#[allow(non_snake_case)]
600impl Document {
601 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
602 debug_assert!(*node.owner_doc() == *self);
603 if !node.is_connected() {
604 return;
605 }
606
607 let parent = match node.parent_in_flat_tree() {
608 Some(parent) => parent,
609 None => {
610 let document_element = match self.GetDocumentElement() {
613 Some(element) => element,
614 None => return,
615 };
616 if let Some(dirty_root) = self.dirty_root.get() {
617 for ancestor in dirty_root
620 .upcast::<Node>()
621 .inclusive_ancestors_in_flat_tree()
622 {
623 if ancestor.is::<Element>() {
624 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
625 }
626 }
627 }
628 self.dirty_root.set(Some(&document_element));
629 return;
630 },
631 };
632
633 if parent.is::<Element>() {
634 if !parent.is_styled() {
635 return;
636 }
637
638 if parent.is_display_none() {
639 return;
640 }
641 }
642
643 let element_parent: DomRoot<Element>;
644 let element = match node.downcast::<Element>() {
645 Some(element) => element,
646 None => {
647 match DomRoot::downcast::<Element>(parent) {
650 Some(parent) => {
651 element_parent = parent;
652 &element_parent
653 },
654 None => {
655 return;
659 },
660 }
661 },
662 };
663
664 let dirty_root = match self.dirty_root.get() {
665 None => {
666 element
667 .upcast::<Node>()
668 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
669 self.dirty_root.set(Some(element));
670 return;
671 },
672 Some(root) => root,
673 };
674
675 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
676 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
677 return;
678 }
679
680 if ancestor.is::<Element>() {
681 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
682 }
683 }
684
685 let new_dirty_root = element
686 .upcast::<Node>()
687 .common_ancestor_in_flat_tree(dirty_root.upcast())
688 .expect("Couldn't find common ancestor");
689
690 let mut has_dirty_descendants = true;
691 for ancestor in dirty_root
692 .upcast::<Node>()
693 .inclusive_ancestors_in_flat_tree()
694 {
695 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
696 has_dirty_descendants &= *ancestor != *new_dirty_root;
697 }
698
699 self.dirty_root
700 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
701 }
702
703 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
704 self.dirty_root.take()
705 }
706
707 #[inline]
708 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
709 self.loader.borrow()
710 }
711
712 #[inline]
713 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
714 self.loader.borrow_mut()
715 }
716
717 #[inline]
718 pub(crate) fn has_browsing_context(&self) -> bool {
719 self.has_browsing_context
720 }
721
722 #[inline]
724 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
725 if self.has_browsing_context {
726 self.window.undiscarded_window_proxy()
727 } else {
728 None
729 }
730 }
731
732 pub(crate) fn webview_id(&self) -> WebViewId {
733 self.window.webview_id()
734 }
735
736 #[inline]
737 pub(crate) fn window(&self) -> &Window {
738 &self.window
739 }
740
741 #[inline]
742 pub(crate) fn is_html_document(&self) -> bool {
743 self.is_html_document
744 }
745
746 pub(crate) fn is_xhtml_document(&self) -> bool {
747 self.content_type.matches(APPLICATION, "xhtml+xml")
748 }
749
750 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
751 self.https_state.set(https_state);
752 }
753
754 pub(crate) fn is_fully_active(&self) -> bool {
755 self.activity.get() == DocumentActivity::FullyActive
756 }
757
758 pub(crate) fn is_active(&self) -> bool {
759 self.activity.get() != DocumentActivity::Inactive
760 }
761
762 #[inline]
763 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
764 self.current_rendering_epoch.get()
765 }
766
767 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
768 assert!(self.has_browsing_context);
770 if activity == self.activity.get() {
771 return;
772 }
773
774 self.activity.set(activity);
776 let media = ServoMedia::get();
777 let pipeline_id = self.window().pipeline_id();
778 let client_context_id =
779 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
780
781 if activity != DocumentActivity::FullyActive {
782 self.window().suspend(can_gc);
783 media.suspend(&client_context_id);
784 return;
785 }
786
787 self.title_changed();
788 self.notify_embedder_favicon();
789 self.dirty_all_nodes();
790 self.window().resume(can_gc);
791 media.resume(&client_context_id);
792
793 if self.ready_state.get() != DocumentReadyState::Complete {
794 return;
795 }
796
797 let document = Trusted::new(self);
801 self.owner_global()
802 .task_manager()
803 .dom_manipulation_task_source()
804 .queue(task!(fire_pageshow_event: move || {
805 let document = document.root();
806 let window = document.window();
807 if document.page_showing.get() {
809 return;
810 }
811 document.page_showing.set(true);
813 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
815 let event = PageTransitionEvent::new(
818 window,
819 atom!("pageshow"),
820 false, false, true, CanGc::note(),
824 );
825 let event = event.upcast::<Event>();
826 event.set_trusted(true);
827 window.dispatch_event_with_target_override(event, CanGc::note());
828 }))
829 }
830
831 pub(crate) fn origin(&self) -> &MutableOrigin {
832 &self.origin
833 }
834
835 pub(crate) fn url(&self) -> ServoUrl {
837 self.url.borrow().clone()
838 }
839
840 pub(crate) fn set_url(&self, url: ServoUrl) {
841 *self.url.borrow_mut() = url;
842 }
843
844 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
846 let document_url = self.url();
848 if document_url.as_str() == "about:srcdoc" {
849 let base_url = self
850 .browsing_context()
851 .and_then(|browsing_context| browsing_context.creator_base_url());
852
853 if base_url.is_none() {
855 error!("about:srcdoc page should always have a creator base URL");
856 }
857
858 return base_url.unwrap_or(document_url);
860 }
861
862 if document_url.matches_about_blank() {
865 return self
866 .browsing_context()
867 .and_then(|browsing_context| browsing_context.creator_base_url())
868 .unwrap_or(document_url);
869 }
870
871 document_url
873 }
874
875 pub(crate) fn base_url(&self) -> ServoUrl {
877 match self.base_element() {
878 None => self.fallback_base_url(),
880 Some(base) => base.frozen_base_url(),
882 }
883 }
884
885 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
886 self.needs_restyle.set(self.needs_restyle.get() | reason)
887 }
888
889 pub(crate) fn clear_restyle_reasons(&self) {
890 self.needs_restyle.set(RestyleReason::empty());
891 }
892
893 pub(crate) fn restyle_reason(&self) -> RestyleReason {
894 let mut condition = self.needs_restyle.get();
895 if self.stylesheets.borrow().has_changed() {
896 condition.insert(RestyleReason::StylesheetsChanged);
897 }
898
899 if let Some(root) = self.GetDocumentElement() {
903 if root.upcast::<Node>().has_dirty_descendants() {
904 condition.insert(RestyleReason::DOMChanged);
905 }
906 }
907
908 if !self.pending_restyles.borrow().is_empty() {
909 condition.insert(RestyleReason::PendingRestyles);
910 }
911
912 condition
913 }
914
915 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
917 self.base_element.get()
918 }
919
920 pub(crate) fn refresh_base_element(&self) {
923 let base = self
924 .upcast::<Node>()
925 .traverse_preorder(ShadowIncluding::No)
926 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
927 .find(|element| {
928 element
929 .upcast::<Element>()
930 .has_attribute(&local_name!("href"))
931 });
932 self.base_element.set(base.as_deref());
933 }
934
935 pub(crate) fn dom_count(&self) -> u32 {
936 self.dom_count.get()
937 }
938
939 pub(crate) fn increment_dom_count(&self) {
943 self.dom_count.set(self.dom_count.get() + 1);
944 }
945
946 pub(crate) fn decrement_dom_count(&self) {
948 self.dom_count.set(self.dom_count.get() - 1);
949 }
950
951 pub(crate) fn quirks_mode(&self) -> QuirksMode {
952 self.quirks_mode.get()
953 }
954
955 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
956 let old_mode = self.quirks_mode.replace(new_mode);
957
958 if old_mode != new_mode {
959 self.window.layout_mut().set_quirks_mode(new_mode);
960 }
961 }
962
963 pub(crate) fn encoding(&self) -> &'static Encoding {
964 self.encoding.get()
965 }
966
967 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
968 self.encoding.set(encoding);
969 }
970
971 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
972 if node.is_connected() {
973 node.note_dirty_descendants();
974 }
975
976 node.dirty(NodeDamage::ContentOrHeritage);
979 }
980
981 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
983 self.document_or_shadow_root
984 .unregister_named_element(&self.id_map, to_unregister, &id);
985 self.reset_form_owner_for_listeners(&id, can_gc);
986 }
987
988 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
990 let root = self.GetDocumentElement().expect(
991 "The element is in the document, so there must be a document \
992 element.",
993 );
994 self.document_or_shadow_root.register_named_element(
995 &self.id_map,
996 element,
997 &id,
998 DomRoot::from_ref(root.upcast::<Node>()),
999 );
1000 self.reset_form_owner_for_listeners(&id, can_gc);
1001 }
1002
1003 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1005 self.document_or_shadow_root
1006 .unregister_named_element(&self.name_map, to_unregister, &name);
1007 }
1008
1009 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1011 let root = self.GetDocumentElement().expect(
1012 "The element is in the document, so there must be a document \
1013 element.",
1014 );
1015 self.document_or_shadow_root.register_named_element(
1016 &self.name_map,
1017 element,
1018 &name,
1019 DomRoot::from_ref(root.upcast::<Node>()),
1020 );
1021 }
1022
1023 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1024 &self,
1025 id: DOMString,
1026 listener: &T,
1027 ) {
1028 let mut map = self.form_id_listener_map.borrow_mut();
1029 let listener = listener.to_element();
1030 let set = map.entry(Atom::from(id)).or_default();
1031 set.insert(Dom::from_ref(listener));
1032 }
1033
1034 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1035 &self,
1036 id: DOMString,
1037 listener: &T,
1038 ) {
1039 let mut map = self.form_id_listener_map.borrow_mut();
1040 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1041 entry
1042 .get_mut()
1043 .remove(&Dom::from_ref(listener.to_element()));
1044 if entry.get().is_empty() {
1045 entry.remove();
1046 }
1047 }
1048 }
1049
1050 pub(crate) fn find_fragment_node(&self, fragid: &str) -> Option<DomRoot<Element>> {
1053 percent_decode(fragid.as_bytes())
1057 .decode_utf8()
1058 .ok()
1059 .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
1061 .or_else(|| self.get_anchor_by_name(fragid))
1063 }
1065
1066 pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) {
1070 let target = self.find_fragment_node(fragment);
1071
1072 self.set_target_element(target.as_deref());
1074
1075 let point = target
1076 .as_ref()
1077 .map(|element| {
1078 let rect = element.upcast::<Node>().border_box().unwrap_or_default();
1083
1084 let device_pixel_ratio = self.window.device_pixel_ratio().get();
1089 (
1090 rect.origin.x.to_nearest_pixel(device_pixel_ratio),
1091 rect.origin.y.to_nearest_pixel(device_pixel_ratio),
1092 )
1093 })
1094 .or_else(|| {
1095 if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
1096 Some((0.0, 0.0))
1099 } else {
1100 None
1101 }
1102 });
1103
1104 if let Some((x, y)) = point {
1105 self.window.scroll(x, y, ScrollBehavior::Instant)
1106 }
1107 }
1108
1109 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1110 let name = Atom::from(name);
1111 self.name_map.borrow().get(&name).and_then(|elements| {
1112 elements
1113 .iter()
1114 .find(|e| e.is::<HTMLAnchorElement>())
1115 .map(|e| DomRoot::from_ref(&**e))
1116 })
1117 }
1118
1119 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1121 match state {
1122 DocumentReadyState::Loading => {
1123 if self.window().is_top_level() {
1124 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1125 self.webview_id(),
1126 LoadStatus::Started,
1127 ));
1128 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1129 }
1130 },
1131 DocumentReadyState::Complete => {
1132 if self.window().is_top_level() {
1133 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1134 self.webview_id(),
1135 LoadStatus::Complete,
1136 ));
1137 }
1138 update_with_current_instant(&self.dom_complete);
1139 },
1140 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1141 };
1142
1143 self.ready_state.set(state);
1144
1145 self.upcast::<EventTarget>()
1146 .fire_event(atom!("readystatechange"), can_gc);
1147 }
1148
1149 pub(crate) fn scripting_enabled(&self) -> bool {
1152 self.has_browsing_context() &&
1155 !self.has_active_sandboxing_flag(
1159 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1160 )
1161 }
1162
1163 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1166 self.focused.get()
1167 }
1168
1169 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1174 self.focus_sequence.get()
1175 }
1176
1177 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1179 self.focus_sequence.set(FocusSequenceNumber(
1180 self.focus_sequence
1181 .get()
1182 .0
1183 .checked_add(1)
1184 .expect("too many focus messages have been sent"),
1185 ));
1186 self.focus_sequence.get()
1187 }
1188
1189 pub(crate) fn has_focus_transaction(&self) -> bool {
1190 self.focus_transaction.borrow().is_some()
1191 }
1192
1193 pub(crate) fn begin_focus_transaction(&self) {
1196 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1198 element: self.focused.get().as_deref().map(Dom::from_ref),
1199 has_focus: self.has_focus.get(),
1200 focus_options: FocusOptions {
1201 preventScroll: true,
1202 },
1203 });
1204 }
1205
1206 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1208 if Some(not_focusable) != self.focused.get().as_deref() {
1211 return;
1212 }
1213
1214 let implicit_transaction = self.focus_transaction.borrow().is_none();
1215
1216 if implicit_transaction {
1217 self.begin_focus_transaction();
1218 }
1219
1220 {
1223 let mut focus_transaction = self.focus_transaction.borrow_mut();
1224 focus_transaction.as_mut().unwrap().element = None;
1225 }
1226
1227 if implicit_transaction {
1228 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1229 }
1230 }
1231
1232 pub(crate) fn request_focus(
1235 &self,
1236 elem: Option<&Element>,
1237 focus_initiator: FocusInitiator,
1238 can_gc: CanGc,
1239 ) {
1240 self.request_focus_with_options(
1241 elem,
1242 focus_initiator,
1243 FocusOptions {
1244 preventScroll: true,
1245 },
1246 can_gc,
1247 );
1248 }
1249
1250 pub(crate) fn request_focus_with_options(
1256 &self,
1257 elem: Option<&Element>,
1258 focus_initiator: FocusInitiator,
1259 focus_options: FocusOptions,
1260 can_gc: CanGc,
1261 ) {
1262 if elem.is_some_and(|e| !e.is_focusable_area()) {
1265 return;
1266 }
1267
1268 let implicit_transaction = self.focus_transaction.borrow().is_none();
1269
1270 if implicit_transaction {
1271 self.begin_focus_transaction();
1272 }
1273
1274 {
1275 let mut focus_transaction = self.focus_transaction.borrow_mut();
1276 let focus_transaction = focus_transaction.as_mut().unwrap();
1277 focus_transaction.element = elem.map(Dom::from_ref);
1278 focus_transaction.has_focus = true;
1279 focus_transaction.focus_options = focus_options;
1280 }
1281
1282 if implicit_transaction {
1283 self.commit_focus_transaction(focus_initiator, can_gc);
1284 }
1285 }
1286
1287 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1291 if self.window().parent_info().is_none() {
1292 warn!("Top-level document cannot be unfocused");
1293 return;
1294 }
1295
1296 assert!(
1299 self.focus_transaction.borrow().is_none(),
1300 "there mustn't be an in-progress focus transaction at this point"
1301 );
1302
1303 self.begin_focus_transaction();
1305
1306 {
1308 let mut focus_transaction = self.focus_transaction.borrow_mut();
1309 focus_transaction.as_mut().unwrap().has_focus = false;
1310 }
1311
1312 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1314 }
1315
1316 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1319 let (mut new_focused, new_focus_state, prevent_scroll) = {
1320 let focus_transaction = self.focus_transaction.borrow();
1321 let focus_transaction = focus_transaction
1322 .as_ref()
1323 .expect("no focus transaction in progress");
1324 (
1325 focus_transaction
1326 .element
1327 .as_ref()
1328 .map(|e| DomRoot::from_ref(&**e)),
1329 focus_transaction.has_focus,
1330 focus_transaction.focus_options.preventScroll,
1331 )
1332 };
1333 *self.focus_transaction.borrow_mut() = None;
1334
1335 if !new_focus_state {
1336 if new_focused.take().is_some() {
1339 trace!(
1340 "Forgetting the document's focused area because the \
1341 document's container was removed from the top-level BC's \
1342 focus chain"
1343 );
1344 }
1345 }
1346
1347 let old_focused = self.focused.get();
1348 let old_focus_state = self.has_focus.get();
1349
1350 debug!(
1351 "Committing focus transaction: {:?} → {:?}",
1352 (&old_focused, old_focus_state),
1353 (&new_focused, new_focus_state),
1354 );
1355
1356 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1359 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1360
1361 let trace_focus_chain = |name, element, doc| {
1362 trace!(
1363 "{} local focus chain: {}",
1364 name,
1365 match (element, doc) {
1366 (Some(e), _) => format!("[{:?}, document]", e),
1367 (None, true) => "[document]".to_owned(),
1368 (None, false) => "[]".to_owned(),
1369 }
1370 );
1371 };
1372
1373 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1374 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1375
1376 if old_focused_filtered != new_focused_filtered {
1377 if let Some(elem) = &old_focused_filtered {
1378 let node = elem.upcast::<Node>();
1379 elem.set_focus_state(false);
1380 if node.is_connected() {
1382 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1383 }
1384
1385 if elem.input_method_type().is_some() {
1387 self.send_to_embedder(EmbedderMsg::HideIME(self.webview_id()));
1388 }
1389 }
1390 }
1391
1392 if old_focus_state != new_focus_state && !new_focus_state {
1393 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1394 }
1395
1396 self.focused.set(new_focused.as_deref());
1397 self.has_focus.set(new_focus_state);
1398
1399 if old_focus_state != new_focus_state && new_focus_state {
1400 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1401 }
1402
1403 if old_focused_filtered != new_focused_filtered {
1404 if let Some(elem) = &new_focused_filtered {
1405 elem.set_focus_state(true);
1406 let node = elem.upcast::<Node>();
1407 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1409
1410 if let Some(kind) = elem.input_method_type() {
1412 let rect = elem.upcast::<Node>().border_box().unwrap_or_default();
1413 let rect = Rect::new(
1414 Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()),
1415 Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()),
1416 );
1417 let (text, multiline) = if let Some(input) = elem.downcast::<HTMLInputElement>()
1418 {
1419 (
1420 Some((
1421 (input.Value()).to_string(),
1422 input.GetSelectionEnd().unwrap_or(0) as i32,
1423 )),
1424 false,
1425 )
1426 } else if let Some(textarea) = elem.downcast::<HTMLTextAreaElement>() {
1427 (
1428 Some((
1429 (textarea.Value()).to_string(),
1430 textarea.GetSelectionEnd().unwrap_or(0) as i32,
1431 )),
1432 true,
1433 )
1434 } else {
1435 (None, false)
1436 };
1437 self.send_to_embedder(EmbedderMsg::ShowIME(
1438 self.webview_id(),
1439 kind,
1440 text,
1441 multiline,
1442 DeviceIntRect::from_untyped(&rect.to_box2d()),
1443 ));
1444 }
1445 if !prevent_scroll {
1449 elem.ScrollIntoView(BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(
1450 ScrollIntoViewOptions {
1451 parent: ScrollOptions {
1452 behavior: ScrollBehavior::Smooth,
1453 },
1454 block: ScrollLogicalPosition::Center,
1455 inline: ScrollLogicalPosition::Center,
1456 container: ScrollIntoViewContainer::All,
1457 },
1458 ));
1459 }
1460 }
1461 }
1462
1463 if focus_initiator != FocusInitiator::Local {
1464 return;
1465 }
1466
1467 match (old_focus_state, new_focus_state) {
1470 (_, true) => {
1471 let child_browsing_context_id = new_focused
1492 .as_ref()
1493 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1494 .and_then(|iframe| iframe.browsing_context_id());
1495
1496 let sequence = self.increment_fetch_focus_sequence();
1497
1498 debug!(
1499 "Advertising the focus request to the constellation \
1500 with sequence number {} and child BC ID {}",
1501 sequence,
1502 child_browsing_context_id
1503 .as_ref()
1504 .map(|id| id as &dyn std::fmt::Display)
1505 .unwrap_or(&"(none)"),
1506 );
1507
1508 self.window()
1509 .send_to_constellation(ScriptToConstellationMessage::Focus(
1510 child_browsing_context_id,
1511 sequence,
1512 ));
1513 },
1514 (false, false) => {
1515 },
1518 (true, false) => {
1519 unreachable!(
1520 "Can't lose the document's focus without specifying \
1521 another one to focus"
1522 );
1523 },
1524 }
1525 }
1526
1527 pub(crate) fn title_changed(&self) {
1529 if self.browsing_context().is_some() {
1530 self.send_title_to_embedder();
1531 let title = String::from(self.Title());
1532 self.window
1533 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1534 self.window.pipeline_id(),
1535 title.clone(),
1536 ));
1537 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1538 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1539 self.window.pipeline_id(),
1540 title,
1541 ));
1542 }
1543 }
1544 }
1545
1546 fn title(&self) -> Option<DOMString> {
1550 let title = self.GetDocumentElement().and_then(|root| {
1551 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1552 root.upcast::<Node>()
1554 .child_elements()
1555 .find(|node| {
1556 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1557 })
1558 .map(DomRoot::upcast::<Node>)
1559 } else {
1560 root.upcast::<Node>()
1562 .traverse_preorder(ShadowIncluding::No)
1563 .find(|node| node.is::<HTMLTitleElement>())
1564 }
1565 });
1566
1567 title.map(|title| {
1568 let value = title.child_text_content();
1570 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1571 })
1572 }
1573
1574 pub(crate) fn send_title_to_embedder(&self) {
1576 let window = self.window();
1577 if window.is_top_level() {
1578 let title = self.title().map(String::from);
1579 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1580 }
1581 }
1582
1583 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1584 let window = self.window();
1585 window.send_to_embedder(msg);
1586 }
1587
1588 pub(crate) fn dirty_all_nodes(&self) {
1589 let root = match self.GetDocumentElement() {
1590 Some(root) => root,
1591 None => return,
1592 };
1593 for node in root
1594 .upcast::<Node>()
1595 .traverse_preorder(ShadowIncluding::Yes)
1596 {
1597 node.dirty(NodeDamage::Other)
1598 }
1599 }
1600
1601 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1603 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1615 for target in notify_list.iter() {
1616 if target.downcast::<Document>().is_some() {
1617 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1620 } else if target.downcast::<Element>().is_some() {
1621 target.fire_event(Atom::from("scroll"), can_gc);
1624 }
1625 }
1626
1627 }
1631
1632 pub(crate) fn handle_viewport_scroll_event(&self) {
1636 let target = self.upcast::<EventTarget>();
1645 if self
1646 .pending_scroll_event_targets
1647 .borrow()
1648 .iter()
1649 .any(|other_target| *other_target == target)
1650 {
1651 return;
1652 }
1653
1654 self.pending_scroll_event_targets
1657 .borrow_mut()
1658 .push(Dom::from_ref(target));
1659 }
1660
1661 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1665 let target = element.upcast::<EventTarget>();
1675 if self
1676 .pending_scroll_event_targets
1677 .borrow()
1678 .iter()
1679 .any(|other_target| *other_target == target)
1680 {
1681 return;
1682 }
1683
1684 self.pending_scroll_event_targets
1687 .borrow_mut()
1688 .push(Dom::from_ref(target));
1689 }
1690
1691 pub(crate) fn node_from_nodes_and_strings(
1693 &self,
1694 mut nodes: Vec<NodeOrString>,
1695 can_gc: CanGc,
1696 ) -> Fallible<DomRoot<Node>> {
1697 if nodes.len() == 1 {
1698 Ok(match nodes.pop().unwrap() {
1699 NodeOrString::Node(node) => node,
1700 NodeOrString::String(string) => {
1701 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1702 },
1703 })
1704 } else {
1705 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1706 for node in nodes {
1707 match node {
1708 NodeOrString::Node(node) => {
1709 fragment.AppendChild(&node, can_gc)?;
1710 },
1711 NodeOrString::String(string) => {
1712 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1713 fragment.AppendChild(&node, can_gc).unwrap();
1716 },
1717 }
1718 }
1719 Ok(fragment)
1720 }
1721 }
1722
1723 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1724 match self.GetBody() {
1725 Some(ref body) if body.is_body_element() => {
1726 body.upcast::<Element>().get_string_attribute(local_name)
1727 },
1728 _ => DOMString::new(),
1729 }
1730 }
1731
1732 pub(crate) fn set_body_attribute(
1733 &self,
1734 local_name: &LocalName,
1735 value: DOMString,
1736 can_gc: CanGc,
1737 ) {
1738 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1739 let body = body.upcast::<Element>();
1740 let value = body.parse_attribute(&ns!(), local_name, value);
1741 body.set_attribute(local_name, value, can_gc);
1742 }
1743 }
1744
1745 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1746 self.current_script.set(script);
1747 }
1748
1749 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1750 self.script_blocking_stylesheets_count.get()
1751 }
1752
1753 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1754 let count_cell = &self.script_blocking_stylesheets_count;
1755 count_cell.set(count_cell.get() + 1);
1756 }
1757
1758 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1759 let count_cell = &self.script_blocking_stylesheets_count;
1760 assert!(count_cell.get() > 0);
1761 count_cell.set(count_cell.get() - 1);
1762 }
1763
1764 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1765 self.render_blocking_element_count.get()
1766 }
1767
1768 pub(crate) fn increment_render_blocking_element_count(&self) {
1769 let count_cell = &self.render_blocking_element_count;
1770 count_cell.set(count_cell.get() + 1);
1771 }
1772
1773 pub(crate) fn decrement_render_blocking_element_count(&self) {
1774 let count_cell = &self.render_blocking_element_count;
1775 assert!(count_cell.get() > 0);
1776 count_cell.set(count_cell.get() - 1);
1777 }
1778
1779 pub(crate) fn invalidate_stylesheets(&self) {
1780 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1781
1782 if let Some(element) = self.GetDocumentElement() {
1786 element.upcast::<Node>().dirty(NodeDamage::Style);
1787 }
1788 }
1789
1790 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1793 !self.animation_frame_list.borrow().is_empty()
1794 }
1795
1796 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1798 let ident = self.animation_frame_ident.get() + 1;
1799 self.animation_frame_ident.set(ident);
1800
1801 let had_animation_frame_callbacks;
1802 {
1803 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1804 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1805 animation_frame_list.push_back((ident, Some(callback)));
1806 }
1807
1808 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1814 self.window().send_to_constellation(
1815 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1816 AnimationState::AnimationCallbacksPresent,
1817 ),
1818 );
1819 }
1820
1821 ident
1822 }
1823
1824 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1826 let mut list = self.animation_frame_list.borrow_mut();
1827 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1828 pair.1 = None;
1829 }
1830 }
1831
1832 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1834 let _realm = enter_realm(self);
1835
1836 self.running_animation_callbacks.set(true);
1837 let timing = self.global().performance().Now();
1838
1839 let num_callbacks = self.animation_frame_list.borrow().len();
1840 for _ in 0..num_callbacks {
1841 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1842 if let Some(callback) = maybe_callback {
1843 callback.call(self, *timing, can_gc);
1844 }
1845 }
1846 self.running_animation_callbacks.set(false);
1847
1848 if self.animation_frame_list.borrow().is_empty() {
1849 self.window().send_to_constellation(
1850 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1851 AnimationState::NoAnimationCallbacksPresent,
1852 ),
1853 );
1854 }
1855 }
1856
1857 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1858 self.policy_container.borrow()
1859 }
1860
1861 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1862 *self.policy_container.borrow_mut() = policy_container;
1863 }
1864
1865 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1866 self.policy_container.borrow_mut().set_csp_list(csp_list);
1867 }
1868
1869 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1870 self.policy_container.borrow().csp_list.clone()
1871 }
1872
1873 pub(crate) fn prepare_request(&self, request: RequestBuilder) -> RequestBuilder {
1877 request
1878 .policy_container(self.policy_container().to_owned())
1879 .https_state(self.https_state.get())
1880 }
1881
1882 pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1883 &self,
1884 load: LoadType,
1885 mut request: RequestBuilder,
1886 listener: Listener,
1887 ) {
1888 request = request
1889 .insecure_requests_policy(self.insecure_requests_policy())
1890 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1891 let callback = NetworkListener {
1892 context: std::sync::Arc::new(Mutex::new(listener)),
1893 task_source: self
1894 .owner_global()
1895 .task_manager()
1896 .networking_task_source()
1897 .into(),
1898 }
1899 .into_callback();
1900 self.loader_mut()
1901 .fetch_async_with_callback(load, request, callback);
1902 }
1903
1904 pub(crate) fn fetch_background<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1905 &self,
1906 mut request: RequestBuilder,
1907 listener: Listener,
1908 ) {
1909 request = request
1910 .insecure_requests_policy(self.insecure_requests_policy())
1911 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1912 let callback = NetworkListener {
1913 context: std::sync::Arc::new(Mutex::new(listener)),
1914 task_source: self
1915 .owner_global()
1916 .task_manager()
1917 .networking_task_source()
1918 .into(),
1919 }
1920 .into_callback();
1921 self.loader_mut().fetch_async_background(request, callback);
1922 }
1923
1924 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
1927 debug!("Document got finish_load: {:?}", load);
1929 self.loader.borrow_mut().finish_load(&load);
1930
1931 match load {
1932 LoadType::Stylesheet(_) => {
1933 self.process_pending_parsing_blocking_script(can_gc);
1936
1937 self.process_deferred_scripts(can_gc);
1939 },
1940 LoadType::PageSource(_) => {
1941 if self.has_browsing_context && self.is_fully_active() {
1944 self.window().allow_layout_if_necessary();
1945 }
1946
1947 self.process_deferred_scripts(can_gc);
1952 },
1953 _ => {},
1954 }
1955
1956 let loader = self.loader.borrow();
1963
1964 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1966 update_with_current_instant(&self.top_level_dom_complete);
1967 }
1968
1969 if loader.is_blocked() || loader.events_inhibited() {
1970 return;
1972 }
1973
1974 ScriptThread::mark_document_with_no_blocked_loads(self);
1975 }
1976
1977 pub(crate) fn prompt_to_unload(&self, recursive_flag: bool, can_gc: CanGc) -> bool {
1979 self.incr_ignore_opens_during_unload_counter();
1982 let beforeunload_event = BeforeUnloadEvent::new(
1984 &self.window,
1985 atom!("beforeunload"),
1986 EventBubbles::Bubbles,
1987 EventCancelable::Cancelable,
1988 can_gc,
1989 );
1990 let event = beforeunload_event.upcast::<Event>();
1991 event.set_trusted(true);
1992 let event_target = self.window.upcast::<EventTarget>();
1993 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
1994 self.window
1995 .dispatch_event_with_target_override(event, can_gc);
1996 if has_listeners {
1999 self.salvageable.set(false);
2000 }
2001 let mut can_unload = true;
2002 let default_prevented = event.DefaultPrevented();
2004 let return_value_not_empty = !event
2005 .downcast::<BeforeUnloadEvent>()
2006 .unwrap()
2007 .ReturnValue()
2008 .is_empty();
2009 if default_prevented || return_value_not_empty {
2010 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2011 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2012 self.send_to_embedder(msg);
2013 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2014 }
2015 if !recursive_flag {
2017 let iframes: Vec<_> = self.iframes().iter().collect();
2020 for iframe in &iframes {
2021 let document = iframe.owner_document();
2023 can_unload = document.prompt_to_unload(true, can_gc);
2024 if !document.salvageable() {
2025 self.salvageable.set(false);
2026 }
2027 if !can_unload {
2028 break;
2029 }
2030 }
2031 }
2032 self.decr_ignore_opens_during_unload_counter();
2034 can_unload
2035 }
2036
2037 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2039 self.incr_ignore_opens_during_unload_counter();
2042 if self.page_showing.get() {
2044 self.page_showing.set(false);
2046 let event = PageTransitionEvent::new(
2049 &self.window,
2050 atom!("pagehide"),
2051 false, false, self.salvageable.get(), can_gc,
2055 );
2056 let event = event.upcast::<Event>();
2057 event.set_trusted(true);
2058 self.window
2059 .dispatch_event_with_target_override(event, can_gc);
2060 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2062 }
2063 if !self.fired_unload.get() {
2065 let event = Event::new(
2066 self.window.upcast(),
2067 atom!("unload"),
2068 EventBubbles::Bubbles,
2069 EventCancelable::Cancelable,
2070 can_gc,
2071 );
2072 event.set_trusted(true);
2073 let event_target = self.window.upcast::<EventTarget>();
2074 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2075 self.window
2076 .dispatch_event_with_target_override(&event, can_gc);
2077 self.fired_unload.set(true);
2078 if has_listeners {
2080 self.salvageable.set(false);
2081 }
2082 }
2083 if !recursive_flag {
2087 let iframes: Vec<_> = self.iframes().iter().collect();
2090 for iframe in &iframes {
2091 let document = iframe.owner_document();
2093 document.unload(true, can_gc);
2094 if !document.salvageable() {
2095 self.salvageable.set(false);
2096 }
2097 }
2098 }
2099
2100 let global_scope = self.window.as_global_scope();
2101 if !self.salvageable.get() {
2104 global_scope.close_event_sources();
2106 let msg = ScriptToConstellationMessage::DiscardDocument;
2107 let _ = global_scope.script_to_constellation_chan().send(msg);
2108 }
2109 global_scope.clean_up_all_file_resources();
2111
2112 self.decr_ignore_opens_during_unload_counter();
2114 }
2115
2116 pub(crate) fn maybe_queue_document_completion(&self) {
2118 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2120 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2121 None => false,
2122 };
2123
2124 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2129 !self.is_fully_active() ||
2130 is_in_delaying_load_events_mode;
2131
2132 if not_ready_for_load {
2133 return;
2135 }
2136
2137 assert!(!self.loader.borrow().events_inhibited());
2138 self.loader.borrow_mut().inhibit_events();
2139
2140 debug!("Document loads are complete.");
2143 let document = Trusted::new(self);
2144 self.owner_global()
2145 .task_manager()
2146 .dom_manipulation_task_source()
2147 .queue(task!(fire_load_event: move || {
2148 let document = document.root();
2149 let window = document.window();
2150 if !window.is_alive() {
2151 return;
2152 }
2153
2154 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2156
2157 if document.browsing_context().is_none() {
2159 return;
2160 }
2161 let event = Event::new(
2162 window.upcast(),
2163 atom!("load"),
2164 EventBubbles::DoesNotBubble,
2165 EventCancelable::NotCancelable,
2166 CanGc::note(),
2167 );
2168 event.set_trusted(true);
2169
2170 update_with_current_instant(&document.load_event_start);
2172
2173 debug!("About to dispatch load for {:?}", document.url());
2174 window.dispatch_event_with_target_override(&event, CanGc::note());
2175
2176 update_with_current_instant(&document.load_event_end);
2178
2179 if let Some(fragment) = document.url().fragment() {
2180 document.check_and_scroll_fragment(fragment);
2181 }
2182 }));
2183
2184 let document = Trusted::new(self);
2186 if document.root().browsing_context().is_some() {
2187 self.owner_global()
2188 .task_manager()
2189 .dom_manipulation_task_source()
2190 .queue(task!(fire_pageshow_event: move || {
2191 let document = document.root();
2192 let window = document.window();
2193 if document.page_showing.get() || !window.is_alive() {
2194 return;
2195 }
2196
2197 document.page_showing.set(true);
2198
2199 let event = PageTransitionEvent::new(
2200 window,
2201 atom!("pageshow"),
2202 false, false, false, CanGc::note(),
2206 );
2207 let event = event.upcast::<Event>();
2208 event.set_trusted(true);
2209
2210 window.dispatch_event_with_target_override(event, CanGc::note());
2211 }));
2212 }
2213
2214 #[cfg(feature = "webxr")]
2229 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2230 self.window.Navigator().Xr().dispatch_sessionavailable();
2231 }
2232
2233 let document = Trusted::new(self);
2237 if document.root().browsing_context().is_some() {
2238 self.owner_global()
2239 .task_manager()
2240 .dom_manipulation_task_source()
2241 .queue(task!(completely_loaded: move || {
2242 let document = document.root();
2243 document.completely_loaded.set(true);
2244 if let Some(DeclarativeRefresh::PendingLoad {
2245 url,
2246 time
2247 }) = &*document.declarative_refresh.borrow() {
2248 document.window.as_global_scope().schedule_callback(
2250 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2251 window: DomRoot::from_ref(document.window()),
2252 url: url.clone(),
2253 }),
2254 Duration::from_secs(*time),
2255 );
2256 }
2257 document.notify_constellation_load();
2260 }));
2261 }
2262 }
2263
2264 pub(crate) fn completely_loaded(&self) -> bool {
2265 self.completely_loaded.get()
2266 }
2267
2268 pub(crate) fn set_pending_parsing_blocking_script(
2270 &self,
2271 script: &HTMLScriptElement,
2272 load: Option<ScriptResult>,
2273 ) {
2274 assert!(!self.has_pending_parsing_blocking_script());
2275 *self.pending_parsing_blocking_script.borrow_mut() =
2276 Some(PendingScript::new_with_load(script, load));
2277 }
2278
2279 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2281 self.pending_parsing_blocking_script.borrow().is_some()
2282 }
2283
2284 pub(crate) fn pending_parsing_blocking_script_loaded(
2286 &self,
2287 element: &HTMLScriptElement,
2288 result: ScriptResult,
2289 can_gc: CanGc,
2290 ) {
2291 {
2292 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2293 let entry = blocking_script.as_mut().unwrap();
2294 assert!(&*entry.element == element);
2295 entry.loaded(result);
2296 }
2297 self.process_pending_parsing_blocking_script(can_gc);
2298 }
2299
2300 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2301 if self.script_blocking_stylesheets_count.get() > 0 {
2302 return;
2303 }
2304 let pair = self
2305 .pending_parsing_blocking_script
2306 .borrow_mut()
2307 .as_mut()
2308 .and_then(PendingScript::take_result);
2309 if let Some((element, result)) = pair {
2310 *self.pending_parsing_blocking_script.borrow_mut() = None;
2311 self.get_current_parser()
2312 .unwrap()
2313 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2314 }
2315 }
2316
2317 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2319 self.asap_scripts_set
2320 .borrow_mut()
2321 .push(Dom::from_ref(script));
2322 }
2323
2324 pub(crate) fn asap_script_loaded(
2327 &self,
2328 element: &HTMLScriptElement,
2329 result: ScriptResult,
2330 can_gc: CanGc,
2331 ) {
2332 {
2333 let mut scripts = self.asap_scripts_set.borrow_mut();
2334 let idx = scripts
2335 .iter()
2336 .position(|entry| &**entry == element)
2337 .unwrap();
2338 scripts.swap_remove(idx);
2339 }
2340 element.execute(result, can_gc);
2341 }
2342
2343 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2345 self.asap_in_order_scripts_list.push(script);
2346 }
2347
2348 pub(crate) fn asap_in_order_script_loaded(
2351 &self,
2352 element: &HTMLScriptElement,
2353 result: ScriptResult,
2354 can_gc: CanGc,
2355 ) {
2356 self.asap_in_order_scripts_list.loaded(element, result);
2357 while let Some((element, result)) = self
2358 .asap_in_order_scripts_list
2359 .take_next_ready_to_be_executed()
2360 {
2361 element.execute(result, can_gc);
2362 }
2363 }
2364
2365 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2367 self.deferred_scripts.push(script);
2368 }
2369
2370 pub(crate) fn deferred_script_loaded(
2373 &self,
2374 element: &HTMLScriptElement,
2375 result: ScriptResult,
2376 can_gc: CanGc,
2377 ) {
2378 self.deferred_scripts.loaded(element, result);
2379 self.process_deferred_scripts(can_gc);
2380 }
2381
2382 fn process_deferred_scripts(&self, can_gc: CanGc) {
2384 if self.ready_state.get() != DocumentReadyState::Interactive {
2385 return;
2386 }
2387 loop {
2389 if self.script_blocking_stylesheets_count.get() > 0 {
2390 return;
2391 }
2392 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2393 {
2394 element.execute(result, can_gc);
2395 } else {
2396 break;
2397 }
2398 }
2399 if self.deferred_scripts.is_empty() {
2400 self.maybe_dispatch_dom_content_loaded();
2402 }
2403 }
2404
2405 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2407 if self.domcontentloaded_dispatched.get() {
2408 return;
2409 }
2410 self.domcontentloaded_dispatched.set(true);
2411 assert_ne!(
2412 self.ReadyState(),
2413 DocumentReadyState::Complete,
2414 "Complete before DOMContentLoaded?"
2415 );
2416
2417 update_with_current_instant(&self.dom_content_loaded_event_start);
2418
2419 let document = Trusted::new(self);
2421 self.owner_global()
2422 .task_manager()
2423 .dom_manipulation_task_source()
2424 .queue(
2425 task!(fire_dom_content_loaded_event: move || {
2426 let document = document.root();
2427 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2428 update_with_current_instant(&document.dom_content_loaded_event_end);
2429 })
2430 );
2431
2432 self.interactive_time
2434 .borrow()
2435 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2436
2437 }
2440
2441 pub(crate) fn abort(&self, can_gc: CanGc) {
2443 self.loader.borrow_mut().inhibit_events();
2445
2446 for iframe in self.iframes().iter() {
2448 if let Some(document) = iframe.GetContentDocument() {
2449 document.abort(can_gc);
2451 }
2453 }
2454
2455 self.script_blocking_stylesheets_count.set(0);
2457 *self.pending_parsing_blocking_script.borrow_mut() = None;
2458 *self.asap_scripts_set.borrow_mut() = vec![];
2459 self.asap_in_order_scripts_list.clear();
2460 self.deferred_scripts.clear();
2461 let loads_cancelled = self.loader.borrow_mut().cancel_all_loads();
2462 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2463 if loads_cancelled || event_sources_canceled {
2464 self.salvageable.set(false);
2466 };
2467
2468 self.owner_global()
2473 .task_manager()
2474 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2475
2476 if let Some(parser) = self.get_current_parser() {
2478 self.active_parser_was_aborted.set(true);
2479 parser.abort(can_gc);
2480 self.salvageable.set(false);
2481 }
2482 }
2483
2484 pub(crate) fn notify_constellation_load(&self) {
2485 self.window()
2486 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2487 }
2488
2489 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2490 self.current_parser.set(script);
2491 }
2492
2493 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2494 self.current_parser.get()
2495 }
2496
2497 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2500 self.iframes.borrow_mut().validate(self);
2501 self.iframes.borrow()
2502 }
2503
2504 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2507 self.iframes.borrow_mut().validate(self);
2508 self.iframes.borrow_mut()
2509 }
2510
2511 pub(crate) fn invalidate_iframes_collection(&self) {
2512 self.iframes.borrow_mut().invalidate();
2513 }
2514
2515 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2516 self.dom_interactive.get()
2517 }
2518
2519 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2520 self.interactive_time
2521 .borrow_mut()
2522 .set_navigation_start(navigation_start);
2523 }
2524
2525 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2526 self.interactive_time.borrow()
2527 }
2528
2529 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2530 self.get_interactive_metrics().get_tti().is_some()
2531 }
2532
2533 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2534 self.dom_content_loaded_event_start.get()
2535 }
2536
2537 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2538 self.dom_content_loaded_event_end.get()
2539 }
2540
2541 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2542 self.dom_complete.get()
2543 }
2544
2545 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2546 self.top_level_dom_complete.get()
2547 }
2548
2549 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2550 self.load_event_start.get()
2551 }
2552
2553 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2554 self.load_event_end.get()
2555 }
2556
2557 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2558 self.unload_event_start.get()
2559 }
2560
2561 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2562 self.unload_event_end.get()
2563 }
2564
2565 pub(crate) fn start_tti(&self) {
2566 if self.get_interactive_metrics().needs_tti() {
2567 self.tti_window.borrow_mut().start_window();
2568 }
2569 }
2570
2571 pub(crate) fn record_tti_if_necessary(&self) {
2575 if self.has_recorded_tti_metric() {
2576 return;
2577 }
2578 if self.tti_window.borrow().needs_check() {
2579 self.get_interactive_metrics()
2580 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2581 self.tti_window.borrow().get_start(),
2582 ));
2583 }
2584 }
2585
2586 fn fire_focus_event(
2588 &self,
2589 focus_event_type: FocusEventType,
2590 event_target: &EventTarget,
2591 related_target: Option<&EventTarget>,
2592 can_gc: CanGc,
2593 ) {
2594 let (event_name, does_bubble) = match focus_event_type {
2595 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2596 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2597 };
2598 let event = FocusEvent::new(
2599 &self.window,
2600 event_name,
2601 does_bubble,
2602 EventCancelable::NotCancelable,
2603 Some(&self.window),
2604 0i32,
2605 related_target,
2606 can_gc,
2607 );
2608 let event = event.upcast::<Event>();
2609 event.set_trusted(true);
2610 event.fire(event_target, can_gc);
2611 }
2612
2613 pub(crate) fn is_cookie_averse(&self) -> bool {
2615 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2616 }
2617
2618 pub(crate) fn lookup_custom_element_definition(
2620 &self,
2621 namespace: &Namespace,
2622 local_name: &LocalName,
2623 is: Option<&LocalName>,
2624 ) -> Option<Rc<CustomElementDefinition>> {
2625 if !pref!(dom_customelements_enabled) {
2626 return None;
2627 }
2628
2629 if *namespace != ns!(html) {
2631 return None;
2632 }
2633
2634 if !self.has_browsing_context {
2636 return None;
2637 }
2638
2639 let registry = self.window.CustomElements();
2641
2642 registry.lookup_definition(local_name, is)
2643 }
2644
2645 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2646 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2647 self.throw_on_dynamic_markup_insertion_counter
2648 .set(counter + 1);
2649 }
2650
2651 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2652 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2653 self.throw_on_dynamic_markup_insertion_counter
2654 .set(counter - 1);
2655 }
2656
2657 pub(crate) fn react_to_environment_changes(&self) {
2658 for image in self.responsive_images.borrow().iter() {
2659 image.react_to_environment_changes();
2660 }
2661 }
2662
2663 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2664 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2665 }
2666
2667 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2668 let index = self
2669 .responsive_images
2670 .borrow()
2671 .iter()
2672 .position(|x| **x == *img);
2673 if let Some(i) = index {
2674 self.responsive_images.borrow_mut().remove(i);
2675 }
2676 }
2677
2678 pub(crate) fn register_media_controls(&self, controls: &ShadowRoot) -> String {
2679 let id = Uuid::new_v4().to_string();
2680 self.media_controls
2681 .borrow_mut()
2682 .insert(id.clone(), Dom::from_ref(controls));
2683 id
2684 }
2685
2686 pub(crate) fn unregister_media_controls(&self, id: &str) {
2687 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2688 debug_assert!(
2689 did_have_these_media_controls,
2690 "Trying to unregister unknown media controls"
2691 );
2692 }
2693
2694 pub(crate) fn add_dirty_webgl_canvas(&self, context: &WebGLRenderingContext) {
2695 self.dirty_webgl_contexts
2696 .borrow_mut()
2697 .entry(context.context_id())
2698 .or_insert_with(|| Dom::from_ref(context));
2699 }
2700
2701 pub(crate) fn add_dirty_2d_canvas(&self, context: &CanvasRenderingContext2D) {
2702 self.dirty_2d_contexts
2703 .borrow_mut()
2704 .entry(context.context_id())
2705 .or_insert_with(|| Dom::from_ref(context));
2706 }
2707
2708 #[cfg(feature = "webgpu")]
2709 pub(crate) fn add_dirty_webgpu_context(&self, context: &GPUCanvasContext) {
2710 self.dirty_webgpu_contexts
2711 .borrow_mut()
2712 .entry(context.context_id())
2713 .or_insert_with(|| Dom::from_ref(context));
2714 }
2715
2716 pub(crate) fn needs_rendering_update(&self) -> bool {
2720 if !self.is_fully_active() {
2721 return false;
2722 }
2723 if !self.window().layout_blocked() &&
2724 (!self.restyle_reason().is_empty() ||
2725 self.window().layout().needs_new_display_list())
2726 {
2727 return true;
2728 }
2729 if self.resize_observer_started_observing_target.get() {
2730 return true;
2731 }
2732 if self.event_handler.has_pending_input_events() {
2733 return true;
2734 }
2735 if self.has_pending_scroll_events() {
2736 return true;
2737 }
2738 if self.window().has_unhandled_resize_event() {
2739 return true;
2740 }
2741 if self.has_pending_animated_image_update.get() ||
2742 !self.dirty_2d_contexts.borrow().is_empty() ||
2743 !self.dirty_webgl_contexts.borrow().is_empty()
2744 {
2745 return true;
2746 }
2747
2748 #[cfg(feature = "webgpu")]
2749 if !self.dirty_webgpu_contexts.borrow().is_empty() {
2750 return true;
2751 }
2752
2753 false
2754 }
2755
2756 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
2764 if self.render_blocking_element_count() > 0 {
2765 return Default::default();
2766 }
2767
2768 let mut results = ReflowPhasesRun::empty();
2769 if self.has_pending_animated_image_update.get() {
2770 self.image_animation_manager
2771 .borrow()
2772 .update_active_frames(&self.window, self.current_animation_timeline_value());
2773 self.has_pending_animated_image_update.set(false);
2774 results.insert(ReflowPhasesRun::UpdatedImageData);
2775 }
2776
2777 self.current_rendering_epoch
2778 .set(self.current_rendering_epoch.get().next());
2779 let current_rendering_epoch = self.current_rendering_epoch.get();
2780
2781 let mut image_keys = Vec::new();
2783 #[cfg(feature = "webgpu")]
2784 image_keys.extend(
2785 self.dirty_webgpu_contexts
2786 .borrow_mut()
2787 .drain()
2788 .filter(|(_, context)| context.update_rendering(current_rendering_epoch))
2789 .map(|(_, context)| {
2790 results.insert(ReflowPhasesRun::UpdatedImageData);
2791 context.image_key()
2792 }),
2793 );
2794
2795 image_keys.extend(
2796 self.dirty_2d_contexts
2797 .borrow_mut()
2798 .drain()
2799 .filter(|(_, context)| context.update_rendering(current_rendering_epoch))
2800 .map(|(_, context)| {
2801 results.insert(ReflowPhasesRun::UpdatedImageData);
2802 context.image_key()
2803 }),
2804 );
2805
2806 let dirty_webgl_context_ids: Vec<_> = self
2807 .dirty_webgl_contexts
2808 .borrow_mut()
2809 .drain()
2810 .filter(|(_, context)| context.onscreen())
2811 .map(|(id, context)| {
2812 image_keys.push(context.image_key());
2813 id
2814 })
2815 .collect();
2816
2817 if !dirty_webgl_context_ids.is_empty() {
2818 results.insert(ReflowPhasesRun::UpdatedImageData);
2819 self.window
2820 .webgl_chan()
2821 .expect("Where's the WebGL channel?")
2822 .send(WebGLMsg::SwapBuffers(
2823 dirty_webgl_context_ids,
2824 Some(current_rendering_epoch),
2825 0,
2826 ))
2827 .unwrap();
2828 }
2829
2830 let pipeline_id = self.window().pipeline_id();
2833 if !image_keys.is_empty() {
2834 self.waiting_on_canvas_image_updates.set(true);
2835 self.window().compositor_api().delay_new_frame_for_canvas(
2836 self.window().pipeline_id(),
2837 current_rendering_epoch,
2838 image_keys.into_iter().flatten().collect(),
2839 );
2840 }
2841
2842 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
2843
2844 self.window().compositor_api().update_epoch(
2845 self.webview_id(),
2846 pipeline_id,
2847 current_rendering_epoch,
2848 );
2849
2850 results
2851 }
2852
2853 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2854 self.waiting_on_canvas_image_updates.set(false);
2855 }
2856
2857 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2858 self.waiting_on_canvas_image_updates.get()
2859 }
2860
2861 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2871 if !self.is_fully_active() {
2872 return false;
2873 }
2874
2875 let fonts = self.Fonts(can_gc);
2876 if !fonts.waiting_to_fullfill_promise() {
2877 return false;
2878 }
2879 if self.window().font_context().web_fonts_still_loading() != 0 {
2880 return false;
2881 }
2882 if self.ReadyState() != DocumentReadyState::Complete {
2883 return false;
2884 }
2885 if !self.restyle_reason().is_empty() {
2886 return false;
2887 }
2888 fonts.fulfill_ready_promise_if_needed(can_gc)
2889 }
2890
2891 pub(crate) fn id_map(
2892 &self,
2893 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2894 self.id_map.borrow()
2895 }
2896
2897 pub(crate) fn name_map(
2898 &self,
2899 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2900 self.name_map.borrow()
2901 }
2902
2903 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
2905 self.resize_observers
2906 .borrow_mut()
2907 .push(Dom::from_ref(resize_observer));
2908 }
2909
2910 pub(crate) fn has_resize_observers(&self) -> bool {
2912 !self.resize_observers.borrow().is_empty()
2913 }
2914
2915 pub(crate) fn gather_active_resize_observations_at_depth(
2918 &self,
2919 depth: &ResizeObservationDepth,
2920 ) -> bool {
2921 let mut has_active_resize_observations = false;
2922 for observer in self.resize_observers.borrow_mut().iter_mut() {
2923 observer.gather_active_resize_observations_at_depth(
2924 depth,
2925 &mut has_active_resize_observations,
2926 );
2927 }
2928 has_active_resize_observations
2929 }
2930
2931 pub(crate) fn broadcast_active_resize_observations(
2933 &self,
2934 can_gc: CanGc,
2935 ) -> ResizeObservationDepth {
2936 let mut shallowest = ResizeObservationDepth::max();
2937 let iterator: Vec<DomRoot<ResizeObserver>> = self
2941 .resize_observers
2942 .borrow()
2943 .iter()
2944 .cloned()
2945 .map(|obs| DomRoot::from_ref(&*obs))
2946 .collect();
2947 for observer in iterator {
2948 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
2949 }
2950 shallowest
2951 }
2952
2953 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
2955 self.resize_observers
2956 .borrow()
2957 .iter()
2958 .any(|observer| observer.has_skipped_resize_observations())
2959 }
2960
2961 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
2963 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
2964 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
2965 ..Default::default()
2966 };
2967 self.window
2968 .as_global_scope()
2969 .report_an_error(error_info, HandleValue::null(), can_gc);
2970 }
2971
2972 pub(crate) fn status_code(&self) -> Option<u16> {
2973 self.status_code
2974 }
2975
2976 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
2978 let encoding = self.encoding.get();
2984
2985 let base_url = self.base_url();
2991
2992 url::Url::options()
2994 .base_url(Some(base_url.as_url()))
2995 .encoding_override(Some(&|input| {
2996 servo_url::encoding::encode_as_url_query_string(input, encoding)
2997 }))
2998 .parse(url)
2999 .map(ServoUrl::from)
3000 }
3001
3002 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
3004 if !self.has_browsing_context {
3006 return false;
3007 }
3008
3009 if !self.is_fully_active() {
3011 return false;
3012 }
3013
3014 true
3020 }
3021
3022 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3025 self.intersection_observers
3026 .borrow_mut()
3027 .push(Dom::from_ref(intersection_observer));
3028 }
3029
3030 pub(crate) fn remove_intersection_observer(
3034 &self,
3035 intersection_observer: &IntersectionObserver,
3036 ) {
3037 self.intersection_observers
3038 .borrow_mut()
3039 .retain(|observer| *observer != intersection_observer)
3040 }
3041
3042 pub(crate) fn update_intersection_observer_steps(
3044 &self,
3045 time: CrossProcessInstant,
3046 can_gc: CanGc,
3047 ) {
3048 for intersection_observer in &*self.intersection_observers.borrow() {
3050 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3051 }
3052 }
3053
3054 fn update_single_intersection_observer_steps(
3056 &self,
3057 intersection_observer: &IntersectionObserver,
3058 time: CrossProcessInstant,
3059 can_gc: CanGc,
3060 ) {
3061 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3064
3065 intersection_observer.update_intersection_observations_steps(
3069 self,
3070 time,
3071 root_bounds,
3072 can_gc,
3073 );
3074 }
3075
3076 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3078 self.intersection_observer_task_queued.set(false);
3081
3082 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3087
3088 for intersection_observer in notify_list.iter() {
3091 intersection_observer.invoke_callback_if_necessary(can_gc);
3093 }
3094 }
3095
3096 pub(crate) fn queue_an_intersection_observer_task(&self) {
3098 if self.intersection_observer_task_queued.get() {
3101 return;
3102 }
3103
3104 self.intersection_observer_task_queued.set(true);
3107
3108 let document = Trusted::new(self);
3112 self.owner_global()
3113 .task_manager()
3114 .intersection_observer_task_source()
3115 .queue(task!(notify_intersection_observers: move || {
3116 document.root().notify_intersection_observers(CanGc::note());
3117 }));
3118 }
3119
3120 pub(crate) fn handle_paint_metric(
3121 &self,
3122 metric_type: ProgressiveWebMetricType,
3123 metric_value: CrossProcessInstant,
3124 first_reflow: bool,
3125 can_gc: CanGc,
3126 ) {
3127 let metrics = self.interactive_time.borrow();
3128 match metric_type {
3129 ProgressiveWebMetricType::FirstPaint => {
3130 metrics.set_first_paint(metric_value, first_reflow)
3131 },
3132 ProgressiveWebMetricType::FirstContentfulPaint => {
3133 metrics.set_first_contentful_paint(metric_value, first_reflow)
3134 },
3135 ProgressiveWebMetricType::TimeToInteractive => {
3136 unreachable!("Unexpected non-paint metric.")
3137 },
3138 }
3139
3140 let entry = PerformancePaintTiming::new(
3141 self.window.as_global_scope(),
3142 metric_type,
3143 metric_value,
3144 can_gc,
3145 );
3146 self.window
3147 .Performance()
3148 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
3149 }
3150
3151 fn write(
3153 &self,
3154 text: Vec<TrustedHTMLOrString>,
3155 line_feed: bool,
3156 containing_class: &str,
3157 field: &str,
3158 can_gc: CanGc,
3159 ) -> ErrorResult {
3160 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3162 let mut is_trusted = true;
3164 for value in text {
3166 match value {
3167 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3169 strings.push(trusted_html.to_string().to_owned());
3170 },
3171 TrustedHTMLOrString::String(str_) => {
3172 is_trusted = false;
3174 strings.push(str_.into());
3176 },
3177 };
3178 }
3179 let mut string = itertools::join(strings, "");
3180 if !is_trusted {
3184 string = TrustedHTML::get_trusted_script_compliant_string(
3185 &self.global(),
3186 TrustedHTMLOrString::String(string.into()),
3187 &format!("{} {}", containing_class, field),
3188 can_gc,
3189 )?
3190 .str()
3191 .to_owned();
3192 }
3193 if line_feed {
3195 string.push('\n');
3196 }
3197 if !self.is_html_document() {
3199 return Err(Error::InvalidState(None));
3200 }
3201
3202 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3205 return Err(Error::InvalidState(None));
3206 }
3207
3208 if !self.is_active() || self.active_parser_was_aborted.get() {
3210 return Ok(());
3211 }
3212
3213 let parser = match self.get_current_parser() {
3214 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3215 _ => {
3217 if self.is_prompting_or_unloading() ||
3220 self.ignore_destructive_writes_counter.get() > 0
3221 {
3222 return Ok(());
3223 }
3224 self.Open(None, None, can_gc)?;
3226 self.get_current_parser().unwrap()
3227 },
3228 };
3229
3230 parser.write(string.into(), can_gc);
3232
3233 Ok(())
3234 }
3235}
3236
3237#[derive(MallocSizeOf, PartialEq)]
3238pub(crate) enum DocumentSource {
3239 FromParser,
3240 NotFromParser,
3241}
3242
3243#[allow(unsafe_code)]
3244pub(crate) trait LayoutDocumentHelpers<'dom> {
3245 fn is_html_document_for_layout(&self) -> bool;
3246 fn quirks_mode(self) -> QuirksMode;
3247 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3248 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3249 fn shadow_roots_styles_changed(self) -> bool;
3250 fn flush_shadow_roots_stylesheets(self);
3251}
3252
3253#[allow(unsafe_code)]
3254impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3255 #[inline]
3256 fn is_html_document_for_layout(&self) -> bool {
3257 self.unsafe_get().is_html_document
3258 }
3259
3260 #[inline]
3261 fn quirks_mode(self) -> QuirksMode {
3262 self.unsafe_get().quirks_mode.get()
3263 }
3264
3265 #[inline]
3266 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3267 self.unsafe_get().style_shared_lock()
3268 }
3269
3270 #[inline]
3271 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3272 unsafe {
3277 self.unsafe_get()
3278 .shadow_roots
3279 .borrow_for_layout()
3280 .iter()
3281 .map(|sr| sr.to_layout())
3282 .collect()
3283 }
3284 }
3285
3286 #[inline]
3287 fn shadow_roots_styles_changed(self) -> bool {
3288 self.unsafe_get().shadow_roots_styles_changed.get()
3289 }
3290
3291 #[inline]
3292 fn flush_shadow_roots_stylesheets(self) {
3293 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3294 }
3295}
3296
3297fn get_registrable_domain_suffix_of_or_is_equal_to(
3301 host_suffix_string: &DOMString,
3302 original_host: Host,
3303) -> Option<Host> {
3304 if host_suffix_string.is_empty() {
3306 return None;
3307 }
3308
3309 let host = match Host::parse(&host_suffix_string.str()) {
3311 Ok(host) => host,
3312 Err(_) => return None,
3313 };
3314
3315 if host != original_host {
3317 let host = match host {
3319 Host::Domain(ref host) => host,
3320 _ => return None,
3321 };
3322 let original_host = match original_host {
3323 Host::Domain(ref original_host) => original_host,
3324 _ => return None,
3325 };
3326
3327 let index = original_host.len().checked_sub(host.len())?;
3329 let (prefix, suffix) = original_host.split_at(index);
3330
3331 if !prefix.ends_with('.') {
3332 return None;
3333 }
3334 if suffix != host {
3335 return None;
3336 }
3337
3338 if is_pub_domain(host) {
3340 return None;
3341 }
3342 }
3343
3344 Some(host)
3346}
3347
3348fn url_has_network_scheme(url: &ServoUrl) -> bool {
3350 matches!(url.scheme(), "ftp" | "http" | "https")
3351}
3352
3353#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3354pub(crate) enum HasBrowsingContext {
3355 No,
3356 Yes,
3357}
3358
3359impl Document {
3360 #[allow(clippy::too_many_arguments)]
3361 pub(crate) fn new_inherited(
3362 window: &Window,
3363 has_browsing_context: HasBrowsingContext,
3364 url: Option<ServoUrl>,
3365 origin: MutableOrigin,
3366 is_html_document: IsHTMLDocument,
3367 content_type: Option<Mime>,
3368 last_modified: Option<String>,
3369 activity: DocumentActivity,
3370 source: DocumentSource,
3371 doc_loader: DocumentLoader,
3372 referrer: Option<String>,
3373 status_code: Option<u16>,
3374 canceller: FetchCanceller,
3375 is_initial_about_blank: bool,
3376 allow_declarative_shadow_roots: bool,
3377 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3378 has_trustworthy_ancestor_origin: bool,
3379 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3380 creation_sandboxing_flag_set: SandboxingFlagSet,
3381 ) -> Document {
3382 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3383
3384 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3385 (DocumentReadyState::Loading, false)
3386 } else {
3387 (DocumentReadyState::Complete, true)
3388 };
3389
3390 let frame_type = match window.is_top_level() {
3391 true => TimerMetadataFrameType::RootWindow,
3392 false => TimerMetadataFrameType::IFrame,
3393 };
3394 let interactive_time = ProgressiveWebMetrics::new(
3395 window.time_profiler_chan().clone(),
3396 url.clone(),
3397 frame_type,
3398 );
3399
3400 let content_type = content_type.unwrap_or_else(|| {
3401 match is_html_document {
3402 IsHTMLDocument::HTMLDocument => "text/html",
3404 IsHTMLDocument::NonHTMLDocument => "application/xml",
3406 }
3407 .parse()
3408 .unwrap()
3409 });
3410
3411 let encoding = content_type
3412 .get_parameter(CHARSET)
3413 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3414 .unwrap_or(UTF_8);
3415
3416 let has_focus = window.parent_info().is_none();
3417
3418 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3419
3420 Document {
3421 node: Node::new_document_node(),
3422 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3423 window: Dom::from_ref(window),
3424 has_browsing_context,
3425 implementation: Default::default(),
3426 content_type,
3427 last_modified,
3428 url: DomRefCell::new(url),
3429 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3431 event_handler: DocumentEventHandler::new(window),
3432 embedder_controls: DocumentEmbedderControls::new(window),
3433 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3434 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3435 encoding: Cell::new(encoding),
3437 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3438 activity: Cell::new(activity),
3439 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3440 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3441 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3442 images: Default::default(),
3443 embeds: Default::default(),
3444 links: Default::default(),
3445 forms: Default::default(),
3446 scripts: Default::default(),
3447 anchors: Default::default(),
3448 applets: Default::default(),
3449 iframes: RefCell::new(IFrameCollection::new()),
3450 style_shared_lock: {
3451 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3458 LazyLock::new(StyleSharedRwLock::new);
3459
3460 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3461 },
3463 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3464 stylesheet_list: MutNullableDom::new(None),
3465 ready_state: Cell::new(ready_state),
3466 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3467 focus_transaction: DomRefCell::new(None),
3468 focused: Default::default(),
3469 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3470 has_focus: Cell::new(has_focus),
3471 current_script: Default::default(),
3472 pending_parsing_blocking_script: Default::default(),
3473 script_blocking_stylesheets_count: Default::default(),
3474 render_blocking_element_count: Default::default(),
3475 deferred_scripts: Default::default(),
3476 asap_in_order_scripts_list: Default::default(),
3477 asap_scripts_set: Default::default(),
3478 animation_frame_ident: Cell::new(0),
3479 animation_frame_list: DomRefCell::new(VecDeque::new()),
3480 running_animation_callbacks: Cell::new(false),
3481 loader: DomRefCell::new(doc_loader),
3482 current_parser: Default::default(),
3483 base_element: Default::default(),
3484 appropriate_template_contents_owner_document: Default::default(),
3485 pending_restyles: DomRefCell::new(FxHashMap::default()),
3486 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3487 dom_interactive: Cell::new(Default::default()),
3488 dom_content_loaded_event_start: Cell::new(Default::default()),
3489 dom_content_loaded_event_end: Cell::new(Default::default()),
3490 dom_complete: Cell::new(Default::default()),
3491 top_level_dom_complete: Cell::new(Default::default()),
3492 load_event_start: Cell::new(Default::default()),
3493 load_event_end: Cell::new(Default::default()),
3494 unload_event_start: Cell::new(Default::default()),
3495 unload_event_end: Cell::new(Default::default()),
3496 https_state: Cell::new(HttpsState::None),
3497 origin,
3498 referrer,
3499 target_element: MutNullableDom::new(None),
3500 policy_container: DomRefCell::new(PolicyContainer::default()),
3501 ignore_destructive_writes_counter: Default::default(),
3502 ignore_opens_during_unload_counter: Default::default(),
3503 spurious_animation_frames: Cell::new(0),
3504 dom_count: Cell::new(1),
3505 fullscreen_element: MutNullableDom::new(None),
3506 form_id_listener_map: Default::default(),
3507 interactive_time: DomRefCell::new(interactive_time),
3508 tti_window: DomRefCell::new(InteractiveWindow::default()),
3509 canceller,
3510 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3511 page_showing: Cell::new(false),
3512 salvageable: Cell::new(true),
3513 active_parser_was_aborted: Cell::new(false),
3514 fired_unload: Cell::new(false),
3515 responsive_images: Default::default(),
3516 redirect_count: Cell::new(0),
3517 completely_loaded: Cell::new(false),
3518 script_and_layout_blockers: Cell::new(0),
3519 delayed_tasks: Default::default(),
3520 shadow_roots: DomRefCell::new(HashSet::new()),
3521 shadow_roots_styles_changed: Cell::new(false),
3522 media_controls: DomRefCell::new(HashMap::new()),
3523 dirty_2d_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3524 dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3525 has_pending_animated_image_update: Cell::new(false),
3526 #[cfg(feature = "webgpu")]
3527 dirty_webgpu_contexts: DomRefCell::new(HashMapTracedValues::new_fx()),
3528 selection: MutNullableDom::new(None),
3529 animation_timeline: if pref!(layout_animations_test_enabled) {
3530 DomRefCell::new(AnimationTimeline::new_for_testing())
3531 } else {
3532 DomRefCell::new(AnimationTimeline::new())
3533 },
3534 animations: DomRefCell::new(Animations::new()),
3535 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3536 dirty_root: Default::default(),
3537 declarative_refresh: Default::default(),
3538 resize_observers: Default::default(),
3539 fonts: Default::default(),
3540 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3541 status_code,
3542 is_initial_about_blank: Cell::new(is_initial_about_blank),
3543 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3544 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3545 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3546 intersection_observer_task_queued: Cell::new(false),
3547 intersection_observers: Default::default(),
3548 highlighted_dom_node: Default::default(),
3549 adopted_stylesheets: Default::default(),
3550 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3551 pending_scroll_event_targets: Default::default(),
3552 resize_observer_started_observing_target: Cell::new(false),
3553 waiting_on_canvas_image_updates: Cell::new(false),
3554 current_rendering_epoch: Default::default(),
3555 custom_element_reaction_stack,
3556 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3557 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3558 favicon: RefCell::new(None),
3559 }
3560 }
3561
3562 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3564 if let Some(csp_list) = self.get_csp_list() {
3565 for policy in &csp_list.0 {
3566 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3567 policy.disposition == PolicyDisposition::Enforce
3568 {
3569 return InsecureRequestsPolicy::Upgrade;
3570 }
3571 }
3572 }
3573
3574 self.inherited_insecure_requests_policy
3575 .get()
3576 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3577 }
3578
3579 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3581 &self.event_handler
3582 }
3583
3584 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3586 &self.embedder_controls
3587 }
3588
3589 fn has_pending_scroll_events(&self) -> bool {
3592 !self.pending_scroll_event_targets.borrow().is_empty()
3593 }
3594
3595 pub(crate) fn set_resize_observer_started_observing_target(&self, value: bool) {
3596 self.resize_observer_started_observing_target.set(value);
3597 }
3598
3599 pub(crate) fn add_script_and_layout_blocker(&self) {
3606 self.script_and_layout_blockers
3607 .set(self.script_and_layout_blockers.get() + 1);
3608 }
3609
3610 pub(crate) fn remove_script_and_layout_blocker(&self) {
3614 assert!(self.script_and_layout_blockers.get() > 0);
3615 self.script_and_layout_blockers
3616 .set(self.script_and_layout_blockers.get() - 1);
3617 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3618 {
3619 let task = self.delayed_tasks.borrow_mut().remove(0);
3620 task.run_box();
3621 }
3622 }
3623
3624 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3626 self.delayed_tasks.borrow_mut().push(Box::new(task));
3627 }
3628
3629 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3632 assert_eq!(
3633 self.script_and_layout_blockers.get(),
3634 0,
3635 "Attempt to use script or layout while DOM not in a stable state"
3636 );
3637 }
3638
3639 #[allow(clippy::too_many_arguments)]
3640 pub(crate) fn new(
3641 window: &Window,
3642 has_browsing_context: HasBrowsingContext,
3643 url: Option<ServoUrl>,
3644 origin: MutableOrigin,
3645 doctype: IsHTMLDocument,
3646 content_type: Option<Mime>,
3647 last_modified: Option<String>,
3648 activity: DocumentActivity,
3649 source: DocumentSource,
3650 doc_loader: DocumentLoader,
3651 referrer: Option<String>,
3652 status_code: Option<u16>,
3653 canceller: FetchCanceller,
3654 is_initial_about_blank: bool,
3655 allow_declarative_shadow_roots: bool,
3656 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3657 has_trustworthy_ancestor_origin: bool,
3658 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3659 creation_sandboxing_flag_set: SandboxingFlagSet,
3660 can_gc: CanGc,
3661 ) -> DomRoot<Document> {
3662 Self::new_with_proto(
3663 window,
3664 None,
3665 has_browsing_context,
3666 url,
3667 origin,
3668 doctype,
3669 content_type,
3670 last_modified,
3671 activity,
3672 source,
3673 doc_loader,
3674 referrer,
3675 status_code,
3676 canceller,
3677 is_initial_about_blank,
3678 allow_declarative_shadow_roots,
3679 inherited_insecure_requests_policy,
3680 has_trustworthy_ancestor_origin,
3681 custom_element_reaction_stack,
3682 creation_sandboxing_flag_set,
3683 can_gc,
3684 )
3685 }
3686
3687 #[allow(clippy::too_many_arguments)]
3688 fn new_with_proto(
3689 window: &Window,
3690 proto: Option<HandleObject>,
3691 has_browsing_context: HasBrowsingContext,
3692 url: Option<ServoUrl>,
3693 origin: MutableOrigin,
3694 doctype: IsHTMLDocument,
3695 content_type: Option<Mime>,
3696 last_modified: Option<String>,
3697 activity: DocumentActivity,
3698 source: DocumentSource,
3699 doc_loader: DocumentLoader,
3700 referrer: Option<String>,
3701 status_code: Option<u16>,
3702 canceller: FetchCanceller,
3703 is_initial_about_blank: bool,
3704 allow_declarative_shadow_roots: bool,
3705 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3706 has_trustworthy_ancestor_origin: bool,
3707 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3708 creation_sandboxing_flag_set: SandboxingFlagSet,
3709 can_gc: CanGc,
3710 ) -> DomRoot<Document> {
3711 let document = reflect_dom_object_with_proto(
3712 Box::new(Document::new_inherited(
3713 window,
3714 has_browsing_context,
3715 url,
3716 origin,
3717 doctype,
3718 content_type,
3719 last_modified,
3720 activity,
3721 source,
3722 doc_loader,
3723 referrer,
3724 status_code,
3725 canceller,
3726 is_initial_about_blank,
3727 allow_declarative_shadow_roots,
3728 inherited_insecure_requests_policy,
3729 has_trustworthy_ancestor_origin,
3730 custom_element_reaction_stack,
3731 creation_sandboxing_flag_set,
3732 )),
3733 window,
3734 proto,
3735 can_gc,
3736 );
3737 {
3738 let node = document.upcast::<Node>();
3739 node.set_owner_doc(&document);
3740 }
3741 document
3742 }
3743
3744 pub(crate) fn get_redirect_count(&self) -> u16 {
3745 self.redirect_count.get()
3746 }
3747
3748 pub(crate) fn set_redirect_count(&self, count: u16) {
3749 self.redirect_count.set(count)
3750 }
3751
3752 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3753 if name.is_empty() {
3754 return 0;
3755 }
3756 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3757 }
3758
3759 pub(crate) fn nth_element_by_name(
3760 &self,
3761 index: u32,
3762 name: &DOMString,
3763 ) -> Option<DomRoot<Node>> {
3764 if name.is_empty() {
3765 return None;
3766 }
3767 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3768 }
3769
3770 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3773 let element = match node.downcast::<Element>() {
3774 Some(element) => element,
3775 None => return false,
3776 };
3777 if element.namespace() != &ns!(html) {
3778 return false;
3779 }
3780 element.get_name().is_some_and(|n| &*n == name)
3781 }
3782
3783 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3784 let doc = self.GetDocumentElement();
3785 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3786 maybe_node
3787 .iter()
3788 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3789 .filter(|node| callback(node))
3790 .count() as u32
3791 }
3792
3793 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3794 &self,
3795 index: u32,
3796 callback: F,
3797 ) -> Option<DomRoot<Node>> {
3798 let doc = self.GetDocumentElement();
3799 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3800 maybe_node
3801 .iter()
3802 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3803 .filter(|node| callback(node))
3804 .nth(index as usize)
3805 .map(|n| DomRoot::from_ref(&*n))
3806 }
3807
3808 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3809 self.GetDocumentElement().and_then(DomRoot::downcast)
3810 }
3811
3812 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3814 &self.style_shared_lock
3815 }
3816
3817 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3819 let mut stylesheets = self.stylesheets.borrow_mut();
3826 let have_changed = stylesheets.has_changed();
3827 stylesheets.flush_without_invalidation();
3828 have_changed
3829 }
3830
3831 pub(crate) fn salvageable(&self) -> bool {
3832 self.salvageable.get()
3833 }
3834
3835 pub(crate) fn appropriate_template_contents_owner_document(
3837 &self,
3838 can_gc: CanGc,
3839 ) -> DomRoot<Document> {
3840 self.appropriate_template_contents_owner_document
3841 .or_init(|| {
3842 let doctype = if self.is_html_document {
3843 IsHTMLDocument::HTMLDocument
3844 } else {
3845 IsHTMLDocument::NonHTMLDocument
3846 };
3847 let new_doc = Document::new(
3848 self.window(),
3849 HasBrowsingContext::No,
3850 None,
3851 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3853 doctype,
3854 None,
3855 None,
3856 DocumentActivity::Inactive,
3857 DocumentSource::NotFromParser,
3858 DocumentLoader::new(&self.loader()),
3859 None,
3860 None,
3861 Default::default(),
3862 false,
3863 self.allow_declarative_shadow_roots(),
3864 Some(self.insecure_requests_policy()),
3865 self.has_trustworthy_ancestor_or_current_origin(),
3866 self.custom_element_reaction_stack.clone(),
3867 self.creation_sandboxing_flag_set(),
3868 can_gc,
3869 );
3870 new_doc
3871 .appropriate_template_contents_owner_document
3872 .set(Some(&new_doc));
3873 new_doc
3874 })
3875 }
3876
3877 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
3878 self.id_map
3879 .borrow()
3880 .get(id)
3881 .map(|elements| DomRoot::from_ref(&*elements[0]))
3882 }
3883
3884 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
3885 let map = self.pending_restyles.borrow_mut();
3886 RefMut::map(map, |m| {
3887 &mut m
3888 .entry(Dom::from_ref(el))
3889 .or_insert_with(|| NoTrace(PendingRestyle::default()))
3890 .0
3891 })
3892 }
3893
3894 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
3895 let mut entry = self.ensure_pending_restyle(el);
3901 if entry.snapshot.is_none() {
3902 entry.snapshot = Some(Snapshot::new());
3903 }
3904 if attr.local_name() == &local_name!("style") {
3905 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
3906 }
3907
3908 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
3909 entry.hint.insert(RestyleHint::RESTYLE_SELF);
3910 }
3911
3912 let snapshot = entry.snapshot.as_mut().unwrap();
3913 if attr.local_name() == &local_name!("id") {
3914 if snapshot.id_changed {
3915 return;
3916 }
3917 snapshot.id_changed = true;
3918 } else if attr.local_name() == &local_name!("class") {
3919 if snapshot.class_changed {
3920 return;
3921 }
3922 snapshot.class_changed = true;
3923 } else {
3924 snapshot.other_attributes_changed = true;
3925 }
3926 let local_name = style::LocalName::cast(attr.local_name());
3927 if !snapshot.changed_attrs.contains(local_name) {
3928 snapshot.changed_attrs.push(local_name.clone());
3929 }
3930 if snapshot.attrs.is_none() {
3931 let attrs = el
3932 .attrs()
3933 .iter()
3934 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
3935 .collect();
3936 snapshot.attrs = Some(attrs);
3937 }
3938 }
3939
3940 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
3941 self.policy_container
3942 .borrow_mut()
3943 .set_referrer_policy(policy);
3944 }
3945
3946 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
3947 self.policy_container.borrow().get_referrer_policy()
3948 }
3949
3950 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
3951 if let Some(ref element) = self.target_element.get() {
3952 element.set_target_state(false);
3953 }
3954
3955 self.target_element.set(node);
3956
3957 if let Some(ref element) = self.target_element.get() {
3958 element.set_target_state(true);
3959 }
3960 }
3961
3962 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
3963 self.ignore_destructive_writes_counter
3964 .set(self.ignore_destructive_writes_counter.get() + 1);
3965 }
3966
3967 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
3968 self.ignore_destructive_writes_counter
3969 .set(self.ignore_destructive_writes_counter.get() - 1);
3970 }
3971
3972 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
3973 self.ignore_opens_during_unload_counter.get() > 0
3974 }
3975
3976 fn incr_ignore_opens_during_unload_counter(&self) {
3977 self.ignore_opens_during_unload_counter
3978 .set(self.ignore_opens_during_unload_counter.get() + 1);
3979 }
3980
3981 fn decr_ignore_opens_during_unload_counter(&self) {
3982 self.ignore_opens_during_unload_counter
3983 .set(self.ignore_opens_during_unload_counter.get() - 1);
3984 }
3985
3986 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
3988 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
3990 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
3991 let mut error = false;
3992
3993 match *pending.namespace() {
3996 ns!(mathml) => {
3997 if pending.local_name().as_ref() != "math" {
3998 error = true;
3999 }
4000 },
4001 ns!(svg) => {
4002 if pending.local_name().as_ref() != "svg" {
4003 error = true;
4004 }
4005 },
4006 ns!(html) => (),
4007 _ => error = true,
4008 }
4009 if !pending.fullscreen_element_ready_check() {
4011 error = true;
4012 }
4013
4014 if pref!(dom_fullscreen_test) {
4015 info!("Tests don't really enter fullscreen.");
4018 } else {
4019 warn!("Fullscreen not supported yet");
4022 }
4023
4024 let window = self.window();
4027 if !error {
4029 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4030 self.send_to_embedder(event);
4031 }
4032
4033 let pipeline_id = self.window().pipeline_id();
4034
4035 let trusted_pending = Trusted::new(pending);
4037 let trusted_promise = TrustedPromise::new(promise.clone());
4038 let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
4039 let script_msg = CommonScriptMsg::Task(
4042 ScriptThreadEventCategory::EnterFullscreen,
4043 handler,
4044 Some(pipeline_id),
4045 TaskSourceName::DOMManipulation,
4046 );
4047 let msg = MainThreadScriptMsg::Common(script_msg);
4048 window.main_thread_script_chan().send(msg).unwrap();
4049
4050 promise
4051 }
4052
4053 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4055 let global = self.global();
4056 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4058 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4059 if self.fullscreen_element.get().is_none() {
4061 promise.reject_error(Error::Type(String::from("fullscreen is null")), can_gc);
4062 return promise;
4063 }
4064 let element = self.fullscreen_element.get().unwrap();
4066
4067 let window = self.window();
4070 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4072 self.send_to_embedder(event);
4073
4074 let trusted_element = Trusted::new(&*element);
4076 let trusted_promise = TrustedPromise::new(promise.clone());
4077 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4078 let pipeline_id = Some(global.pipeline_id());
4079 let script_msg = CommonScriptMsg::Task(
4082 ScriptThreadEventCategory::ExitFullscreen,
4083 handler,
4084 pipeline_id,
4085 TaskSourceName::DOMManipulation,
4086 );
4087 let msg = MainThreadScriptMsg::Common(script_msg);
4088 window.main_thread_script_chan().send(msg).unwrap();
4089
4090 promise
4091 }
4092
4093 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4094 self.fullscreen_element.set(element);
4095 }
4096
4097 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4098 match self.browsing_context() {
4100 None => false,
4102 Some(_) => {
4103 let window = self.window();
4105 if window.is_top_level() {
4106 true
4107 } else {
4108 window
4110 .GetFrameElement()
4111 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4112 }
4113 },
4114 }
4115 }
4116
4117 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4118 let map = self.form_id_listener_map.borrow();
4119 if let Some(listeners) = map.get(id) {
4120 for listener in listeners {
4121 listener
4122 .as_maybe_form_control()
4123 .expect("Element must be a form control")
4124 .reset_form_owner(can_gc);
4125 }
4126 }
4127 }
4128
4129 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4130 self.shadow_roots
4131 .borrow_mut()
4132 .insert(Dom::from_ref(shadow_root));
4133 self.invalidate_shadow_roots_stylesheets();
4134 }
4135
4136 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4137 let mut shadow_roots = self.shadow_roots.borrow_mut();
4138 shadow_roots.remove(&Dom::from_ref(shadow_root));
4139 }
4140
4141 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4142 self.shadow_roots_styles_changed.set(true);
4143 }
4144
4145 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4146 self.shadow_roots_styles_changed.get()
4147 }
4148
4149 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4150 if !self.shadow_roots_styles_changed.get() {
4151 return;
4152 }
4153 self.shadow_roots_styles_changed.set(false);
4154 }
4155
4156 pub(crate) fn stylesheet_count(&self) -> usize {
4157 self.stylesheets.borrow().len()
4158 }
4159
4160 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4161 let stylesheets = self.stylesheets.borrow();
4162
4163 stylesheets
4164 .get(Origin::Author, index)
4165 .and_then(|s| s.owner.get_cssom_object())
4166 }
4167
4168 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4175 let stylesheets = &mut *self.stylesheets.borrow_mut();
4176
4177 let insertion_point = stylesheets
4179 .iter()
4180 .map(|(sheet, _origin)| sheet)
4181 .find(|sheet_in_doc| {
4182 match &sheet_in_doc.owner {
4183 StylesheetSource::Element(other_node) => {
4184 owner_node.upcast::<Node>().is_before(other_node.upcast())
4185 },
4186 StylesheetSource::Constructed(_) => true,
4189 }
4190 })
4191 .cloned();
4192
4193 if self.has_browsing_context() {
4194 self.window.layout_mut().add_stylesheet(
4195 sheet.clone(),
4196 insertion_point.as_ref().map(|s| s.sheet.clone()),
4197 );
4198 }
4199
4200 DocumentOrShadowRoot::add_stylesheet(
4201 StylesheetSource::Element(Dom::from_ref(owner_node)),
4202 StylesheetSetRef::Document(stylesheets),
4203 sheet,
4204 insertion_point,
4205 self.style_shared_lock(),
4206 );
4207 }
4208
4209 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4214 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4215 debug_assert!(cssom_stylesheet.is_constructed());
4216
4217 let stylesheets = &mut *self.stylesheets.borrow_mut();
4218 let sheet = cssom_stylesheet.style_stylesheet().clone();
4219
4220 let insertion_point = stylesheets
4221 .iter()
4222 .last()
4223 .map(|(sheet, _origin)| sheet)
4224 .cloned();
4225
4226 if self.has_browsing_context() {
4227 self.window.layout_mut().add_stylesheet(
4228 sheet.clone(),
4229 insertion_point.as_ref().map(|s| s.sheet.clone()),
4230 );
4231 }
4232
4233 DocumentOrShadowRoot::add_stylesheet(
4234 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4235 StylesheetSetRef::Document(stylesheets),
4236 sheet,
4237 insertion_point,
4238 self.style_shared_lock(),
4239 );
4240 }
4241
4242 pub(crate) fn load_web_fonts_from_stylesheet(&self, stylesheet: &Arc<Stylesheet>) {
4244 self.window
4245 .layout()
4246 .load_web_fonts_from_stylesheet(stylesheet);
4247 }
4248
4249 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4252 if self.has_browsing_context() {
4253 self.window
4254 .layout_mut()
4255 .remove_stylesheet(stylesheet.clone());
4256 }
4257
4258 DocumentOrShadowRoot::remove_stylesheet(
4259 owner,
4260 stylesheet,
4261 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4262 )
4263 }
4264
4265 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4266 Ref::map(self.id_map.borrow(), |map| {
4267 map.get(id).map(|vec| &**vec).unwrap_or_default()
4268 })
4269 }
4270
4271 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4272 Ref::map(self.name_map.borrow(), |map| {
4273 map.get(name).map(|vec| &**vec).unwrap_or_default()
4274 })
4275 }
4276
4277 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4278 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4279 self.pending_restyles
4280 .borrow_mut()
4281 .drain()
4282 .filter_map(|(elem, restyle)| {
4283 let node = elem.upcast::<Node>();
4284 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4285 return None;
4286 }
4287 node.note_dirty_descendants();
4288 Some((node.to_trusted_node_address(), restyle.0))
4289 })
4290 .collect()
4291 }
4292
4293 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4294 self.animation_timeline.borrow_mut().advance_specific(delta);
4295 let current_timeline_value = self.current_animation_timeline_value();
4296 self.animations
4297 .borrow()
4298 .update_for_new_timeline_value(&self.window, current_timeline_value);
4299 }
4300
4301 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4302 let current_timeline_value = self.current_animation_timeline_value();
4303 self.animations
4304 .borrow()
4305 .mark_animating_nodes_as_dirty(current_timeline_value);
4306 }
4307
4308 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4309 self.animation_timeline.borrow().current_value()
4310 }
4311
4312 pub(crate) fn animations(&self) -> Ref<'_, Animations> {
4313 self.animations.borrow()
4314 }
4315
4316 pub(crate) fn update_animations_post_reflow(&self) {
4317 self.animations
4318 .borrow()
4319 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4320 self.image_animation_manager
4321 .borrow()
4322 .maybe_schedule_update_after_layout(
4323 &self.window,
4324 self.current_animation_timeline_value(),
4325 );
4326 }
4327
4328 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4329 self.animations.borrow().cancel_animations_for_node(node);
4330 self.image_animation_manager
4331 .borrow()
4332 .cancel_animations_for_node(node);
4333 }
4334
4335 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4337 if !pref!(layout_animations_test_enabled) {
4339 self.animation_timeline.borrow_mut().update();
4340 }
4341
4342 let current_timeline_value = self.current_animation_timeline_value();
4349 self.animations
4350 .borrow()
4351 .update_for_new_timeline_value(&self.window, current_timeline_value);
4352 self.maybe_mark_animating_nodes_as_dirty();
4353
4354 self.window()
4356 .as_global_scope()
4357 .perform_a_microtask_checkpoint(can_gc);
4358
4359 let _realm = enter_realm(self);
4361 self.animations().send_pending_events(self.window(), can_gc);
4362 }
4363
4364 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4365 self.image_animation_manager.borrow()
4366 }
4367
4368 pub(crate) fn set_has_pending_animated_image_update(&self) {
4369 self.has_pending_animated_image_update.set(true);
4370 }
4371
4372 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4374 if self.will_declaratively_refresh() {
4376 return;
4377 }
4378
4379 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4381 Regex::new(
4385 r#"(?xs)
4386 ^
4387 \s* # 3
4388 ((?<time>[0-9]+)|\.) # 5-6
4389 [0-9.]* # 8
4390 (
4391 (
4392 (\s*;|\s*,|\s) # 10.3
4393 \s* # 10.4
4394 )
4395 (
4396 (
4397 (U|u)(R|r)(L|l) # 11.2-11.4
4398 \s*=\s* # 11.5-11.7
4399 )?
4400 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4401 |
4402 (?<url4>(?s-u:.)*)
4403 )
4404 )?
4405 $
4406 "#,
4407 )
4408 .unwrap()
4409 });
4410
4411 let mut url_record = self.url();
4413 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4414 captures
4415 } else {
4416 return;
4417 };
4418 let time = if let Some(time_string) = captures.name("time") {
4419 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4420 } else {
4421 0
4422 };
4423 let captured_url = captures.name("url1").or(captures
4424 .name("url2")
4425 .or(captures.name("url3").or(captures.name("url4"))));
4426
4427 if let Some(url_match) = captured_url {
4429 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4430 Some(&url_record),
4431 &String::from_utf8_lossy(url_match.as_bytes()),
4432 ) {
4433 info!("Refresh to {}", url.debug_compact());
4434 url
4435 } else {
4436 return;
4438 }
4439 }
4440 if self.completely_loaded() {
4442 self.window.as_global_scope().schedule_callback(
4444 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4445 window: DomRoot::from_ref(self.window()),
4446 url: url_record,
4447 }),
4448 Duration::from_secs(time),
4449 );
4450 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4451 } else {
4452 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4453 url: url_record,
4454 time,
4455 });
4456 }
4457 }
4458
4459 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4460 self.declarative_refresh.borrow().is_some()
4461 }
4462 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4463 *self.declarative_refresh.borrow_mut() = Some(refresh);
4464 }
4465
4466 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4468 if self.visibility_state.get() == visibility_state {
4470 return;
4471 }
4472 self.visibility_state.set(visibility_state);
4474 let entry = VisibilityStateEntry::new(
4477 &self.global(),
4478 visibility_state,
4479 CrossProcessInstant::now(),
4480 can_gc,
4481 );
4482 self.window
4483 .Performance()
4484 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
4485
4486 if visibility_state == DocumentVisibilityState::Hidden {
4497 self.window
4498 .Navigator()
4499 .GetGamepads()
4500 .iter_mut()
4501 .for_each(|gamepad| {
4502 if let Some(g) = gamepad {
4503 g.vibration_actuator().handle_visibility_change();
4504 }
4505 });
4506 }
4507
4508 self.upcast::<EventTarget>()
4510 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4511 }
4512
4513 pub(crate) fn is_initial_about_blank(&self) -> bool {
4515 self.is_initial_about_blank.get()
4516 }
4517
4518 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4520 self.allow_declarative_shadow_roots.get()
4521 }
4522
4523 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4524 self.has_trustworthy_ancestor_origin.get()
4525 }
4526
4527 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4528 self.has_trustworthy_ancestor_origin.get() ||
4529 self.origin().immutable().is_potentially_trustworthy()
4530 }
4531
4532 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4533 self.highlighted_dom_node.set(node);
4534 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4535 }
4536
4537 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4538 self.highlighted_dom_node.get()
4539 }
4540
4541 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4542 self.custom_element_reaction_stack.clone()
4543 }
4544
4545 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4546 self.active_sandboxing_flag_set.get().contains(flag)
4547 }
4548
4549 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4550 self.active_sandboxing_flag_set.set(flags)
4551 }
4552
4553 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4554 self.creation_sandboxing_flag_set.get()
4555 }
4556
4557 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4558 &self,
4559 ) -> SandboxingFlagSet {
4560 self.window()
4561 .window_proxy()
4562 .frame_element()
4563 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4564 .map(HTMLIFrameElement::sandboxing_flag_set)
4565 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4566 }
4567
4568 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4569 self.window()
4570 .scrolling_box_query(None, flags)
4571 .expect("We should always have a ScrollingBox for the Viewport")
4572 }
4573
4574 pub(crate) fn notify_embedder_favicon(&self) {
4575 if let Some(ref image) = *self.favicon.borrow() {
4576 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4577 }
4578 }
4579
4580 pub(crate) fn set_favicon(&self, favicon: Image) {
4581 *self.favicon.borrow_mut() = Some(favicon);
4582 self.notify_embedder_favicon();
4583 }
4584}
4585
4586#[allow(non_snake_case)]
4587impl DocumentMethods<crate::DomTypeHolder> for Document {
4588 fn Constructor(
4590 window: &Window,
4591 proto: Option<HandleObject>,
4592 can_gc: CanGc,
4593 ) -> Fallible<DomRoot<Document>> {
4594 let doc = window.Document();
4595 let docloader = DocumentLoader::new(&doc.loader());
4596 Ok(Document::new_with_proto(
4597 window,
4598 proto,
4599 HasBrowsingContext::No,
4600 None,
4601 doc.origin().clone(),
4602 IsHTMLDocument::NonHTMLDocument,
4603 None,
4604 None,
4605 DocumentActivity::Inactive,
4606 DocumentSource::NotFromParser,
4607 docloader,
4608 None,
4609 None,
4610 Default::default(),
4611 false,
4612 doc.allow_declarative_shadow_roots(),
4613 Some(doc.insecure_requests_policy()),
4614 doc.has_trustworthy_ancestor_or_current_origin(),
4615 doc.custom_element_reaction_stack(),
4616 doc.active_sandboxing_flag_set.get(),
4617 can_gc,
4618 ))
4619 }
4620
4621 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
4623 false
4624 }
4625
4626 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4628 self.stylesheet_list.or_init(|| {
4629 StyleSheetList::new(
4630 &self.window,
4631 StyleSheetListOwner::Document(Dom::from_ref(self)),
4632 can_gc,
4633 )
4634 })
4635 }
4636
4637 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4639 self.implementation
4640 .or_init(|| DOMImplementation::new(self, can_gc))
4641 }
4642
4643 fn URL(&self) -> USVString {
4645 USVString(String::from(self.url().as_str()))
4646 }
4647
4648 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4650 self.document_or_shadow_root.get_active_element(
4651 self.get_focused_element(),
4652 self.GetBody(),
4653 self.GetDocumentElement(),
4654 )
4655 }
4656
4657 fn HasFocus(&self) -> bool {
4659 if self.window().parent_info().is_none() {
4681 self.is_fully_active()
4683 } else {
4684 self.is_fully_active() && self.has_focus.get()
4686 }
4687 }
4688
4689 fn Domain(&self) -> DOMString {
4691 if !self.has_browsing_context {
4693 return DOMString::new();
4694 }
4695
4696 match self.origin.effective_domain() {
4698 None => DOMString::new(),
4700 Some(Host::Domain(domain)) => DOMString::from(domain),
4702 Some(host) => DOMString::from(host.to_string()),
4703 }
4704 }
4705
4706 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4708 if !self.has_browsing_context {
4710 return Err(Error::Security);
4711 }
4712
4713 if self.has_active_sandboxing_flag(
4716 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4717 ) {
4718 return Err(Error::Security);
4719 }
4720
4721 let effective_domain = match self.origin.effective_domain() {
4723 Some(effective_domain) => effective_domain,
4724 None => return Err(Error::Security),
4725 };
4726
4727 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
4729 None => return Err(Error::Security),
4730 Some(host) => host,
4731 };
4732
4733 self.origin.set_domain(host);
4735
4736 Ok(())
4737 }
4738
4739 fn Referrer(&self) -> DOMString {
4741 match self.referrer {
4742 Some(ref referrer) => DOMString::from(referrer.to_string()),
4743 None => DOMString::new(),
4744 }
4745 }
4746
4747 fn DocumentURI(&self) -> USVString {
4749 self.URL()
4750 }
4751
4752 fn CompatMode(&self) -> DOMString {
4754 DOMString::from(match self.quirks_mode.get() {
4755 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4756 QuirksMode::Quirks => "BackCompat",
4757 })
4758 }
4759
4760 fn CharacterSet(&self) -> DOMString {
4762 DOMString::from(self.encoding.get().name())
4763 }
4764
4765 fn Charset(&self) -> DOMString {
4767 self.CharacterSet()
4768 }
4769
4770 fn InputEncoding(&self) -> DOMString {
4772 self.CharacterSet()
4773 }
4774
4775 fn ContentType(&self) -> DOMString {
4777 DOMString::from(self.content_type.to_string())
4778 }
4779
4780 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4782 self.upcast::<Node>()
4783 .children()
4784 .filter_map(DomRoot::downcast)
4785 .next()
4786 }
4787
4788 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4790 self.upcast::<Node>().child_elements().next()
4791 }
4792
4793 fn GetElementsByTagName(
4795 &self,
4796 qualified_name: DOMString,
4797 can_gc: CanGc,
4798 ) -> DomRoot<HTMLCollection> {
4799 let qualified_name = LocalName::from(qualified_name);
4800 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4801 return DomRoot::from_ref(entry);
4802 }
4803 let result = HTMLCollection::by_qualified_name(
4804 &self.window,
4805 self.upcast(),
4806 qualified_name.clone(),
4807 can_gc,
4808 );
4809 self.tag_map
4810 .borrow_mut()
4811 .insert(qualified_name, Dom::from_ref(&*result));
4812 result
4813 }
4814
4815 fn GetElementsByTagNameNS(
4817 &self,
4818 maybe_ns: Option<DOMString>,
4819 tag_name: DOMString,
4820 can_gc: CanGc,
4821 ) -> DomRoot<HTMLCollection> {
4822 let ns = namespace_from_domstring(maybe_ns);
4823 let local = LocalName::from(tag_name);
4824 let qname = QualName::new(None, ns, local);
4825 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4826 return DomRoot::from_ref(collection);
4827 }
4828 let result =
4829 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4830 self.tagns_map
4831 .borrow_mut()
4832 .insert(qname, Dom::from_ref(&*result));
4833 result
4834 }
4835
4836 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4838 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4839 .map(Atom::from)
4840 .collect();
4841 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4842 return DomRoot::from_ref(collection);
4843 }
4844 let result = HTMLCollection::by_atomic_class_name(
4845 &self.window,
4846 self.upcast(),
4847 class_atoms.clone(),
4848 can_gc,
4849 );
4850 self.classes_map
4851 .borrow_mut()
4852 .insert(class_atoms, Dom::from_ref(&*result));
4853 result
4854 }
4855
4856 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4858 self.get_element_by_id(&Atom::from(id))
4859 }
4860
4861 fn CreateElement(
4863 &self,
4864 mut local_name: DOMString,
4865 options: StringOrElementCreationOptions,
4866 can_gc: CanGc,
4867 ) -> Fallible<DomRoot<Element>> {
4868 if !is_valid_element_local_name(&local_name.str()) {
4871 debug!("Not a valid element name");
4872 return Err(Error::InvalidCharacter);
4873 }
4874
4875 if self.is_html_document {
4876 local_name.make_ascii_lowercase();
4877 }
4878
4879 let ns = if self.is_html_document || self.is_xhtml_document() {
4880 ns!(html)
4881 } else {
4882 ns!()
4883 };
4884
4885 let name = QualName::new(None, ns, LocalName::from(local_name));
4886 let is = match options {
4887 StringOrElementCreationOptions::String(_) => None,
4888 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4889 options.is.as_ref().map(LocalName::from)
4890 },
4891 };
4892 Ok(Element::create(
4893 name,
4894 is,
4895 self,
4896 ElementCreator::ScriptCreated,
4897 CustomElementCreationMode::Synchronous,
4898 None,
4899 can_gc,
4900 ))
4901 }
4902
4903 fn CreateElementNS(
4905 &self,
4906 namespace: Option<DOMString>,
4907 qualified_name: DOMString,
4908 options: StringOrElementCreationOptions,
4909 can_gc: CanGc,
4910 ) -> Fallible<DomRoot<Element>> {
4911 let context = domname::Context::Element;
4914 let (namespace, prefix, local_name) =
4915 domname::validate_and_extract(namespace, &qualified_name, context)?;
4916
4917 let name = QualName::new(prefix, namespace, local_name);
4920 let is = match options {
4921 StringOrElementCreationOptions::String(_) => None,
4922 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4923 options.is.as_ref().map(LocalName::from)
4924 },
4925 };
4926
4927 Ok(Element::create(
4929 name,
4930 is,
4931 self,
4932 ElementCreator::ScriptCreated,
4933 CustomElementCreationMode::Synchronous,
4934 None,
4935 can_gc,
4936 ))
4937 }
4938
4939 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
4941 if !is_valid_attribute_local_name(&local_name.str()) {
4944 debug!("Not a valid attribute name");
4945 return Err(Error::InvalidCharacter);
4946 }
4947 if self.is_html_document {
4948 local_name.make_ascii_lowercase();
4949 }
4950 let name = LocalName::from(local_name);
4951 let value = AttrValue::String("".to_owned());
4952
4953 Ok(Attr::new(
4954 self,
4955 name.clone(),
4956 value,
4957 name,
4958 ns!(),
4959 None,
4960 None,
4961 can_gc,
4962 ))
4963 }
4964
4965 fn CreateAttributeNS(
4967 &self,
4968 namespace: Option<DOMString>,
4969 qualified_name: DOMString,
4970 can_gc: CanGc,
4971 ) -> Fallible<DomRoot<Attr>> {
4972 let context = domname::Context::Attribute;
4975 let (namespace, prefix, local_name) =
4976 domname::validate_and_extract(namespace, &qualified_name, context)?;
4977 let value = AttrValue::String("".to_owned());
4978 let qualified_name = LocalName::from(qualified_name);
4979 Ok(Attr::new(
4980 self,
4981 local_name,
4982 value,
4983 qualified_name,
4984 namespace,
4985 prefix,
4986 None,
4987 can_gc,
4988 ))
4989 }
4990
4991 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
4993 DocumentFragment::new(self, can_gc)
4994 }
4995
4996 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
4998 Text::new(data, self, can_gc)
4999 }
5000
5001 fn CreateCDATASection(
5003 &self,
5004 data: DOMString,
5005 can_gc: CanGc,
5006 ) -> Fallible<DomRoot<CDATASection>> {
5007 if self.is_html_document {
5009 return Err(Error::NotSupported);
5010 }
5011
5012 if data.contains("]]>") {
5014 return Err(Error::InvalidCharacter);
5015 }
5016
5017 Ok(CDATASection::new(data, self, can_gc))
5019 }
5020
5021 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5023 Comment::new(data, self, None, can_gc)
5024 }
5025
5026 fn CreateProcessingInstruction(
5028 &self,
5029 target: DOMString,
5030 data: DOMString,
5031 can_gc: CanGc,
5032 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5033 if !matches_name_production(&target.str()) {
5035 return Err(Error::InvalidCharacter);
5036 }
5037
5038 if data.contains("?>") {
5040 return Err(Error::InvalidCharacter);
5041 }
5042
5043 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5045 }
5046
5047 fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5049 if node.is::<Document>() || node.is::<ShadowRoot>() {
5051 return Err(Error::NotSupported);
5052 }
5053
5054 let clone_children = if deep {
5056 CloneChildrenFlag::CloneChildren
5057 } else {
5058 CloneChildrenFlag::DoNotCloneChildren
5059 };
5060
5061 Ok(Node::clone(node, Some(self), clone_children, can_gc))
5062 }
5063
5064 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5066 if node.is::<Document>() {
5068 return Err(Error::NotSupported);
5069 }
5070
5071 if node.is::<ShadowRoot>() {
5073 return Err(Error::HierarchyRequest);
5074 }
5075
5076 Node::adopt(node, self, can_gc);
5078
5079 Ok(DomRoot::from_ref(node))
5081 }
5082
5083 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5085 interface.make_ascii_lowercase();
5086 match &*interface.str() {
5087 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5088 &self.window,
5089 can_gc,
5090 ))),
5091 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5092 CompositionEvent::new_uninitialized(&self.window, can_gc),
5093 )),
5094 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5095 self.window.upcast(),
5096 can_gc,
5097 ))),
5098 "events" | "event" | "htmlevents" | "svgevents" => {
5101 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5102 },
5103 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5104 &self.window,
5105 can_gc,
5106 ))),
5107 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5108 &self.window,
5109 can_gc,
5110 ))),
5111 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5112 &self.window,
5113 can_gc,
5114 ))),
5115 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5116 self.window.upcast(),
5117 can_gc,
5118 ))),
5119 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5120 &self.window,
5121 can_gc,
5122 ))),
5123 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5124 &self.window,
5125 "".into(),
5126 can_gc,
5127 ))),
5128 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5129 &self.window,
5130 &TouchList::new(&self.window, &[], can_gc),
5131 &TouchList::new(&self.window, &[], can_gc),
5132 &TouchList::new(&self.window, &[], can_gc),
5133 can_gc,
5134 ))),
5135 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5136 &self.window,
5137 can_gc,
5138 ))),
5139 _ => Err(Error::NotSupported),
5140 }
5141 }
5142
5143 fn LastModified(&self) -> DOMString {
5145 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5146 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5152 }))
5153 }
5154
5155 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5157 Range::new_with_doc(self, None, can_gc)
5158 }
5159
5160 fn CreateNodeIterator(
5162 &self,
5163 root: &Node,
5164 what_to_show: u32,
5165 filter: Option<Rc<NodeFilter>>,
5166 can_gc: CanGc,
5167 ) -> DomRoot<NodeIterator> {
5168 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5169 }
5170
5171 fn CreateTreeWalker(
5173 &self,
5174 root: &Node,
5175 what_to_show: u32,
5176 filter: Option<Rc<NodeFilter>>,
5177 ) -> DomRoot<TreeWalker> {
5178 TreeWalker::new(self, root, what_to_show, filter)
5179 }
5180
5181 fn Title(&self) -> DOMString {
5183 self.title().unwrap_or_else(|| DOMString::from(""))
5184 }
5185
5186 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5188 let root = match self.GetDocumentElement() {
5189 Some(root) => root,
5190 None => return,
5191 };
5192
5193 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5194 let elem = root.upcast::<Node>().child_elements().find(|node| {
5195 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5196 });
5197 match elem {
5198 Some(elem) => DomRoot::upcast::<Node>(elem),
5199 None => {
5200 let name = QualName::new(None, ns!(svg), local_name!("title"));
5201 let elem = Element::create(
5202 name,
5203 None,
5204 self,
5205 ElementCreator::ScriptCreated,
5206 CustomElementCreationMode::Synchronous,
5207 None,
5208 can_gc,
5209 );
5210 let parent = root.upcast::<Node>();
5211 let child = elem.upcast::<Node>();
5212 parent
5213 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5214 .unwrap()
5215 },
5216 }
5217 } else if root.namespace() == &ns!(html) {
5218 let elem = root
5219 .upcast::<Node>()
5220 .traverse_preorder(ShadowIncluding::No)
5221 .find(|node| node.is::<HTMLTitleElement>());
5222 match elem {
5223 Some(elem) => elem,
5224 None => match self.GetHead() {
5225 Some(head) => {
5226 let name = QualName::new(None, ns!(html), local_name!("title"));
5227 let elem = Element::create(
5228 name,
5229 None,
5230 self,
5231 ElementCreator::ScriptCreated,
5232 CustomElementCreationMode::Synchronous,
5233 None,
5234 can_gc,
5235 );
5236 head.upcast::<Node>()
5237 .AppendChild(elem.upcast(), can_gc)
5238 .unwrap()
5239 },
5240 None => return,
5241 },
5242 }
5243 } else {
5244 return;
5245 };
5246
5247 node.set_text_content_for_element(Some(title), can_gc);
5248 }
5249
5250 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5252 self.get_html_element().and_then(|root| {
5253 root.upcast::<Node>()
5254 .children()
5255 .filter_map(DomRoot::downcast)
5256 .next()
5257 })
5258 }
5259
5260 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5262 self.current_script.get()
5263 }
5264
5265 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5267 self.get_html_element().and_then(|root| {
5268 let node = root.upcast::<Node>();
5269 node.children()
5270 .find(|child| {
5271 matches!(
5272 child.type_id(),
5273 NodeTypeId::Element(ElementTypeId::HTMLElement(
5274 HTMLElementTypeId::HTMLBodyElement,
5275 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5276 HTMLElementTypeId::HTMLFrameSetElement,
5277 ))
5278 )
5279 })
5280 .map(|node| DomRoot::downcast(node).unwrap())
5281 })
5282 }
5283
5284 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5286 let new_body = match new_body {
5288 Some(new_body) => new_body,
5289 None => return Err(Error::HierarchyRequest),
5290 };
5291
5292 let node = new_body.upcast::<Node>();
5293 match node.type_id() {
5294 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5295 NodeTypeId::Element(ElementTypeId::HTMLElement(
5296 HTMLElementTypeId::HTMLFrameSetElement,
5297 )) => {},
5298 _ => return Err(Error::HierarchyRequest),
5299 }
5300
5301 let old_body = self.GetBody();
5303 if old_body.as_deref() == Some(new_body) {
5304 return Ok(());
5305 }
5306
5307 match (self.GetDocumentElement(), &old_body) {
5308 (Some(ref root), Some(child)) => {
5310 let root = root.upcast::<Node>();
5311 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5312 .unwrap();
5313 },
5314
5315 (None, _) => return Err(Error::HierarchyRequest),
5317
5318 (Some(ref root), &None) => {
5320 let root = root.upcast::<Node>();
5321 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5322 },
5323 }
5324 Ok(())
5325 }
5326
5327 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5329 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5330 }
5331
5332 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5334 self.images.or_init(|| {
5335 HTMLCollection::new_with_filter_fn(
5336 &self.window,
5337 self.upcast(),
5338 |element, _| element.is::<HTMLImageElement>(),
5339 can_gc,
5340 )
5341 })
5342 }
5343
5344 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5346 self.embeds.or_init(|| {
5347 HTMLCollection::new_with_filter_fn(
5348 &self.window,
5349 self.upcast(),
5350 |element, _| element.is::<HTMLEmbedElement>(),
5351 can_gc,
5352 )
5353 })
5354 }
5355
5356 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5358 self.Embeds(can_gc)
5359 }
5360
5361 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5363 self.links.or_init(|| {
5364 HTMLCollection::new_with_filter_fn(
5365 &self.window,
5366 self.upcast(),
5367 |element, _| {
5368 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5369 element.has_attribute(&local_name!("href"))
5370 },
5371 can_gc,
5372 )
5373 })
5374 }
5375
5376 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5378 self.forms.or_init(|| {
5379 HTMLCollection::new_with_filter_fn(
5380 &self.window,
5381 self.upcast(),
5382 |element, _| element.is::<HTMLFormElement>(),
5383 can_gc,
5384 )
5385 })
5386 }
5387
5388 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5390 self.scripts.or_init(|| {
5391 HTMLCollection::new_with_filter_fn(
5392 &self.window,
5393 self.upcast(),
5394 |element, _| element.is::<HTMLScriptElement>(),
5395 can_gc,
5396 )
5397 })
5398 }
5399
5400 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5402 self.anchors.or_init(|| {
5403 HTMLCollection::new_with_filter_fn(
5404 &self.window,
5405 self.upcast(),
5406 |element, _| {
5407 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5408 },
5409 can_gc,
5410 )
5411 })
5412 }
5413
5414 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5416 self.applets
5417 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5418 }
5419
5420 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5422 if self.is_fully_active() {
5423 Some(self.window.Location())
5424 } else {
5425 None
5426 }
5427 }
5428
5429 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5431 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5432 }
5433
5434 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5436 self.upcast::<Node>().child_elements().next()
5437 }
5438
5439 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5441 self.upcast::<Node>()
5442 .rev_children()
5443 .filter_map(DomRoot::downcast)
5444 .next()
5445 }
5446
5447 fn ChildElementCount(&self) -> u32 {
5449 self.upcast::<Node>().child_elements().count() as u32
5450 }
5451
5452 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5454 self.upcast::<Node>().prepend(nodes, can_gc)
5455 }
5456
5457 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5459 self.upcast::<Node>().append(nodes, can_gc)
5460 }
5461
5462 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5464 self.upcast::<Node>().replace_children(nodes, can_gc)
5465 }
5466
5467 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5469 let root = self.upcast::<Node>();
5470 root.query_selector(selectors)
5471 }
5472
5473 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5475 let root = self.upcast::<Node>();
5476 root.query_selector_all(selectors)
5477 }
5478
5479 fn ReadyState(&self) -> DocumentReadyState {
5481 self.ready_state.get()
5482 }
5483
5484 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5486 if self.has_browsing_context {
5487 Some(DomRoot::from_ref(&*self.window))
5488 } else {
5489 None
5490 }
5491 }
5492
5493 fn GetCookie(&self) -> Fallible<DOMString> {
5495 if self.is_cookie_averse() {
5496 return Ok(DOMString::new());
5497 }
5498
5499 if !self.origin.is_tuple() {
5500 return Err(Error::Security);
5501 }
5502
5503 let url = self.url();
5504 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5505 let _ = self
5506 .window
5507 .as_global_scope()
5508 .resource_threads()
5509 .send(GetCookiesForUrl(url, tx, NonHTTP));
5510 let cookies = rx.recv().unwrap();
5511 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5512 }
5513
5514 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5516 if self.is_cookie_averse() {
5517 return Ok(());
5518 }
5519
5520 if !self.origin.is_tuple() {
5521 return Err(Error::Security);
5522 }
5523
5524 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5525 vec![cookie]
5526 } else {
5527 vec![]
5528 };
5529
5530 let _ = self
5531 .window
5532 .as_global_scope()
5533 .resource_threads()
5534 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5535 Ok(())
5536 }
5537
5538 fn BgColor(&self) -> DOMString {
5540 self.get_body_attribute(&local_name!("bgcolor"))
5541 }
5542
5543 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5545 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5546 }
5547
5548 fn FgColor(&self) -> DOMString {
5550 self.get_body_attribute(&local_name!("text"))
5551 }
5552
5553 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5555 self.set_body_attribute(&local_name!("text"), value, can_gc)
5556 }
5557
5558 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5560 if name.is_empty() {
5561 return None;
5562 }
5563 let name = Atom::from(name);
5564
5565 let elements_with_name = self.get_elements_with_name(&name);
5568 let name_iter = elements_with_name
5569 .iter()
5570 .filter(|elem| is_named_element_with_name_attribute(elem));
5571 let elements_with_id = self.get_elements_with_id(&name);
5572 let id_iter = elements_with_id
5573 .iter()
5574 .filter(|elem| is_named_element_with_id_attribute(elem));
5575 let mut elements = name_iter.chain(id_iter);
5576
5577 let first = elements.next()?;
5584 if elements.all(|other| first == other) {
5585 if let Some(nested_window_proxy) = first
5586 .downcast::<HTMLIFrameElement>()
5587 .and_then(|iframe| iframe.GetContentWindow())
5588 {
5589 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5590 }
5591
5592 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5594 }
5595
5596 #[derive(JSTraceable, MallocSizeOf)]
5599 struct DocumentNamedGetter {
5600 #[no_trace]
5601 name: Atom,
5602 }
5603 impl CollectionFilter for DocumentNamedGetter {
5604 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5605 let type_ = match elem.upcast::<Node>().type_id() {
5606 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5607 _ => return false,
5608 };
5609 match type_ {
5610 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5611 elem.get_name().as_ref() == Some(&self.name)
5612 },
5613 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5614 name == *self.name ||
5615 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5616 }),
5617 _ => false,
5621 }
5622 }
5623 }
5624 let collection = HTMLCollection::create(
5625 self.window(),
5626 self.upcast(),
5627 Box::new(DocumentNamedGetter { name }),
5628 can_gc,
5629 );
5630 Some(NamedPropertyValue::HTMLCollection(collection))
5631 }
5632
5633 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5635 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5636
5637 let name_map = self.name_map.borrow();
5638 for (name, elements) in &(name_map).0 {
5639 if name.is_empty() {
5640 continue;
5641 }
5642 let mut name_iter = elements
5643 .iter()
5644 .filter(|elem| is_named_element_with_name_attribute(elem));
5645 if let Some(first) = name_iter.next() {
5646 names_with_first_named_element_map.insert(name, first);
5647 }
5648 }
5649 let id_map = self.id_map.borrow();
5650 for (id, elements) in &(id_map).0 {
5651 if id.is_empty() {
5652 continue;
5653 }
5654 let mut id_iter = elements
5655 .iter()
5656 .filter(|elem| is_named_element_with_id_attribute(elem));
5657 if let Some(first) = id_iter.next() {
5658 match names_with_first_named_element_map.entry(id) {
5659 Vacant(entry) => drop(entry.insert(first)),
5660 Occupied(mut entry) => {
5661 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5662 *entry.get_mut() = first;
5663 }
5664 },
5665 }
5666 }
5667 }
5668
5669 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5670 names_with_first_named_element_map
5671 .iter()
5672 .map(|(k, v)| (*k, *v))
5673 .collect();
5674 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5675 if a.1 == b.1 {
5676 a.0.cmp(b.0)
5679 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5680 Ordering::Less
5681 } else {
5682 Ordering::Greater
5683 }
5684 });
5685
5686 names_with_first_named_element_vec
5687 .iter()
5688 .map(|(k, _v)| DOMString::from(&***k))
5689 .collect()
5690 }
5691
5692 fn Clear(&self) {
5694 }
5696
5697 fn CaptureEvents(&self) {
5699 }
5701
5702 fn ReleaseEvents(&self) {
5704 }
5706
5707 global_event_handlers!();
5709
5710 event_handler!(
5712 readystatechange,
5713 GetOnreadystatechange,
5714 SetOnreadystatechange
5715 );
5716
5717 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5719 self.document_or_shadow_root.element_from_point(
5720 x,
5721 y,
5722 self.GetDocumentElement(),
5723 self.has_browsing_context,
5724 )
5725 }
5726
5727 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5729 self.document_or_shadow_root.elements_from_point(
5730 x,
5731 y,
5732 self.GetDocumentElement(),
5733 self.has_browsing_context,
5734 )
5735 }
5736
5737 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5739 if self.quirks_mode() == QuirksMode::Quirks {
5741 if let Some(ref body) = self.GetBody() {
5743 let e = body.upcast::<Element>();
5744 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5748 return Some(DomRoot::from_ref(e));
5749 }
5750 }
5751
5752 return None;
5754 }
5755
5756 self.GetDocumentElement()
5759 }
5760
5761 fn Open(
5763 &self,
5764 _unused1: Option<DOMString>,
5765 _unused2: Option<DOMString>,
5766 can_gc: CanGc,
5767 ) -> Fallible<DomRoot<Document>> {
5768 if !self.is_html_document() {
5770 return Err(Error::InvalidState(None));
5771 }
5772
5773 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5775 return Err(Error::InvalidState(None));
5776 }
5777
5778 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5780
5781 if !self.origin.same_origin(&entry_responsible_document.origin) {
5783 return Err(Error::Security);
5784 }
5785
5786 if self
5788 .get_current_parser()
5789 .is_some_and(|parser| parser.is_active())
5790 {
5791 return Ok(DomRoot::from_ref(self));
5792 }
5793
5794 if self.is_prompting_or_unloading() {
5796 return Ok(DomRoot::from_ref(self));
5797 }
5798
5799 if self.active_parser_was_aborted.get() {
5801 return Ok(DomRoot::from_ref(self));
5802 }
5803
5804 self.window().set_navigation_start();
5808
5809 if self.has_browsing_context() {
5812 self.abort(can_gc);
5815 }
5816
5817 for node in self
5819 .upcast::<Node>()
5820 .traverse_preorder(ShadowIncluding::Yes)
5821 {
5822 node.upcast::<EventTarget>().remove_all_listeners();
5823 }
5824
5825 if self.window.Document() == DomRoot::from_ref(self) {
5827 self.window.upcast::<EventTarget>().remove_all_listeners();
5828 }
5829
5830 Node::replace_all(None, self.upcast::<Node>(), can_gc);
5832
5833 if self.is_fully_active() {
5840 let mut new_url = entry_responsible_document.url();
5842
5843 if entry_responsible_document != DomRoot::from_ref(self) {
5845 new_url.set_fragment(None);
5846 }
5847
5848 self.set_url(new_url);
5851 }
5852
5853 self.is_initial_about_blank.set(false);
5855
5856 self.set_quirks_mode(QuirksMode::NoQuirks);
5862
5863 let resource_threads = self.window.as_global_scope().resource_threads().clone();
5869 *self.loader.borrow_mut() =
5870 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
5871 ServoParser::parse_html_script_input(self, self.url());
5872
5873 self.ready_state.set(DocumentReadyState::Loading);
5879
5880 Ok(DomRoot::from_ref(self))
5882 }
5883
5884 fn Open_(
5886 &self,
5887 url: USVString,
5888 target: DOMString,
5889 features: DOMString,
5890 can_gc: CanGc,
5891 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
5892 self.browsing_context()
5893 .ok_or(Error::InvalidAccess)?
5894 .open(url, target, features, can_gc)
5895 }
5896
5897 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5899 self.write(text, false, "Document", "write", can_gc)
5902 }
5903
5904 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5906 self.write(text, true, "Document", "writeln", can_gc)
5909 }
5910
5911 fn Close(&self, can_gc: CanGc) -> ErrorResult {
5913 if !self.is_html_document() {
5914 return Err(Error::InvalidState(None));
5916 }
5917
5918 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5920 return Err(Error::InvalidState(None));
5921 }
5922
5923 let parser = match self.get_current_parser() {
5924 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
5925 _ => {
5926 return Ok(());
5928 },
5929 };
5930
5931 parser.close(can_gc);
5933
5934 Ok(())
5935 }
5936
5937 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
5939
5940 event_handler!(
5942 fullscreenchange,
5943 GetOnfullscreenchange,
5944 SetOnfullscreenchange
5945 );
5946
5947 fn FullscreenEnabled(&self) -> bool {
5949 self.get_allow_fullscreen()
5950 }
5951
5952 fn Fullscreen(&self) -> bool {
5954 self.fullscreen_element.get().is_some()
5955 }
5956
5957 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
5959 self.fullscreen_element.get()
5961 }
5962
5963 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
5965 self.exit_fullscreen(can_gc)
5966 }
5967
5968 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
5972 match self.media_controls.borrow().get(&*id.str()) {
5973 Some(m) => Ok(DomRoot::from_ref(m)),
5974 None => Err(Error::InvalidAccess),
5975 }
5976 }
5977
5978 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
5980 if self.has_browsing_context {
5981 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
5982 } else {
5983 None
5984 }
5985 }
5986
5987 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
5989 self.fonts
5990 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
5991 }
5992
5993 fn Hidden(&self) -> bool {
5995 self.visibility_state.get() == DocumentVisibilityState::Hidden
5996 }
5997
5998 fn VisibilityState(&self) -> DocumentVisibilityState {
6000 self.visibility_state.get()
6001 }
6002
6003 fn CreateExpression(
6004 &self,
6005 expression: DOMString,
6006 resolver: Option<Rc<XPathNSResolver>>,
6007 can_gc: CanGc,
6008 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6009 let global = self.global();
6010 let window = global.as_window();
6011 let evaluator = XPathEvaluator::new(window, None, can_gc);
6012 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateExpression(
6013 &*evaluator,
6014 expression,
6015 resolver,
6016 can_gc,
6017 )
6018 }
6019
6020 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6021 let global = self.global();
6022 let window = global.as_window();
6023 let evaluator = XPathEvaluator::new(window, None, can_gc);
6024 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6025 }
6026
6027 fn Evaluate(
6028 &self,
6029 expression: DOMString,
6030 context_node: &Node,
6031 resolver: Option<Rc<XPathNSResolver>>,
6032 type_: u16,
6033 result: Option<&super::types::XPathResult>,
6034 can_gc: CanGc,
6035 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6036 let global = self.global();
6037 let window = global.as_window();
6038 let evaluator = XPathEvaluator::new(window, None, can_gc);
6039 XPathEvaluatorMethods::<crate::DomTypeHolder>::Evaluate(
6040 &*evaluator,
6041 expression,
6042 context_node,
6043 resolver,
6044 type_,
6045 result,
6046 can_gc,
6047 )
6048 }
6049
6050 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6052 self.adopted_stylesheets_frozen_types.get_or_init(
6053 || {
6054 self.adopted_stylesheets
6055 .borrow()
6056 .clone()
6057 .iter()
6058 .map(|sheet| sheet.as_rooted())
6059 .collect()
6060 },
6061 context,
6062 retval,
6063 can_gc,
6064 );
6065 }
6066
6067 fn SetAdoptedStyleSheets(&self, context: JSContext, val: HandleValue) -> ErrorResult {
6069 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6070 context,
6071 self.adopted_stylesheets.borrow_mut().as_mut(),
6072 val,
6073 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6074 );
6075
6076 if result.is_ok() {
6078 self.adopted_stylesheets_frozen_types.clear()
6079 }
6080
6081 result
6082 }
6083}
6084
6085fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6086 if marker.get().is_none() {
6087 marker.set(Some(CrossProcessInstant::now()))
6088 }
6089}
6090
6091#[derive(Clone, Copy, PartialEq)]
6093pub(crate) enum FocusType {
6094 Element, Parent, }
6097
6098#[derive(Clone, Copy, PartialEq)]
6100pub enum FocusInitiator {
6101 Local,
6104 Remote,
6107}
6108
6109pub(crate) enum FocusEventType {
6111 Focus, Blur, }
6114
6115#[derive(JSTraceable, MallocSizeOf)]
6116pub(crate) enum AnimationFrameCallback {
6117 DevtoolsFramerateTick {
6118 actor_name: String,
6119 },
6120 FrameRequestCallback {
6121 #[conditional_malloc_size_of]
6122 callback: Rc<FrameRequestCallback>,
6123 },
6124}
6125
6126impl AnimationFrameCallback {
6127 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6128 match *self {
6129 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6130 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6131 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6132 devtools_sender.send(msg).unwrap();
6133 },
6134 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6135 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6138 },
6139 }
6140 }
6141}
6142
6143#[derive(Default, JSTraceable, MallocSizeOf)]
6144#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6145struct PendingInOrderScriptVec {
6146 scripts: DomRefCell<VecDeque<PendingScript>>,
6147}
6148
6149impl PendingInOrderScriptVec {
6150 fn is_empty(&self) -> bool {
6151 self.scripts.borrow().is_empty()
6152 }
6153
6154 fn push(&self, element: &HTMLScriptElement) {
6155 self.scripts
6156 .borrow_mut()
6157 .push_back(PendingScript::new(element));
6158 }
6159
6160 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6161 let mut scripts = self.scripts.borrow_mut();
6162 let entry = scripts
6163 .iter_mut()
6164 .find(|entry| &*entry.element == element)
6165 .unwrap();
6166 entry.loaded(result);
6167 }
6168
6169 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6170 let mut scripts = self.scripts.borrow_mut();
6171 let pair = scripts.front_mut()?.take_result()?;
6172 scripts.pop_front();
6173 Some(pair)
6174 }
6175
6176 fn clear(&self) {
6177 *self.scripts.borrow_mut() = Default::default();
6178 }
6179}
6180
6181#[derive(JSTraceable, MallocSizeOf)]
6182#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6183struct PendingScript {
6184 element: Dom<HTMLScriptElement>,
6185 load: Option<ScriptResult>,
6187}
6188
6189impl PendingScript {
6190 fn new(element: &HTMLScriptElement) -> Self {
6191 Self {
6192 element: Dom::from_ref(element),
6193 load: None,
6194 }
6195 }
6196
6197 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6198 Self {
6199 element: Dom::from_ref(element),
6200 load,
6201 }
6202 }
6203
6204 fn loaded(&mut self, result: ScriptResult) {
6205 assert!(self.load.is_none());
6206 self.load = Some(result);
6207 }
6208
6209 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6210 self.load
6211 .take()
6212 .map(|result| (DomRoot::from_ref(&*self.element), result))
6213 }
6214}
6215
6216fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6217 let type_ = match elem.upcast::<Node>().type_id() {
6218 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6219 _ => return false,
6220 };
6221 match type_ {
6222 HTMLElementTypeId::HTMLFormElement |
6223 HTMLElementTypeId::HTMLIFrameElement |
6224 HTMLElementTypeId::HTMLImageElement => true,
6225 _ => false,
6229 }
6230}
6231
6232fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6233 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6237}
6238
6239impl DocumentHelpers for Document {
6240 fn ensure_safe_to_run_script_or_layout(&self) {
6241 Document::ensure_safe_to_run_script_or_layout(self)
6242 }
6243}