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, 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::{CspList, PolicyDisposition};
23use cookie::Cookie;
24use cssparser::match_ignore_ascii_case;
25use data_url::mime::Mime;
26use devtools_traits::ScriptToDevtoolsControlMsg;
27use dom_struct::dom_struct;
28use embedder_traits::{AllowOrDeny, AnimationState, EmbedderMsg, FocusSequenceNumber, LoadStatus};
29use encoding_rs::{Encoding, UTF_8};
30use euclid::Point2D;
31use euclid::default::{Rect, Size2D};
32use fnv::FnvHashMap;
33use html5ever::{LocalName, Namespace, QualName, local_name, ns};
34use hyper_serde::Serde;
35use js::rust::{HandleObject, HandleValue, MutableHandleValue};
36use layout_api::{PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, TrustedNodeAddress};
37use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
38use net_traits::CookieSource::NonHTTP;
39use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
40use net_traits::policy_container::PolicyContainer;
41use net_traits::pub_domains::is_pub_domain;
42use net_traits::request::{InsecureRequestsPolicy, RequestBuilder};
43use net_traits::response::HttpsState;
44use net_traits::{FetchResponseListener, IpcSend, ReferrerPolicy};
45use percent_encoding::percent_decode;
46use profile_traits::ipc as profile_ipc;
47use profile_traits::time::TimerMetadataFrameType;
48use regex::bytes::Regex;
49use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
50use script_bindings::interfaces::DocumentHelpers;
51use script_bindings::script_runtime::JSContext;
52use script_traits::{DocumentActivity, ProgressiveWebMetricType};
53use servo_arc::Arc;
54use servo_config::pref;
55use servo_media::{ClientContextId, ServoMedia};
56use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
57use style::attr::AttrValue;
58use style::context::QuirksMode;
59use style::invalidation::element::restyle_hints::RestyleHint;
60use style::selector_parser::Snapshot;
61use style::shared_lock::SharedRwLock as StyleSharedRwLock;
62use style::str::{split_html_space_chars, str_join};
63use style::stylesheet_set::DocumentStylesheetSet;
64use style::stylesheets::{Origin, OriginSet, Stylesheet};
65use stylo_atoms::Atom;
66use url::Host;
67use uuid::Uuid;
68#[cfg(feature = "webgpu")]
69use webgpu_traits::WebGPUContextId;
70use webrender_api::units::DeviceIntRect;
71
72use crate::animation_timeline::AnimationTimeline;
73use crate::animations::Animations;
74use crate::canvas_context::CanvasContext as _;
75use crate::document_loader::{DocumentLoader, LoadType};
76use crate::dom::attr::Attr;
77use crate::dom::beforeunloadevent::BeforeUnloadEvent;
78use crate::dom::bindings::callback::ExceptionHandling;
79use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
80use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
81use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
82 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
83};
84use crate::dom::bindings::codegen::Bindings::ElementBinding::{
85 ScrollIntoViewContainer, ScrollIntoViewOptions, ScrollLogicalPosition,
86};
87use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
88use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
89use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
90use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
91use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
92use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
93use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
94use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
95use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
96use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
97use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMethods;
98use crate::dom::bindings::codegen::Bindings::WindowBinding::{
99 FrameRequestCallback, ScrollBehavior, ScrollOptions, WindowMethods,
100};
101use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
102use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
103use crate::dom::bindings::codegen::UnionTypes::{
104 BooleanOrScrollIntoViewOptions, NodeOrString, StringOrElementCreationOptions,
105 TrustedHTMLOrString,
106};
107use crate::dom::bindings::domname::{
108 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
109};
110use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
111use crate::dom::bindings::frozenarray::CachedFrozenArray;
112use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
113use crate::dom::bindings::num::Finite;
114use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
115use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
116use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
117use crate::dom::bindings::str::{DOMString, USVString};
118use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
119#[cfg(feature = "webgpu")]
120use crate::dom::bindings::weakref::WeakRef;
121use crate::dom::bindings::xmlname::matches_name_production;
122use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
123use crate::dom::cdatasection::CDATASection;
124use crate::dom::comment::Comment;
125use crate::dom::compositionevent::CompositionEvent;
126use crate::dom::cssstylesheet::CSSStyleSheet;
127use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack};
128use crate::dom::customevent::CustomEvent;
129use crate::dom::document_event_handler::DocumentEventHandler;
130use crate::dom::documentfragment::DocumentFragment;
131use crate::dom::documentorshadowroot::{
132 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
133};
134use crate::dom::documenttype::DocumentType;
135use crate::dom::domimplementation::DOMImplementation;
136use crate::dom::element::{
137 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
138 ElementPerformFullscreenExit,
139};
140use crate::dom::event::{Event, EventBubbles, EventCancelable};
141use crate::dom::eventtarget::EventTarget;
142use crate::dom::focusevent::FocusEvent;
143use crate::dom::fontfaceset::FontFaceSet;
144use crate::dom::globalscope::GlobalScope;
145use crate::dom::hashchangeevent::HashChangeEvent;
146use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
147use crate::dom::html::htmlareaelement::HTMLAreaElement;
148use crate::dom::html::htmlbaseelement::HTMLBaseElement;
149use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
150use crate::dom::html::htmlelement::HTMLElement;
151use crate::dom::html::htmlembedelement::HTMLEmbedElement;
152use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
153use crate::dom::html::htmlheadelement::HTMLHeadElement;
154use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
155use crate::dom::html::htmliframeelement::HTMLIFrameElement;
156use crate::dom::html::htmlimageelement::HTMLImageElement;
157use crate::dom::html::htmlinputelement::HTMLInputElement;
158use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
159use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
160use crate::dom::html::htmltitleelement::HTMLTitleElement;
161use crate::dom::intersectionobserver::IntersectionObserver;
162use crate::dom::keyboardevent::KeyboardEvent;
163use crate::dom::location::{Location, NavigationType};
164use crate::dom::messageevent::MessageEvent;
165use crate::dom::mouseevent::MouseEvent;
166use crate::dom::node::{
167 CloneChildrenFlag, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding,
168};
169use crate::dom::nodeiterator::NodeIterator;
170use crate::dom::nodelist::NodeList;
171use crate::dom::pagetransitionevent::PageTransitionEvent;
172use crate::dom::performanceentry::PerformanceEntry;
173use crate::dom::performancepainttiming::PerformancePaintTiming;
174use crate::dom::processinginstruction::ProcessingInstruction;
175use crate::dom::promise::Promise;
176use crate::dom::range::Range;
177use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
178use crate::dom::selection::Selection;
179use crate::dom::servoparser::ServoParser;
180use crate::dom::shadowroot::ShadowRoot;
181use crate::dom::storageevent::StorageEvent;
182use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
183use crate::dom::text::Text;
184use crate::dom::touchevent::TouchEvent as DomTouchEvent;
185use crate::dom::touchlist::TouchList;
186use crate::dom::treewalker::TreeWalker;
187use crate::dom::trustedhtml::TrustedHTML;
188use crate::dom::types::VisibilityStateEntry;
189use crate::dom::uievent::UIEvent;
190use crate::dom::virtualmethods::vtable_for;
191use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
192#[cfg(feature = "webgpu")]
193use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext;
194use crate::dom::window::Window;
195use crate::dom::windowproxy::WindowProxy;
196use crate::dom::xpathevaluator::XPathEvaluator;
197use crate::fetch::FetchCanceller;
198use crate::iframe_collection::IFrameCollection;
199use crate::image_animation::ImageAnimationManager;
200use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
201use crate::mime::{APPLICATION, CHARSET};
202use crate::network_listener::{NetworkListener, PreInvoke};
203use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
204use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
205use crate::script_thread::ScriptThread;
206use crate::stylesheet_set::StylesheetSetRef;
207use crate::task::NonSendTaskBox;
208use crate::task_source::TaskSourceName;
209use crate::timers::OneshotTimerCallback;
210
211pub(crate) enum TouchEventResult {
212 Processed(bool),
213 Forwarded,
214}
215
216#[derive(Clone, Copy, PartialEq)]
217pub(crate) enum FireMouseEventType {
218 Move,
219 Over,
220 Out,
221 Enter,
222 Leave,
223}
224
225impl FireMouseEventType {
226 pub(crate) fn as_str(&self) -> &str {
227 match *self {
228 FireMouseEventType::Move => "mousemove",
229 FireMouseEventType::Over => "mouseover",
230 FireMouseEventType::Out => "mouseout",
231 FireMouseEventType::Enter => "mouseenter",
232 FireMouseEventType::Leave => "mouseleave",
233 }
234 }
235}
236
237#[derive(JSTraceable, MallocSizeOf)]
238pub(crate) struct RefreshRedirectDue {
239 #[no_trace]
240 pub(crate) url: ServoUrl,
241 #[ignore_malloc_size_of = "non-owning"]
242 pub(crate) window: DomRoot<Window>,
243}
244impl RefreshRedirectDue {
245 pub(crate) fn invoke(self, can_gc: CanGc) {
246 self.window.Location().navigate(
247 self.url.clone(),
248 NavigationHistoryBehavior::Replace,
249 NavigationType::DeclarativeRefresh,
250 can_gc,
251 );
252 }
253}
254
255#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
256pub(crate) enum IsHTMLDocument {
257 HTMLDocument,
258 NonHTMLDocument,
259}
260
261#[derive(JSTraceable, MallocSizeOf)]
262#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
263struct FocusTransaction {
264 element: Option<Dom<Element>>,
266 has_focus: bool,
268 focus_options: FocusOptions,
270}
271
272#[derive(JSTraceable, MallocSizeOf)]
274pub(crate) enum DeclarativeRefresh {
275 PendingLoad {
276 #[no_trace]
277 url: ServoUrl,
278 time: u64,
279 },
280 CreatedAfterLoad,
281}
282#[cfg(feature = "webgpu")]
283pub(crate) type WebGPUContextsMap =
284 Rc<RefCell<HashMapTracedValues<WebGPUContextId, WeakRef<GPUCanvasContext>>>>;
285
286#[dom_struct]
288pub(crate) struct Document {
289 node: Node,
290 document_or_shadow_root: DocumentOrShadowRoot,
291 window: Dom<Window>,
292 implementation: MutNullableDom<DOMImplementation>,
293 #[ignore_malloc_size_of = "type from external crate"]
294 #[no_trace]
295 content_type: Mime,
296 last_modified: Option<String>,
297 #[no_trace]
298 encoding: Cell<&'static Encoding>,
299 has_browsing_context: bool,
300 is_html_document: bool,
301 #[no_trace]
302 activity: Cell<DocumentActivity>,
303 #[no_trace]
304 url: DomRefCell<ServoUrl>,
305 #[ignore_malloc_size_of = "defined in selectors"]
306 #[no_trace]
307 quirks_mode: Cell<QuirksMode>,
308 event_handler: DocumentEventHandler,
310 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>>>,
312 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>>>,
313 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>>>,
314 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>>>,
315 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
316 images: MutNullableDom<HTMLCollection>,
317 embeds: MutNullableDom<HTMLCollection>,
318 links: MutNullableDom<HTMLCollection>,
319 forms: MutNullableDom<HTMLCollection>,
320 scripts: MutNullableDom<HTMLCollection>,
321 anchors: MutNullableDom<HTMLCollection>,
322 applets: MutNullableDom<HTMLCollection>,
323 iframes: RefCell<IFrameCollection>,
325 #[no_trace]
328 style_shared_lock: StyleSharedRwLock,
329 #[custom_trace]
331 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
332 stylesheet_list: MutNullableDom<StyleSheetList>,
333 ready_state: Cell<DocumentReadyState>,
334 domcontentloaded_dispatched: Cell<bool>,
336 focus_transaction: DomRefCell<Option<FocusTransaction>>,
338 focused: MutNullableDom<Element>,
340 #[no_trace]
342 focus_sequence: Cell<FocusSequenceNumber>,
343 has_focus: Cell<bool>,
347 current_script: MutNullableDom<HTMLScriptElement>,
349 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
351 script_blocking_stylesheets_count: Cell<u32>,
353 deferred_scripts: PendingInOrderScriptVec,
355 asap_in_order_scripts_list: PendingInOrderScriptVec,
357 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
359 scripting_enabled: bool,
362 animation_frame_ident: Cell<u32>,
365 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
368 running_animation_callbacks: Cell<bool>,
373 loader: DomRefCell<DocumentLoader>,
375 current_parser: MutNullableDom<ServoParser>,
377 base_element: MutNullableDom<HTMLBaseElement>,
379 appropriate_template_contents_owner_document: MutNullableDom<Document>,
382 pending_restyles: DomRefCell<FnvHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
385 #[no_trace]
389 needs_restyle: Cell<RestyleReason>,
390 #[no_trace]
393 dom_interactive: Cell<Option<CrossProcessInstant>>,
394 #[no_trace]
395 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
396 #[no_trace]
397 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
398 #[no_trace]
399 dom_complete: Cell<Option<CrossProcessInstant>>,
400 #[no_trace]
401 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
402 #[no_trace]
403 load_event_start: Cell<Option<CrossProcessInstant>>,
404 #[no_trace]
405 load_event_end: Cell<Option<CrossProcessInstant>>,
406 #[no_trace]
407 unload_event_start: Cell<Option<CrossProcessInstant>>,
408 #[no_trace]
409 unload_event_end: Cell<Option<CrossProcessInstant>>,
410 #[no_trace]
412 https_state: Cell<HttpsState>,
413 #[no_trace]
415 origin: MutableOrigin,
416 referrer: Option<String>,
418 target_element: MutNullableDom<Element>,
420 #[no_trace]
422 policy_container: DomRefCell<PolicyContainer>,
423 ignore_destructive_writes_counter: Cell<u32>,
425 ignore_opens_during_unload_counter: Cell<u32>,
427 spurious_animation_frames: Cell<u8>,
431
432 dom_count: Cell<u32>,
438 fullscreen_element: MutNullableDom<Element>,
440 form_id_listener_map: DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>>>,
446 #[no_trace]
447 interactive_time: DomRefCell<ProgressiveWebMetrics>,
448 #[no_trace]
449 tti_window: DomRefCell<InteractiveWindow>,
450 canceller: FetchCanceller,
452 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
454 page_showing: Cell<bool>,
456 salvageable: Cell<bool>,
458 active_parser_was_aborted: Cell<bool>,
460 fired_unload: Cell<bool>,
462 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
464 redirect_count: Cell<u16>,
466 script_and_layout_blockers: Cell<u32>,
468 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
470 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
471 completely_loaded: Cell<bool>,
473 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
475 shadow_roots_styles_changed: Cell<bool>,
477 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
483 dirty_2d_contexts: DomRefCell<HashMapTracedValues<CanvasId, Dom<CanvasRenderingContext2D>>>,
485 dirty_webgl_contexts:
487 DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>,
488 has_pending_animated_image_update: Cell<bool>,
490 #[cfg(feature = "webgpu")]
492 #[ignore_malloc_size_of = "Rc are hard"]
493 webgpu_contexts: WebGPUContextsMap,
494 selection: MutNullableDom<Selection>,
496 animation_timeline: DomRefCell<AnimationTimeline>,
499 animations: DomRefCell<Animations>,
501 image_animation_manager: DomRefCell<ImageAnimationManager>,
503 dirty_root: MutNullableDom<Element>,
505 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
507 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
516 fonts: MutNullableDom<FontFaceSet>,
519 visibility_state: Cell<DocumentVisibilityState>,
521 status_code: Option<u16>,
523 is_initial_about_blank: Cell<bool>,
525 allow_declarative_shadow_roots: Cell<bool>,
527 #[no_trace]
529 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
530 has_trustworthy_ancestor_origin: Cell<bool>,
532 intersection_observer_task_queued: Cell<bool>,
534 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
546 highlighted_dom_node: MutNullableDom<Node>,
548 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
551 #[ignore_malloc_size_of = "mozjs"]
553 adopted_stylesheets_frozen_types: CachedFrozenArray,
554 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
556 resize_observer_started_observing_target: Cell<bool>,
559 waiting_on_canvas_image_updates: Cell<bool>,
563 #[no_trace]
567 current_canvas_epoch: RefCell<Epoch>,
568
569 #[conditional_malloc_size_of]
571 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
572}
573
574#[allow(non_snake_case)]
575impl Document {
576 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
577 debug_assert!(*node.owner_doc() == *self);
578 if !node.is_connected() {
579 return;
580 }
581
582 let parent = match node.parent_in_flat_tree() {
583 Some(parent) => parent,
584 None => {
585 let document_element = match self.GetDocumentElement() {
588 Some(element) => element,
589 None => return,
590 };
591 if let Some(dirty_root) = self.dirty_root.get() {
592 for ancestor in dirty_root
595 .upcast::<Node>()
596 .inclusive_ancestors_in_flat_tree()
597 {
598 if ancestor.is::<Element>() {
599 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
600 }
601 }
602 }
603 self.dirty_root.set(Some(&document_element));
604 return;
605 },
606 };
607
608 if parent.is::<Element>() {
609 if !parent.is_styled() {
610 return;
611 }
612
613 if parent.is_display_none() {
614 return;
615 }
616 }
617
618 let element_parent: DomRoot<Element>;
619 let element = match node.downcast::<Element>() {
620 Some(element) => element,
621 None => {
622 match DomRoot::downcast::<Element>(parent) {
625 Some(parent) => {
626 element_parent = parent;
627 &element_parent
628 },
629 None => {
630 return;
634 },
635 }
636 },
637 };
638
639 let dirty_root = match self.dirty_root.get() {
640 None => {
641 element
642 .upcast::<Node>()
643 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
644 self.dirty_root.set(Some(element));
645 return;
646 },
647 Some(root) => root,
648 };
649
650 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
651 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
652 return;
653 }
654
655 if ancestor.is::<Element>() {
656 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
657 }
658 }
659
660 let new_dirty_root = element
661 .upcast::<Node>()
662 .common_ancestor_in_flat_tree(dirty_root.upcast())
663 .expect("Couldn't find common ancestor");
664
665 let mut has_dirty_descendants = true;
666 for ancestor in dirty_root
667 .upcast::<Node>()
668 .inclusive_ancestors_in_flat_tree()
669 {
670 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
671 has_dirty_descendants &= *ancestor != *new_dirty_root;
672 }
673
674 self.dirty_root
675 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
676 }
677
678 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
679 self.dirty_root.take()
680 }
681
682 #[inline]
683 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
684 self.loader.borrow()
685 }
686
687 #[inline]
688 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
689 self.loader.borrow_mut()
690 }
691
692 #[inline]
693 pub(crate) fn has_browsing_context(&self) -> bool {
694 self.has_browsing_context
695 }
696
697 #[inline]
699 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
700 if self.has_browsing_context {
701 self.window.undiscarded_window_proxy()
702 } else {
703 None
704 }
705 }
706
707 pub(crate) fn webview_id(&self) -> WebViewId {
708 self.window.webview_id()
709 }
710
711 #[inline]
712 pub(crate) fn window(&self) -> &Window {
713 &self.window
714 }
715
716 #[inline]
717 pub(crate) fn is_html_document(&self) -> bool {
718 self.is_html_document
719 }
720
721 pub(crate) fn is_xhtml_document(&self) -> bool {
722 self.content_type.matches(APPLICATION, "xhtml+xml")
723 }
724
725 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
726 self.https_state.set(https_state);
727 }
728
729 pub(crate) fn is_fully_active(&self) -> bool {
730 self.activity.get() == DocumentActivity::FullyActive
731 }
732
733 pub(crate) fn is_active(&self) -> bool {
734 self.activity.get() != DocumentActivity::Inactive
735 }
736
737 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
738 assert!(self.has_browsing_context);
740 if activity == self.activity.get() {
741 return;
742 }
743
744 self.activity.set(activity);
746 let media = ServoMedia::get();
747 let pipeline_id = self.window().pipeline_id();
748 let client_context_id =
749 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
750
751 if activity != DocumentActivity::FullyActive {
752 self.window().suspend(can_gc);
753 media.suspend(&client_context_id);
754 return;
755 }
756
757 self.title_changed();
758 self.dirty_all_nodes();
759 self.window().resume(can_gc);
760 media.resume(&client_context_id);
761
762 if self.ready_state.get() != DocumentReadyState::Complete {
763 return;
764 }
765
766 let document = Trusted::new(self);
770 self.owner_global()
771 .task_manager()
772 .dom_manipulation_task_source()
773 .queue(task!(fire_pageshow_event: move || {
774 let document = document.root();
775 let window = document.window();
776 if document.page_showing.get() {
778 return;
779 }
780 document.page_showing.set(true);
782 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
784 let event = PageTransitionEvent::new(
787 window,
788 atom!("pageshow"),
789 false, false, true, CanGc::note(),
793 );
794 let event = event.upcast::<Event>();
795 event.set_trusted(true);
796 window.dispatch_event_with_target_override(event, CanGc::note());
797 }))
798 }
799
800 pub(crate) fn origin(&self) -> &MutableOrigin {
801 &self.origin
802 }
803
804 pub(crate) fn url(&self) -> ServoUrl {
806 self.url.borrow().clone()
807 }
808
809 pub(crate) fn set_url(&self, url: ServoUrl) {
810 *self.url.borrow_mut() = url;
811 }
812
813 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
815 let document_url = self.url();
816 if let Some(browsing_context) = self.browsing_context() {
817 let container_base_url = browsing_context
820 .parent()
821 .and_then(|parent| parent.document())
822 .map(|document| document.base_url());
823 if document_url.as_str() == "about:srcdoc" {
824 if let Some(base_url) = container_base_url {
825 return base_url;
826 }
827 }
828 if document_url.as_str() == "about:blank" && browsing_context.has_creator_base_url() {
831 return browsing_context.creator_base_url().unwrap();
832 }
833 }
834 document_url
836 }
837
838 pub(crate) fn base_url(&self) -> ServoUrl {
840 match self.base_element() {
841 None => self.fallback_base_url(),
843 Some(base) => base.frozen_base_url(),
845 }
846 }
847
848 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
849 self.needs_restyle.set(self.needs_restyle.get() | reason)
850 }
851
852 pub(crate) fn clear_restyle_reasons(&self) {
853 self.needs_restyle.set(RestyleReason::empty());
854 }
855
856 pub(crate) fn restyle_reason(&self) -> RestyleReason {
857 let mut condition = self.needs_restyle.get();
858 if self.stylesheets.borrow().has_changed() {
859 condition.insert(RestyleReason::StylesheetsChanged);
860 }
861
862 if let Some(root) = self.GetDocumentElement() {
866 if root.upcast::<Node>().has_dirty_descendants() {
867 condition.insert(RestyleReason::DOMChanged);
868 }
869 }
870
871 if !self.pending_restyles.borrow().is_empty() {
872 condition.insert(RestyleReason::PendingRestyles);
873 }
874
875 condition
876 }
877
878 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
880 self.base_element.get()
881 }
882
883 pub(crate) fn refresh_base_element(&self) {
886 let base = self
887 .upcast::<Node>()
888 .traverse_preorder(ShadowIncluding::No)
889 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
890 .find(|element| {
891 element
892 .upcast::<Element>()
893 .has_attribute(&local_name!("href"))
894 });
895 self.base_element.set(base.as_deref());
896 }
897
898 pub(crate) fn dom_count(&self) -> u32 {
899 self.dom_count.get()
900 }
901
902 pub(crate) fn increment_dom_count(&self) {
906 self.dom_count.set(self.dom_count.get() + 1);
907 }
908
909 pub(crate) fn decrement_dom_count(&self) {
911 self.dom_count.set(self.dom_count.get() - 1);
912 }
913
914 pub(crate) fn quirks_mode(&self) -> QuirksMode {
915 self.quirks_mode.get()
916 }
917
918 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
919 let old_mode = self.quirks_mode.replace(new_mode);
920
921 if old_mode != new_mode {
922 self.window.layout_mut().set_quirks_mode(new_mode);
923 }
924 }
925
926 pub(crate) fn encoding(&self) -> &'static Encoding {
927 self.encoding.get()
928 }
929
930 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
931 self.encoding.set(encoding);
932 }
933
934 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
935 if node.is_connected() {
936 node.note_dirty_descendants();
937 }
938
939 node.dirty(NodeDamage::ContentOrHeritage);
942 }
943
944 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
946 self.document_or_shadow_root
947 .unregister_named_element(&self.id_map, to_unregister, &id);
948 self.reset_form_owner_for_listeners(&id, can_gc);
949 }
950
951 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
953 let root = self.GetDocumentElement().expect(
954 "The element is in the document, so there must be a document \
955 element.",
956 );
957 self.document_or_shadow_root.register_named_element(
958 &self.id_map,
959 element,
960 &id,
961 DomRoot::from_ref(root.upcast::<Node>()),
962 );
963 self.reset_form_owner_for_listeners(&id, can_gc);
964 }
965
966 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
968 self.document_or_shadow_root
969 .unregister_named_element(&self.name_map, to_unregister, &name);
970 }
971
972 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
974 let root = self.GetDocumentElement().expect(
975 "The element is in the document, so there must be a document \
976 element.",
977 );
978 self.document_or_shadow_root.register_named_element(
979 &self.name_map,
980 element,
981 &name,
982 DomRoot::from_ref(root.upcast::<Node>()),
983 );
984 }
985
986 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
987 &self,
988 id: DOMString,
989 listener: &T,
990 ) {
991 let mut map = self.form_id_listener_map.borrow_mut();
992 let listener = listener.to_element();
993 let set = map.entry(Atom::from(id)).or_default();
994 set.insert(Dom::from_ref(listener));
995 }
996
997 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
998 &self,
999 id: DOMString,
1000 listener: &T,
1001 ) {
1002 let mut map = self.form_id_listener_map.borrow_mut();
1003 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1004 entry
1005 .get_mut()
1006 .remove(&Dom::from_ref(listener.to_element()));
1007 if entry.get().is_empty() {
1008 entry.remove();
1009 }
1010 }
1011 }
1012
1013 pub(crate) fn find_fragment_node(&self, fragid: &str) -> Option<DomRoot<Element>> {
1016 percent_decode(fragid.as_bytes())
1020 .decode_utf8()
1021 .ok()
1022 .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
1024 .or_else(|| self.get_anchor_by_name(fragid))
1026 }
1028
1029 pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) {
1033 let target = self.find_fragment_node(fragment);
1034
1035 self.set_target_element(target.as_deref());
1037
1038 let point = target
1039 .as_ref()
1040 .map(|element| {
1041 let rect = element.upcast::<Node>().border_box().unwrap_or_default();
1046
1047 let device_pixel_ratio = self.window.device_pixel_ratio().get();
1052 (
1053 rect.origin.x.to_nearest_pixel(device_pixel_ratio),
1054 rect.origin.y.to_nearest_pixel(device_pixel_ratio),
1055 )
1056 })
1057 .or_else(|| {
1058 if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
1059 Some((0.0, 0.0))
1062 } else {
1063 None
1064 }
1065 });
1066
1067 if let Some((x, y)) = point {
1068 self.window.scroll(x, y, ScrollBehavior::Instant)
1069 }
1070 }
1071
1072 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1073 let name = Atom::from(name);
1074 self.name_map.borrow().get(&name).and_then(|elements| {
1075 elements
1076 .iter()
1077 .find(|e| e.is::<HTMLAnchorElement>())
1078 .map(|e| DomRoot::from_ref(&**e))
1079 })
1080 }
1081
1082 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1084 match state {
1085 DocumentReadyState::Loading => {
1086 if self.window().is_top_level() {
1087 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1088 self.webview_id(),
1089 LoadStatus::Started,
1090 ));
1091 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1092 }
1093 },
1094 DocumentReadyState::Complete => {
1095 if self.window().is_top_level() {
1096 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1097 self.webview_id(),
1098 LoadStatus::Complete,
1099 ));
1100 }
1101 update_with_current_instant(&self.dom_complete);
1102 },
1103 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1104 };
1105
1106 self.ready_state.set(state);
1107
1108 self.upcast::<EventTarget>()
1109 .fire_event(atom!("readystatechange"), can_gc);
1110 }
1111
1112 pub(crate) fn is_scripting_enabled(&self) -> bool {
1114 self.scripting_enabled
1115 }
1116
1117 pub(crate) fn scripting_enabled(&self) -> bool {
1120 self.has_browsing_context()
1121 }
1122
1123 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1126 self.focused.get()
1127 }
1128
1129 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1134 self.focus_sequence.get()
1135 }
1136
1137 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1139 self.focus_sequence.set(FocusSequenceNumber(
1140 self.focus_sequence
1141 .get()
1142 .0
1143 .checked_add(1)
1144 .expect("too many focus messages have been sent"),
1145 ));
1146 self.focus_sequence.get()
1147 }
1148
1149 pub(crate) fn has_focus_transaction(&self) -> bool {
1150 self.focus_transaction.borrow().is_some()
1151 }
1152
1153 pub(crate) fn begin_focus_transaction(&self) {
1156 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1158 element: self.focused.get().as_deref().map(Dom::from_ref),
1159 has_focus: self.has_focus.get(),
1160 focus_options: FocusOptions::default(),
1161 });
1162 }
1163
1164 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1166 if Some(not_focusable) != self.focused.get().as_deref() {
1169 return;
1170 }
1171
1172 let implicit_transaction = self.focus_transaction.borrow().is_none();
1173
1174 if implicit_transaction {
1175 self.begin_focus_transaction();
1176 }
1177
1178 {
1181 let mut focus_transaction = self.focus_transaction.borrow_mut();
1182 focus_transaction.as_mut().unwrap().element = None;
1183 }
1184
1185 if implicit_transaction {
1186 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1187 }
1188 }
1189
1190 pub(crate) fn request_focus(
1193 &self,
1194 elem: Option<&Element>,
1195 focus_initiator: FocusInitiator,
1196 can_gc: CanGc,
1197 ) {
1198 self.request_focus_with_options(elem, focus_initiator, FocusOptions::default(), can_gc);
1199 }
1200
1201 pub(crate) fn request_focus_with_options(
1207 &self,
1208 elem: Option<&Element>,
1209 focus_initiator: FocusInitiator,
1210 focus_options: FocusOptions,
1211 can_gc: CanGc,
1212 ) {
1213 if elem.is_some_and(|e| !e.is_focusable_area()) {
1216 return;
1217 }
1218
1219 let implicit_transaction = self.focus_transaction.borrow().is_none();
1220
1221 if implicit_transaction {
1222 self.begin_focus_transaction();
1223 }
1224
1225 {
1226 let mut focus_transaction = self.focus_transaction.borrow_mut();
1227 let focus_transaction = focus_transaction.as_mut().unwrap();
1228 focus_transaction.element = elem.map(Dom::from_ref);
1229 focus_transaction.has_focus = true;
1230 focus_transaction.focus_options = focus_options;
1231 }
1232
1233 if implicit_transaction {
1234 self.commit_focus_transaction(focus_initiator, can_gc);
1235 }
1236 }
1237
1238 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1242 if self.window().parent_info().is_none() {
1243 warn!("Top-level document cannot be unfocused");
1244 return;
1245 }
1246
1247 assert!(
1250 self.focus_transaction.borrow().is_none(),
1251 "there mustn't be an in-progress focus transaction at this point"
1252 );
1253
1254 self.begin_focus_transaction();
1256
1257 {
1259 let mut focus_transaction = self.focus_transaction.borrow_mut();
1260 focus_transaction.as_mut().unwrap().has_focus = false;
1261 }
1262
1263 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1265 }
1266
1267 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1270 let (mut new_focused, new_focus_state, prevent_scroll) = {
1271 let focus_transaction = self.focus_transaction.borrow();
1272 let focus_transaction = focus_transaction
1273 .as_ref()
1274 .expect("no focus transaction in progress");
1275 (
1276 focus_transaction
1277 .element
1278 .as_ref()
1279 .map(|e| DomRoot::from_ref(&**e)),
1280 focus_transaction.has_focus,
1281 focus_transaction.focus_options.preventScroll,
1282 )
1283 };
1284 *self.focus_transaction.borrow_mut() = None;
1285
1286 if !new_focus_state {
1287 if new_focused.take().is_some() {
1290 trace!(
1291 "Forgetting the document's focused area because the \
1292 document's container was removed from the top-level BC's \
1293 focus chain"
1294 );
1295 }
1296 }
1297
1298 let old_focused = self.focused.get();
1299 let old_focus_state = self.has_focus.get();
1300
1301 debug!(
1302 "Committing focus transaction: {:?} → {:?}",
1303 (&old_focused, old_focus_state),
1304 (&new_focused, new_focus_state),
1305 );
1306
1307 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1310 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1311
1312 let trace_focus_chain = |name, element, doc| {
1313 trace!(
1314 "{} local focus chain: {}",
1315 name,
1316 match (element, doc) {
1317 (Some(e), _) => format!("[{:?}, document]", e),
1318 (None, true) => "[document]".to_owned(),
1319 (None, false) => "[]".to_owned(),
1320 }
1321 );
1322 };
1323
1324 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1325 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1326
1327 if old_focused_filtered != new_focused_filtered {
1328 if let Some(elem) = &old_focused_filtered {
1329 let node = elem.upcast::<Node>();
1330 elem.set_focus_state(false);
1331 if node.is_connected() {
1333 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1334 }
1335
1336 if elem.input_method_type().is_some() {
1338 self.send_to_embedder(EmbedderMsg::HideIME(self.webview_id()));
1339 }
1340 }
1341 }
1342
1343 if old_focus_state != new_focus_state && !new_focus_state {
1344 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1345 }
1346
1347 self.focused.set(new_focused.as_deref());
1348 self.has_focus.set(new_focus_state);
1349
1350 if old_focus_state != new_focus_state && new_focus_state {
1351 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1352 }
1353
1354 if old_focused_filtered != new_focused_filtered {
1355 if let Some(elem) = &new_focused_filtered {
1356 elem.set_focus_state(true);
1357 let node = elem.upcast::<Node>();
1358 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1360
1361 if let Some(kind) = elem.input_method_type() {
1363 let rect = elem.upcast::<Node>().border_box().unwrap_or_default();
1364 let rect = Rect::new(
1365 Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()),
1366 Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()),
1367 );
1368 let (text, multiline) = if let Some(input) = elem.downcast::<HTMLInputElement>()
1369 {
1370 (
1371 Some((
1372 (input.Value()).to_string(),
1373 input.GetSelectionEnd().unwrap_or(0) as i32,
1374 )),
1375 false,
1376 )
1377 } else if let Some(textarea) = elem.downcast::<HTMLTextAreaElement>() {
1378 (
1379 Some((
1380 (textarea.Value()).to_string(),
1381 textarea.GetSelectionEnd().unwrap_or(0) as i32,
1382 )),
1383 true,
1384 )
1385 } else {
1386 (None, false)
1387 };
1388 self.send_to_embedder(EmbedderMsg::ShowIME(
1389 self.webview_id(),
1390 kind,
1391 text,
1392 multiline,
1393 DeviceIntRect::from_untyped(&rect.to_box2d()),
1394 ));
1395 }
1396 if !prevent_scroll {
1400 elem.ScrollIntoView(BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(
1401 ScrollIntoViewOptions {
1402 parent: ScrollOptions {
1403 behavior: ScrollBehavior::Smooth,
1404 },
1405 block: ScrollLogicalPosition::Center,
1406 inline: ScrollLogicalPosition::Center,
1407 container: ScrollIntoViewContainer::All,
1408 },
1409 ));
1410 }
1411 }
1412 }
1413
1414 if focus_initiator != FocusInitiator::Local {
1415 return;
1416 }
1417
1418 match (old_focus_state, new_focus_state) {
1421 (_, true) => {
1422 let child_browsing_context_id = new_focused
1443 .as_ref()
1444 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1445 .and_then(|iframe| iframe.browsing_context_id());
1446
1447 let sequence = self.increment_fetch_focus_sequence();
1448
1449 debug!(
1450 "Advertising the focus request to the constellation \
1451 with sequence number {} and child BC ID {}",
1452 sequence,
1453 child_browsing_context_id
1454 .as_ref()
1455 .map(|id| id as &dyn std::fmt::Display)
1456 .unwrap_or(&"(none)"),
1457 );
1458
1459 self.window()
1460 .send_to_constellation(ScriptToConstellationMessage::Focus(
1461 child_browsing_context_id,
1462 sequence,
1463 ));
1464 },
1465 (false, false) => {
1466 },
1469 (true, false) => {
1470 unreachable!(
1471 "Can't lose the document's focus without specifying \
1472 another one to focus"
1473 );
1474 },
1475 }
1476 }
1477
1478 pub(crate) fn title_changed(&self) {
1480 if self.browsing_context().is_some() {
1481 self.send_title_to_embedder();
1482 let title = String::from(self.Title());
1483 self.window
1484 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1485 self.window.pipeline_id(),
1486 title.clone(),
1487 ));
1488 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1489 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1490 self.window.pipeline_id(),
1491 title,
1492 ));
1493 }
1494 }
1495 }
1496
1497 fn title(&self) -> Option<DOMString> {
1501 let title = self.GetDocumentElement().and_then(|root| {
1502 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1503 root.upcast::<Node>()
1505 .child_elements()
1506 .find(|node| {
1507 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1508 })
1509 .map(DomRoot::upcast::<Node>)
1510 } else {
1511 root.upcast::<Node>()
1513 .traverse_preorder(ShadowIncluding::No)
1514 .find(|node| node.is::<HTMLTitleElement>())
1515 }
1516 });
1517
1518 title.map(|title| {
1519 let value = title.child_text_content();
1521 DOMString::from(str_join(split_html_space_chars(&value), " "))
1522 })
1523 }
1524
1525 pub(crate) fn send_title_to_embedder(&self) {
1527 let window = self.window();
1528 if window.is_top_level() {
1529 let title = self.title().map(String::from);
1530 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1531 }
1532 }
1533
1534 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1535 let window = self.window();
1536 window.send_to_embedder(msg);
1537 }
1538
1539 pub(crate) fn dirty_all_nodes(&self) {
1540 let root = match self.GetDocumentElement() {
1541 Some(root) => root,
1542 None => return,
1543 };
1544 for node in root
1545 .upcast::<Node>()
1546 .traverse_preorder(ShadowIncluding::Yes)
1547 {
1548 node.dirty(NodeDamage::Other)
1549 }
1550 }
1551
1552 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1554 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1566 for target in notify_list.iter() {
1567 if target.downcast::<Document>().is_some() {
1568 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1571 } else if target.downcast::<Element>().is_some() {
1572 target.fire_event(Atom::from("scroll"), can_gc);
1575 }
1576 }
1577
1578 }
1582
1583 pub(crate) fn handle_viewport_scroll_event(&self) {
1587 let target = self.upcast::<EventTarget>();
1596 if self
1597 .pending_scroll_event_targets
1598 .borrow()
1599 .iter()
1600 .any(|other_target| *other_target == target)
1601 {
1602 return;
1603 }
1604
1605 self.pending_scroll_event_targets
1608 .borrow_mut()
1609 .push(Dom::from_ref(target));
1610 }
1611
1612 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1616 let target = element.upcast::<EventTarget>();
1626 if self
1627 .pending_scroll_event_targets
1628 .borrow()
1629 .iter()
1630 .any(|other_target| *other_target == target)
1631 {
1632 return;
1633 }
1634
1635 self.pending_scroll_event_targets
1638 .borrow_mut()
1639 .push(Dom::from_ref(target));
1640 }
1641
1642 pub(crate) fn node_from_nodes_and_strings(
1644 &self,
1645 mut nodes: Vec<NodeOrString>,
1646 can_gc: CanGc,
1647 ) -> Fallible<DomRoot<Node>> {
1648 if nodes.len() == 1 {
1649 Ok(match nodes.pop().unwrap() {
1650 NodeOrString::Node(node) => node,
1651 NodeOrString::String(string) => {
1652 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1653 },
1654 })
1655 } else {
1656 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1657 for node in nodes {
1658 match node {
1659 NodeOrString::Node(node) => {
1660 fragment.AppendChild(&node, can_gc)?;
1661 },
1662 NodeOrString::String(string) => {
1663 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1664 fragment.AppendChild(&node, can_gc).unwrap();
1667 },
1668 }
1669 }
1670 Ok(fragment)
1671 }
1672 }
1673
1674 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1675 match self.GetBody() {
1676 Some(ref body) if body.is_body_element() => {
1677 body.upcast::<Element>().get_string_attribute(local_name)
1678 },
1679 _ => DOMString::new(),
1680 }
1681 }
1682
1683 pub(crate) fn set_body_attribute(
1684 &self,
1685 local_name: &LocalName,
1686 value: DOMString,
1687 can_gc: CanGc,
1688 ) {
1689 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1690 let body = body.upcast::<Element>();
1691 let value = body.parse_attribute(&ns!(), local_name, value);
1692 body.set_attribute(local_name, value, can_gc);
1693 }
1694 }
1695
1696 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1697 self.current_script.set(script);
1698 }
1699
1700 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1701 self.script_blocking_stylesheets_count.get()
1702 }
1703
1704 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1705 let count_cell = &self.script_blocking_stylesheets_count;
1706 count_cell.set(count_cell.get() + 1);
1707 }
1708
1709 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1710 let count_cell = &self.script_blocking_stylesheets_count;
1711 assert!(count_cell.get() > 0);
1712 count_cell.set(count_cell.get() - 1);
1713 }
1714
1715 pub(crate) fn invalidate_stylesheets(&self) {
1716 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1717
1718 if let Some(element) = self.GetDocumentElement() {
1722 element.upcast::<Node>().dirty(NodeDamage::Style);
1723 }
1724 }
1725
1726 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1729 !self.animation_frame_list.borrow().is_empty()
1730 }
1731
1732 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1734 let ident = self.animation_frame_ident.get() + 1;
1735 self.animation_frame_ident.set(ident);
1736
1737 let had_animation_frame_callbacks;
1738 {
1739 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1740 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1741 animation_frame_list.push_back((ident, Some(callback)));
1742 }
1743
1744 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1750 self.window().send_to_constellation(
1751 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1752 AnimationState::AnimationCallbacksPresent,
1753 ),
1754 );
1755 }
1756
1757 ident
1758 }
1759
1760 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1762 let mut list = self.animation_frame_list.borrow_mut();
1763 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1764 pair.1 = None;
1765 }
1766 }
1767
1768 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1770 let _realm = enter_realm(self);
1771
1772 self.running_animation_callbacks.set(true);
1773 let timing = self.global().performance().Now();
1774
1775 let num_callbacks = self.animation_frame_list.borrow().len();
1776 for _ in 0..num_callbacks {
1777 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1778 if let Some(callback) = maybe_callback {
1779 callback.call(self, *timing, can_gc);
1780 }
1781 }
1782 self.running_animation_callbacks.set(false);
1783
1784 if self.animation_frame_list.borrow().is_empty() {
1785 self.window().send_to_constellation(
1786 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1787 AnimationState::NoAnimationCallbacksPresent,
1788 ),
1789 );
1790 }
1791 }
1792
1793 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1794 self.policy_container.borrow()
1795 }
1796
1797 pub(crate) fn prepare_request(&self, request: RequestBuilder) -> RequestBuilder {
1801 request
1802 .policy_container(self.policy_container().to_owned())
1803 .https_state(self.https_state.get())
1804 }
1805
1806 pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1807 &self,
1808 load: LoadType,
1809 mut request: RequestBuilder,
1810 listener: Listener,
1811 ) {
1812 request = request
1813 .insecure_requests_policy(self.insecure_requests_policy())
1814 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1815 let callback = NetworkListener {
1816 context: std::sync::Arc::new(Mutex::new(listener)),
1817 task_source: self
1818 .owner_global()
1819 .task_manager()
1820 .networking_task_source()
1821 .into(),
1822 }
1823 .into_callback();
1824 self.loader_mut()
1825 .fetch_async_with_callback(load, request, callback);
1826 }
1827
1828 pub(crate) fn fetch_background<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
1829 &self,
1830 mut request: RequestBuilder,
1831 listener: Listener,
1832 ) {
1833 request = request
1834 .insecure_requests_policy(self.insecure_requests_policy())
1835 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1836 let callback = NetworkListener {
1837 context: std::sync::Arc::new(Mutex::new(listener)),
1838 task_source: self
1839 .owner_global()
1840 .task_manager()
1841 .networking_task_source()
1842 .into(),
1843 }
1844 .into_callback();
1845 self.loader_mut().fetch_async_background(request, callback);
1846 }
1847
1848 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
1851 debug!("Document got finish_load: {:?}", load);
1853 self.loader.borrow_mut().finish_load(&load);
1854
1855 match load {
1856 LoadType::Stylesheet(_) => {
1857 self.process_pending_parsing_blocking_script(can_gc);
1860
1861 self.process_deferred_scripts(can_gc);
1863 },
1864 LoadType::PageSource(_) => {
1865 if self.has_browsing_context && self.is_fully_active() {
1868 self.window().allow_layout_if_necessary();
1869 }
1870
1871 self.process_deferred_scripts(can_gc);
1876 },
1877 _ => {},
1878 }
1879
1880 let loader = self.loader.borrow();
1887
1888 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1890 update_with_current_instant(&self.top_level_dom_complete);
1891 }
1892
1893 if loader.is_blocked() || loader.events_inhibited() {
1894 return;
1896 }
1897
1898 ScriptThread::mark_document_with_no_blocked_loads(self);
1899 }
1900
1901 pub(crate) fn prompt_to_unload(&self, recursive_flag: bool, can_gc: CanGc) -> bool {
1903 self.incr_ignore_opens_during_unload_counter();
1906 let beforeunload_event = BeforeUnloadEvent::new(
1908 &self.window,
1909 atom!("beforeunload"),
1910 EventBubbles::Bubbles,
1911 EventCancelable::Cancelable,
1912 can_gc,
1913 );
1914 let event = beforeunload_event.upcast::<Event>();
1915 event.set_trusted(true);
1916 let event_target = self.window.upcast::<EventTarget>();
1917 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
1918 self.window
1919 .dispatch_event_with_target_override(event, can_gc);
1920 if has_listeners {
1923 self.salvageable.set(false);
1924 }
1925 let mut can_unload = true;
1926 let default_prevented = event.DefaultPrevented();
1928 let return_value_not_empty = !event
1929 .downcast::<BeforeUnloadEvent>()
1930 .unwrap()
1931 .ReturnValue()
1932 .is_empty();
1933 if default_prevented || return_value_not_empty {
1934 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
1935 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
1936 self.send_to_embedder(msg);
1937 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
1938 }
1939 if !recursive_flag {
1941 let iframes: Vec<_> = self.iframes().iter().collect();
1944 for iframe in &iframes {
1945 let document = iframe.owner_document();
1947 can_unload = document.prompt_to_unload(true, can_gc);
1948 if !document.salvageable() {
1949 self.salvageable.set(false);
1950 }
1951 if !can_unload {
1952 break;
1953 }
1954 }
1955 }
1956 self.decr_ignore_opens_during_unload_counter();
1958 can_unload
1959 }
1960
1961 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
1963 self.incr_ignore_opens_during_unload_counter();
1966 if self.page_showing.get() {
1968 self.page_showing.set(false);
1970 let event = PageTransitionEvent::new(
1973 &self.window,
1974 atom!("pagehide"),
1975 false, false, self.salvageable.get(), can_gc,
1979 );
1980 let event = event.upcast::<Event>();
1981 event.set_trusted(true);
1982 self.window
1983 .dispatch_event_with_target_override(event, can_gc);
1984 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
1986 }
1987 if !self.fired_unload.get() {
1989 let event = Event::new(
1990 self.window.upcast(),
1991 atom!("unload"),
1992 EventBubbles::Bubbles,
1993 EventCancelable::Cancelable,
1994 can_gc,
1995 );
1996 event.set_trusted(true);
1997 let event_target = self.window.upcast::<EventTarget>();
1998 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
1999 self.window
2000 .dispatch_event_with_target_override(&event, can_gc);
2001 self.fired_unload.set(true);
2002 if has_listeners {
2004 self.salvageable.set(false);
2005 }
2006 }
2007 if !recursive_flag {
2011 let iframes: Vec<_> = self.iframes().iter().collect();
2014 for iframe in &iframes {
2015 let document = iframe.owner_document();
2017 document.unload(true, can_gc);
2018 if !document.salvageable() {
2019 self.salvageable.set(false);
2020 }
2021 }
2022 }
2023
2024 let global_scope = self.window.as_global_scope();
2025 if !self.salvageable.get() {
2028 global_scope.close_event_sources();
2030 let msg = ScriptToConstellationMessage::DiscardDocument;
2031 let _ = global_scope.script_to_constellation_chan().send(msg);
2032 }
2033 global_scope.clean_up_all_file_resources();
2035
2036 self.decr_ignore_opens_during_unload_counter();
2038 }
2039
2040 pub(crate) fn maybe_queue_document_completion(&self) {
2042 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2044 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2045 None => false,
2046 };
2047
2048 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2053 !self.is_fully_active() ||
2054 is_in_delaying_load_events_mode;
2055
2056 if not_ready_for_load {
2057 return;
2059 }
2060
2061 assert!(!self.loader.borrow().events_inhibited());
2062 self.loader.borrow_mut().inhibit_events();
2063
2064 debug!("Document loads are complete.");
2067 let document = Trusted::new(self);
2068 self.owner_global()
2069 .task_manager()
2070 .dom_manipulation_task_source()
2071 .queue(task!(fire_load_event: move || {
2072 let document = document.root();
2073 let window = document.window();
2074 if !window.is_alive() {
2075 return;
2076 }
2077
2078 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2080
2081 if document.browsing_context().is_none() {
2083 return;
2084 }
2085 let event = Event::new(
2086 window.upcast(),
2087 atom!("load"),
2088 EventBubbles::DoesNotBubble,
2089 EventCancelable::NotCancelable,
2090 CanGc::note(),
2091 );
2092 event.set_trusted(true);
2093
2094 update_with_current_instant(&document.load_event_start);
2096
2097 debug!("About to dispatch load for {:?}", document.url());
2098 window.dispatch_event_with_target_override(&event, CanGc::note());
2099
2100 update_with_current_instant(&document.load_event_end);
2102
2103 if let Some(fragment) = document.url().fragment() {
2104 document.check_and_scroll_fragment(fragment);
2105 }
2106 }));
2107
2108 let document = Trusted::new(self);
2110 if document.root().browsing_context().is_some() {
2111 self.owner_global()
2112 .task_manager()
2113 .dom_manipulation_task_source()
2114 .queue(task!(fire_pageshow_event: move || {
2115 let document = document.root();
2116 let window = document.window();
2117 if document.page_showing.get() || !window.is_alive() {
2118 return;
2119 }
2120
2121 document.page_showing.set(true);
2122
2123 let event = PageTransitionEvent::new(
2124 window,
2125 atom!("pageshow"),
2126 false, false, false, CanGc::note(),
2130 );
2131 let event = event.upcast::<Event>();
2132 event.set_trusted(true);
2133
2134 window.dispatch_event_with_target_override(event, CanGc::note());
2135 }));
2136 }
2137
2138 #[cfg(feature = "webxr")]
2153 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2154 self.window.Navigator().Xr().dispatch_sessionavailable();
2155 }
2156
2157 let document = Trusted::new(self);
2161 if document.root().browsing_context().is_some() {
2162 self.owner_global()
2163 .task_manager()
2164 .dom_manipulation_task_source()
2165 .queue(task!(completely_loaded: move || {
2166 let document = document.root();
2167 document.completely_loaded.set(true);
2168 if let Some(DeclarativeRefresh::PendingLoad {
2169 url,
2170 time
2171 }) = &*document.declarative_refresh.borrow() {
2172 document.window.as_global_scope().schedule_callback(
2174 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2175 window: DomRoot::from_ref(document.window()),
2176 url: url.clone(),
2177 }),
2178 Duration::from_secs(*time),
2179 );
2180 }
2181 document.notify_constellation_load();
2184 }));
2185 }
2186 }
2187
2188 pub(crate) fn completely_loaded(&self) -> bool {
2189 self.completely_loaded.get()
2190 }
2191
2192 pub(crate) fn set_pending_parsing_blocking_script(
2194 &self,
2195 script: &HTMLScriptElement,
2196 load: Option<ScriptResult>,
2197 ) {
2198 assert!(!self.has_pending_parsing_blocking_script());
2199 *self.pending_parsing_blocking_script.borrow_mut() =
2200 Some(PendingScript::new_with_load(script, load));
2201 }
2202
2203 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2205 self.pending_parsing_blocking_script.borrow().is_some()
2206 }
2207
2208 pub(crate) fn pending_parsing_blocking_script_loaded(
2210 &self,
2211 element: &HTMLScriptElement,
2212 result: ScriptResult,
2213 can_gc: CanGc,
2214 ) {
2215 {
2216 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2217 let entry = blocking_script.as_mut().unwrap();
2218 assert!(&*entry.element == element);
2219 entry.loaded(result);
2220 }
2221 self.process_pending_parsing_blocking_script(can_gc);
2222 }
2223
2224 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2225 if self.script_blocking_stylesheets_count.get() > 0 {
2226 return;
2227 }
2228 let pair = self
2229 .pending_parsing_blocking_script
2230 .borrow_mut()
2231 .as_mut()
2232 .and_then(PendingScript::take_result);
2233 if let Some((element, result)) = pair {
2234 *self.pending_parsing_blocking_script.borrow_mut() = None;
2235 self.get_current_parser()
2236 .unwrap()
2237 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2238 }
2239 }
2240
2241 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2243 self.asap_scripts_set
2244 .borrow_mut()
2245 .push(Dom::from_ref(script));
2246 }
2247
2248 pub(crate) fn asap_script_loaded(
2251 &self,
2252 element: &HTMLScriptElement,
2253 result: ScriptResult,
2254 can_gc: CanGc,
2255 ) {
2256 {
2257 let mut scripts = self.asap_scripts_set.borrow_mut();
2258 let idx = scripts
2259 .iter()
2260 .position(|entry| &**entry == element)
2261 .unwrap();
2262 scripts.swap_remove(idx);
2263 }
2264 element.execute(result, can_gc);
2265 }
2266
2267 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2269 self.asap_in_order_scripts_list.push(script);
2270 }
2271
2272 pub(crate) fn asap_in_order_script_loaded(
2275 &self,
2276 element: &HTMLScriptElement,
2277 result: ScriptResult,
2278 can_gc: CanGc,
2279 ) {
2280 self.asap_in_order_scripts_list.loaded(element, result);
2281 while let Some((element, result)) = self
2282 .asap_in_order_scripts_list
2283 .take_next_ready_to_be_executed()
2284 {
2285 element.execute(result, can_gc);
2286 }
2287 }
2288
2289 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2291 self.deferred_scripts.push(script);
2292 }
2293
2294 pub(crate) fn deferred_script_loaded(
2297 &self,
2298 element: &HTMLScriptElement,
2299 result: ScriptResult,
2300 can_gc: CanGc,
2301 ) {
2302 self.deferred_scripts.loaded(element, result);
2303 self.process_deferred_scripts(can_gc);
2304 }
2305
2306 fn process_deferred_scripts(&self, can_gc: CanGc) {
2308 if self.ready_state.get() != DocumentReadyState::Interactive {
2309 return;
2310 }
2311 loop {
2313 if self.script_blocking_stylesheets_count.get() > 0 {
2314 return;
2315 }
2316 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2317 {
2318 element.execute(result, can_gc);
2319 } else {
2320 break;
2321 }
2322 }
2323 if self.deferred_scripts.is_empty() {
2324 self.maybe_dispatch_dom_content_loaded();
2326 }
2327 }
2328
2329 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2331 if self.domcontentloaded_dispatched.get() {
2332 return;
2333 }
2334 self.domcontentloaded_dispatched.set(true);
2335 assert_ne!(
2336 self.ReadyState(),
2337 DocumentReadyState::Complete,
2338 "Complete before DOMContentLoaded?"
2339 );
2340
2341 update_with_current_instant(&self.dom_content_loaded_event_start);
2342
2343 let document = Trusted::new(self);
2345 self.owner_global()
2346 .task_manager()
2347 .dom_manipulation_task_source()
2348 .queue(
2349 task!(fire_dom_content_loaded_event: move || {
2350 let document = document.root();
2351 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2352 update_with_current_instant(&document.dom_content_loaded_event_end);
2353 })
2354 );
2355
2356 self.interactive_time
2358 .borrow()
2359 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2360
2361 }
2364
2365 pub(crate) fn abort(&self, can_gc: CanGc) {
2367 self.loader.borrow_mut().inhibit_events();
2369
2370 for iframe in self.iframes().iter() {
2372 if let Some(document) = iframe.GetContentDocument() {
2373 document.abort(can_gc);
2375 }
2377 }
2378
2379 self.script_blocking_stylesheets_count.set(0);
2381 *self.pending_parsing_blocking_script.borrow_mut() = None;
2382 *self.asap_scripts_set.borrow_mut() = vec![];
2383 self.asap_in_order_scripts_list.clear();
2384 self.deferred_scripts.clear();
2385 let loads_cancelled = self.loader.borrow_mut().cancel_all_loads();
2386 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2387 if loads_cancelled || event_sources_canceled {
2388 self.salvageable.set(false);
2390 };
2391
2392 self.owner_global()
2397 .task_manager()
2398 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2399
2400 if let Some(parser) = self.get_current_parser() {
2402 self.active_parser_was_aborted.set(true);
2403 parser.abort(can_gc);
2404 self.salvageable.set(false);
2405 }
2406 }
2407
2408 pub(crate) fn notify_constellation_load(&self) {
2409 self.window()
2410 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2411 }
2412
2413 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2414 self.current_parser.set(script);
2415 }
2416
2417 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2418 self.current_parser.get()
2419 }
2420
2421 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2424 self.iframes.borrow_mut().validate(self);
2425 self.iframes.borrow()
2426 }
2427
2428 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2431 self.iframes.borrow_mut().validate(self);
2432 self.iframes.borrow_mut()
2433 }
2434
2435 pub(crate) fn invalidate_iframes_collection(&self) {
2436 self.iframes.borrow_mut().invalidate();
2437 }
2438
2439 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2440 self.dom_interactive.get()
2441 }
2442
2443 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2444 self.interactive_time
2445 .borrow_mut()
2446 .set_navigation_start(navigation_start);
2447 }
2448
2449 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2450 self.interactive_time.borrow()
2451 }
2452
2453 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2454 self.get_interactive_metrics().get_tti().is_some()
2455 }
2456
2457 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2458 self.dom_content_loaded_event_start.get()
2459 }
2460
2461 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2462 self.dom_content_loaded_event_end.get()
2463 }
2464
2465 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2466 self.dom_complete.get()
2467 }
2468
2469 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2470 self.top_level_dom_complete.get()
2471 }
2472
2473 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2474 self.load_event_start.get()
2475 }
2476
2477 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2478 self.load_event_end.get()
2479 }
2480
2481 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2482 self.unload_event_start.get()
2483 }
2484
2485 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2486 self.unload_event_end.get()
2487 }
2488
2489 pub(crate) fn start_tti(&self) {
2490 if self.get_interactive_metrics().needs_tti() {
2491 self.tti_window.borrow_mut().start_window();
2492 }
2493 }
2494
2495 pub(crate) fn record_tti_if_necessary(&self) {
2499 if self.has_recorded_tti_metric() {
2500 return;
2501 }
2502 if self.tti_window.borrow().needs_check() {
2503 self.get_interactive_metrics()
2504 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2505 self.tti_window.borrow().get_start(),
2506 ));
2507 }
2508 }
2509
2510 fn fire_focus_event(
2512 &self,
2513 focus_event_type: FocusEventType,
2514 event_target: &EventTarget,
2515 related_target: Option<&EventTarget>,
2516 can_gc: CanGc,
2517 ) {
2518 let (event_name, does_bubble) = match focus_event_type {
2519 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2520 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2521 };
2522 let event = FocusEvent::new(
2523 &self.window,
2524 event_name,
2525 does_bubble,
2526 EventCancelable::NotCancelable,
2527 Some(&self.window),
2528 0i32,
2529 related_target,
2530 can_gc,
2531 );
2532 let event = event.upcast::<Event>();
2533 event.set_trusted(true);
2534 event.fire(event_target, can_gc);
2535 }
2536
2537 pub(crate) fn is_cookie_averse(&self) -> bool {
2539 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2540 }
2541
2542 pub(crate) fn lookup_custom_element_definition(
2544 &self,
2545 namespace: &Namespace,
2546 local_name: &LocalName,
2547 is: Option<&LocalName>,
2548 ) -> Option<Rc<CustomElementDefinition>> {
2549 if !pref!(dom_customelements_enabled) {
2550 return None;
2551 }
2552
2553 if *namespace != ns!(html) {
2555 return None;
2556 }
2557
2558 if !self.has_browsing_context {
2560 return None;
2561 }
2562
2563 let registry = self.window.CustomElements();
2565
2566 registry.lookup_definition(local_name, is)
2567 }
2568
2569 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2570 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2571 self.throw_on_dynamic_markup_insertion_counter
2572 .set(counter + 1);
2573 }
2574
2575 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2576 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2577 self.throw_on_dynamic_markup_insertion_counter
2578 .set(counter - 1);
2579 }
2580
2581 pub(crate) fn react_to_environment_changes(&self) {
2582 for image in self.responsive_images.borrow().iter() {
2583 image.react_to_environment_changes();
2584 }
2585 }
2586
2587 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2588 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2589 }
2590
2591 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2592 let index = self
2593 .responsive_images
2594 .borrow()
2595 .iter()
2596 .position(|x| **x == *img);
2597 if let Some(i) = index {
2598 self.responsive_images.borrow_mut().remove(i);
2599 }
2600 }
2601
2602 pub(crate) fn register_media_controls(&self, controls: &ShadowRoot) -> String {
2603 let id = Uuid::new_v4().to_string();
2604 self.media_controls
2605 .borrow_mut()
2606 .insert(id.clone(), Dom::from_ref(controls));
2607 id
2608 }
2609
2610 pub(crate) fn unregister_media_controls(&self, id: &str, can_gc: CanGc) {
2611 if let Some(ref media_controls) = self.media_controls.borrow_mut().remove(id) {
2612 let media_controls = DomRoot::from_ref(&**media_controls);
2613 media_controls.Host().detach_shadow(can_gc);
2614 } else {
2615 debug_assert!(false, "Trying to unregister unknown media controls");
2616 }
2617 }
2618
2619 pub(crate) fn add_dirty_webgl_canvas(&self, context: &WebGLRenderingContext) {
2620 self.dirty_webgl_contexts
2621 .borrow_mut()
2622 .entry(context.context_id())
2623 .or_insert_with(|| Dom::from_ref(context));
2624 }
2625
2626 pub(crate) fn add_dirty_2d_canvas(&self, context: &CanvasRenderingContext2D) {
2627 self.dirty_2d_contexts
2628 .borrow_mut()
2629 .entry(context.context_id())
2630 .or_insert_with(|| Dom::from_ref(context));
2631 }
2632
2633 #[cfg(feature = "webgpu")]
2634 pub(crate) fn webgpu_contexts(&self) -> WebGPUContextsMap {
2635 self.webgpu_contexts.clone()
2636 }
2637
2638 pub(crate) fn needs_rendering_update(&self) -> bool {
2642 if !self.is_fully_active() {
2643 return false;
2644 }
2645 if !self.window().layout_blocked() &&
2646 (!self.restyle_reason().is_empty() ||
2647 self.window().layout().needs_new_display_list())
2648 {
2649 return true;
2650 }
2651 if self.resize_observer_started_observing_target.get() {
2652 return true;
2653 }
2654 if self.event_handler.has_pending_input_events() {
2655 return true;
2656 }
2657 if self.has_pending_scroll_events() {
2658 return true;
2659 }
2660 if self.window().has_unhandled_resize_event() {
2661 return true;
2662 }
2663 if self.has_pending_animated_image_update.get() {
2664 return true;
2665 }
2666
2667 false
2668 }
2669
2670 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
2678 if self.has_pending_animated_image_update.get() {
2679 self.image_animation_manager
2680 .borrow()
2681 .update_active_frames(&self.window, self.current_animation_timeline_value());
2682 self.has_pending_animated_image_update.set(false);
2683 }
2684
2685 self.current_canvas_epoch.borrow_mut().next();
2687 let canvas_epoch = *self.current_canvas_epoch.borrow();
2688 let mut image_keys = Vec::new();
2689
2690 #[cfg(feature = "webgpu")]
2691 image_keys.extend(
2692 self.webgpu_contexts
2693 .borrow_mut()
2694 .iter()
2695 .filter_map(|(_, context)| context.root())
2696 .filter(|context| context.update_rendering(canvas_epoch))
2697 .map(|context| context.image_key()),
2698 );
2699
2700 image_keys.extend(
2701 self.dirty_2d_contexts
2702 .borrow_mut()
2703 .drain()
2704 .filter(|(_, context)| context.update_rendering(canvas_epoch))
2705 .map(|(_, context)| context.image_key()),
2706 );
2707
2708 let dirty_webgl_context_ids: Vec<_> = self
2709 .dirty_webgl_contexts
2710 .borrow_mut()
2711 .drain()
2712 .filter(|(_, context)| context.onscreen())
2713 .map(|(id, context)| {
2714 image_keys.push(context.image_key());
2715 id
2716 })
2717 .collect();
2718
2719 if !dirty_webgl_context_ids.is_empty() {
2720 self.window
2721 .webgl_chan()
2722 .expect("Where's the WebGL channel?")
2723 .send(WebGLMsg::SwapBuffers(
2724 dirty_webgl_context_ids,
2725 Some(canvas_epoch),
2726 0,
2727 ))
2728 .unwrap();
2729 }
2730
2731 if !image_keys.is_empty() {
2734 self.waiting_on_canvas_image_updates.set(true);
2735 self.window().compositor_api().delay_new_frame_for_canvas(
2736 self.window().pipeline_id(),
2737 canvas_epoch,
2738 image_keys.into_iter().flatten().collect(),
2739 );
2740 }
2741
2742 self.window().reflow(ReflowGoal::UpdateTheRendering)
2743 }
2744
2745 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2746 self.waiting_on_canvas_image_updates.set(false);
2747 }
2748
2749 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2750 self.waiting_on_canvas_image_updates.get()
2751 }
2752
2753 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2763 if !self.is_fully_active() {
2764 return false;
2765 }
2766
2767 let fonts = self.Fonts(can_gc);
2768 if !fonts.waiting_to_fullfill_promise() {
2769 return false;
2770 }
2771 if self.window().font_context().web_fonts_still_loading() != 0 {
2772 return false;
2773 }
2774 if self.ReadyState() != DocumentReadyState::Complete {
2775 return false;
2776 }
2777 if !self.restyle_reason().is_empty() {
2778 return false;
2779 }
2780 fonts.fulfill_ready_promise_if_needed(can_gc)
2781 }
2782
2783 pub(crate) fn id_map(&self) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>>> {
2784 self.id_map.borrow()
2785 }
2786
2787 pub(crate) fn name_map(&self) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>>> {
2788 self.name_map.borrow()
2789 }
2790
2791 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
2793 self.resize_observers
2794 .borrow_mut()
2795 .push(Dom::from_ref(resize_observer));
2796 }
2797
2798 pub(crate) fn has_resize_observers(&self) -> bool {
2800 !self.resize_observers.borrow().is_empty()
2801 }
2802
2803 pub(crate) fn gather_active_resize_observations_at_depth(
2806 &self,
2807 depth: &ResizeObservationDepth,
2808 ) -> bool {
2809 let mut has_active_resize_observations = false;
2810 for observer in self.resize_observers.borrow_mut().iter_mut() {
2811 observer.gather_active_resize_observations_at_depth(
2812 depth,
2813 &mut has_active_resize_observations,
2814 );
2815 }
2816 has_active_resize_observations
2817 }
2818
2819 pub(crate) fn broadcast_active_resize_observations(
2821 &self,
2822 can_gc: CanGc,
2823 ) -> ResizeObservationDepth {
2824 let mut shallowest = ResizeObservationDepth::max();
2825 let iterator: Vec<DomRoot<ResizeObserver>> = self
2829 .resize_observers
2830 .borrow()
2831 .iter()
2832 .cloned()
2833 .map(|obs| DomRoot::from_ref(&*obs))
2834 .collect();
2835 for observer in iterator {
2836 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
2837 }
2838 shallowest
2839 }
2840
2841 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
2843 self.resize_observers
2844 .borrow()
2845 .iter()
2846 .any(|observer| observer.has_skipped_resize_observations())
2847 }
2848
2849 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
2851 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
2852 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
2853 ..Default::default()
2854 };
2855 self.window
2856 .as_global_scope()
2857 .report_an_error(error_info, HandleValue::null(), can_gc);
2858 }
2859
2860 pub(crate) fn status_code(&self) -> Option<u16> {
2861 self.status_code
2862 }
2863
2864 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
2866 let encoding = self.encoding.get();
2872
2873 let base_url = self.base_url();
2879
2880 url::Url::options()
2882 .base_url(Some(base_url.as_url()))
2883 .encoding_override(Some(&|input| {
2884 servo_url::encoding::encode_as_url_query_string(input, encoding)
2885 }))
2886 .parse(url)
2887 .map(ServoUrl::from)
2888 }
2889
2890 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
2892 if !self.has_browsing_context {
2894 return false;
2895 }
2896
2897 if !self.is_fully_active() {
2899 return false;
2900 }
2901
2902 true
2908 }
2909
2910 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
2913 self.intersection_observers
2914 .borrow_mut()
2915 .push(Dom::from_ref(intersection_observer));
2916 }
2917
2918 pub(crate) fn remove_intersection_observer(
2922 &self,
2923 intersection_observer: &IntersectionObserver,
2924 ) {
2925 self.intersection_observers
2926 .borrow_mut()
2927 .retain(|observer| *observer != intersection_observer)
2928 }
2929
2930 pub(crate) fn update_intersection_observer_steps(
2932 &self,
2933 time: CrossProcessInstant,
2934 can_gc: CanGc,
2935 ) {
2936 for intersection_observer in &*self.intersection_observers.borrow() {
2938 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
2939 }
2940 }
2941
2942 fn update_single_intersection_observer_steps(
2944 &self,
2945 intersection_observer: &IntersectionObserver,
2946 time: CrossProcessInstant,
2947 can_gc: CanGc,
2948 ) {
2949 let root_bounds = intersection_observer.root_intersection_rectangle(self);
2952
2953 intersection_observer.update_intersection_observations_steps(
2957 self,
2958 time,
2959 root_bounds,
2960 can_gc,
2961 );
2962 }
2963
2964 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
2966 self.intersection_observer_task_queued.set(false);
2969
2970 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
2975
2976 for intersection_observer in notify_list.iter() {
2979 intersection_observer.invoke_callback_if_necessary(can_gc);
2981 }
2982 }
2983
2984 pub(crate) fn queue_an_intersection_observer_task(&self) {
2986 if self.intersection_observer_task_queued.get() {
2989 return;
2990 }
2991
2992 self.intersection_observer_task_queued.set(true);
2995
2996 let document = Trusted::new(self);
3000 self.owner_global()
3001 .task_manager()
3002 .intersection_observer_task_source()
3003 .queue(task!(notify_intersection_observers: move || {
3004 document.root().notify_intersection_observers(CanGc::note());
3005 }));
3006 }
3007
3008 pub(crate) fn handle_paint_metric(
3009 &self,
3010 metric_type: ProgressiveWebMetricType,
3011 metric_value: CrossProcessInstant,
3012 first_reflow: bool,
3013 can_gc: CanGc,
3014 ) {
3015 let metrics = self.interactive_time.borrow();
3016 match metric_type {
3017 ProgressiveWebMetricType::FirstPaint => {
3018 metrics.set_first_paint(metric_value, first_reflow)
3019 },
3020 ProgressiveWebMetricType::FirstContentfulPaint => {
3021 metrics.set_first_contentful_paint(metric_value, first_reflow)
3022 },
3023 ProgressiveWebMetricType::TimeToInteractive => {
3024 unreachable!("Unexpected non-paint metric.")
3025 },
3026 }
3027
3028 let entry = PerformancePaintTiming::new(
3029 self.window.as_global_scope(),
3030 metric_type,
3031 metric_value,
3032 can_gc,
3033 );
3034 self.window
3035 .Performance()
3036 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
3037 }
3038
3039 fn write(
3041 &self,
3042 text: Vec<TrustedHTMLOrString>,
3043 line_feed: bool,
3044 containing_class: &str,
3045 field: &str,
3046 can_gc: CanGc,
3047 ) -> ErrorResult {
3048 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3050 let mut is_trusted = true;
3052 for value in text {
3054 match value {
3055 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3057 strings.push(trusted_html.to_string().to_owned());
3058 },
3059 TrustedHTMLOrString::String(str_) => {
3060 is_trusted = false;
3062 strings.push(str_.into());
3064 },
3065 };
3066 }
3067 let mut string = itertools::join(strings, "");
3068 if !is_trusted {
3072 string = TrustedHTML::get_trusted_script_compliant_string(
3073 &self.global(),
3074 TrustedHTMLOrString::String(string.into()),
3075 &format!("{} {}", containing_class, field),
3076 can_gc,
3077 )?
3078 .as_ref()
3079 .to_owned();
3080 }
3081 if line_feed {
3083 string.push('\n');
3084 }
3085 if !self.is_html_document() {
3087 return Err(Error::InvalidState);
3088 }
3089
3090 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3093 return Err(Error::InvalidState);
3094 }
3095
3096 if !self.is_active() || self.active_parser_was_aborted.get() {
3098 return Ok(());
3099 }
3100
3101 let parser = match self.get_current_parser() {
3102 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3103 _ => {
3105 if self.is_prompting_or_unloading() ||
3108 self.ignore_destructive_writes_counter.get() > 0
3109 {
3110 return Ok(());
3111 }
3112 self.Open(None, None, can_gc)?;
3114 self.get_current_parser().unwrap()
3115 },
3116 };
3117
3118 parser.write(string.into(), can_gc);
3120
3121 Ok(())
3122 }
3123}
3124
3125#[derive(MallocSizeOf, PartialEq)]
3126pub(crate) enum DocumentSource {
3127 FromParser,
3128 NotFromParser,
3129}
3130
3131#[allow(unsafe_code)]
3132pub(crate) trait LayoutDocumentHelpers<'dom> {
3133 fn is_html_document_for_layout(&self) -> bool;
3134 fn quirks_mode(self) -> QuirksMode;
3135 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3136 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3137 fn shadow_roots_styles_changed(self) -> bool;
3138 fn flush_shadow_roots_stylesheets(self);
3139}
3140
3141#[allow(unsafe_code)]
3142impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3143 #[inline]
3144 fn is_html_document_for_layout(&self) -> bool {
3145 self.unsafe_get().is_html_document
3146 }
3147
3148 #[inline]
3149 fn quirks_mode(self) -> QuirksMode {
3150 self.unsafe_get().quirks_mode.get()
3151 }
3152
3153 #[inline]
3154 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3155 self.unsafe_get().style_shared_lock()
3156 }
3157
3158 #[inline]
3159 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3160 unsafe {
3165 self.unsafe_get()
3166 .shadow_roots
3167 .borrow_for_layout()
3168 .iter()
3169 .map(|sr| sr.to_layout())
3170 .collect()
3171 }
3172 }
3173
3174 #[inline]
3175 fn shadow_roots_styles_changed(self) -> bool {
3176 self.unsafe_get().shadow_roots_styles_changed.get()
3177 }
3178
3179 #[inline]
3180 fn flush_shadow_roots_stylesheets(self) {
3181 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3182 }
3183}
3184
3185fn get_registrable_domain_suffix_of_or_is_equal_to(
3189 host_suffix_string: &str,
3190 original_host: Host,
3191) -> Option<Host> {
3192 if host_suffix_string.is_empty() {
3194 return None;
3195 }
3196
3197 let host = match Host::parse(host_suffix_string) {
3199 Ok(host) => host,
3200 Err(_) => return None,
3201 };
3202
3203 if host != original_host {
3205 let host = match host {
3207 Host::Domain(ref host) => host,
3208 _ => return None,
3209 };
3210 let original_host = match original_host {
3211 Host::Domain(ref original_host) => original_host,
3212 _ => return None,
3213 };
3214
3215 let index = original_host.len().checked_sub(host.len())?;
3217 let (prefix, suffix) = original_host.split_at(index);
3218
3219 if !prefix.ends_with('.') {
3220 return None;
3221 }
3222 if suffix != host {
3223 return None;
3224 }
3225
3226 if is_pub_domain(host) {
3228 return None;
3229 }
3230 }
3231
3232 Some(host)
3234}
3235
3236fn url_has_network_scheme(url: &ServoUrl) -> bool {
3238 matches!(url.scheme(), "ftp" | "http" | "https")
3239}
3240
3241#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3242pub(crate) enum HasBrowsingContext {
3243 No,
3244 Yes,
3245}
3246
3247impl Document {
3248 #[allow(clippy::too_many_arguments)]
3249 pub(crate) fn new_inherited(
3250 window: &Window,
3251 has_browsing_context: HasBrowsingContext,
3252 url: Option<ServoUrl>,
3253 origin: MutableOrigin,
3254 is_html_document: IsHTMLDocument,
3255 content_type: Option<Mime>,
3256 last_modified: Option<String>,
3257 activity: DocumentActivity,
3258 source: DocumentSource,
3259 doc_loader: DocumentLoader,
3260 referrer: Option<String>,
3261 status_code: Option<u16>,
3262 canceller: FetchCanceller,
3263 is_initial_about_blank: bool,
3264 allow_declarative_shadow_roots: bool,
3265 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3266 has_trustworthy_ancestor_origin: bool,
3267 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3268 ) -> Document {
3269 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3270
3271 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3272 (DocumentReadyState::Loading, false)
3273 } else {
3274 (DocumentReadyState::Complete, true)
3275 };
3276
3277 let frame_type = match window.is_top_level() {
3278 true => TimerMetadataFrameType::RootWindow,
3279 false => TimerMetadataFrameType::IFrame,
3280 };
3281 let interactive_time = ProgressiveWebMetrics::new(
3282 window.time_profiler_chan().clone(),
3283 url.clone(),
3284 frame_type,
3285 );
3286
3287 let content_type = content_type.unwrap_or_else(|| {
3288 match is_html_document {
3289 IsHTMLDocument::HTMLDocument => "text/html",
3291 IsHTMLDocument::NonHTMLDocument => "application/xml",
3293 }
3294 .parse()
3295 .unwrap()
3296 });
3297
3298 let encoding = content_type
3299 .get_parameter(CHARSET)
3300 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3301 .unwrap_or(UTF_8);
3302
3303 let has_focus = window.parent_info().is_none();
3304
3305 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3306
3307 Document {
3308 node: Node::new_document_node(),
3309 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3310 window: Dom::from_ref(window),
3311 has_browsing_context,
3312 implementation: Default::default(),
3313 content_type,
3314 last_modified,
3315 url: DomRefCell::new(url),
3316 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3318 event_handler: DocumentEventHandler::new(window),
3319 id_map: DomRefCell::new(HashMapTracedValues::new()),
3320 name_map: DomRefCell::new(HashMapTracedValues::new()),
3321 encoding: Cell::new(encoding),
3323 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3324 activity: Cell::new(activity),
3325 tag_map: DomRefCell::new(HashMapTracedValues::new()),
3326 tagns_map: DomRefCell::new(HashMapTracedValues::new()),
3327 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3328 images: Default::default(),
3329 embeds: Default::default(),
3330 links: Default::default(),
3331 forms: Default::default(),
3332 scripts: Default::default(),
3333 anchors: Default::default(),
3334 applets: Default::default(),
3335 iframes: RefCell::new(IFrameCollection::new()),
3336 style_shared_lock: {
3337 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3344 LazyLock::new(StyleSharedRwLock::new);
3345
3346 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3347 },
3349 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3350 stylesheet_list: MutNullableDom::new(None),
3351 ready_state: Cell::new(ready_state),
3352 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3353 focus_transaction: DomRefCell::new(None),
3354 focused: Default::default(),
3355 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3356 has_focus: Cell::new(has_focus),
3357 current_script: Default::default(),
3358 pending_parsing_blocking_script: Default::default(),
3359 script_blocking_stylesheets_count: Cell::new(0u32),
3360 deferred_scripts: Default::default(),
3361 asap_in_order_scripts_list: Default::default(),
3362 asap_scripts_set: Default::default(),
3363 scripting_enabled: has_browsing_context,
3364 animation_frame_ident: Cell::new(0),
3365 animation_frame_list: DomRefCell::new(VecDeque::new()),
3366 running_animation_callbacks: Cell::new(false),
3367 loader: DomRefCell::new(doc_loader),
3368 current_parser: Default::default(),
3369 base_element: Default::default(),
3370 appropriate_template_contents_owner_document: Default::default(),
3371 pending_restyles: DomRefCell::new(FnvHashMap::default()),
3372 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3373 dom_interactive: Cell::new(Default::default()),
3374 dom_content_loaded_event_start: Cell::new(Default::default()),
3375 dom_content_loaded_event_end: Cell::new(Default::default()),
3376 dom_complete: Cell::new(Default::default()),
3377 top_level_dom_complete: Cell::new(Default::default()),
3378 load_event_start: Cell::new(Default::default()),
3379 load_event_end: Cell::new(Default::default()),
3380 unload_event_start: Cell::new(Default::default()),
3381 unload_event_end: Cell::new(Default::default()),
3382 https_state: Cell::new(HttpsState::None),
3383 origin,
3384 referrer,
3385 target_element: MutNullableDom::new(None),
3386 policy_container: DomRefCell::new(PolicyContainer::default()),
3387 ignore_destructive_writes_counter: Default::default(),
3388 ignore_opens_during_unload_counter: Default::default(),
3389 spurious_animation_frames: Cell::new(0),
3390 dom_count: Cell::new(1),
3391 fullscreen_element: MutNullableDom::new(None),
3392 form_id_listener_map: Default::default(),
3393 interactive_time: DomRefCell::new(interactive_time),
3394 tti_window: DomRefCell::new(InteractiveWindow::default()),
3395 canceller,
3396 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3397 page_showing: Cell::new(false),
3398 salvageable: Cell::new(true),
3399 active_parser_was_aborted: Cell::new(false),
3400 fired_unload: Cell::new(false),
3401 responsive_images: Default::default(),
3402 redirect_count: Cell::new(0),
3403 completely_loaded: Cell::new(false),
3404 script_and_layout_blockers: Cell::new(0),
3405 delayed_tasks: Default::default(),
3406 shadow_roots: DomRefCell::new(HashSet::new()),
3407 shadow_roots_styles_changed: Cell::new(false),
3408 media_controls: DomRefCell::new(HashMap::new()),
3409 dirty_2d_contexts: DomRefCell::new(HashMapTracedValues::new()),
3410 dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()),
3411 has_pending_animated_image_update: Cell::new(false),
3412 #[cfg(feature = "webgpu")]
3413 webgpu_contexts: Rc::new(RefCell::new(HashMapTracedValues::new())),
3414 selection: MutNullableDom::new(None),
3415 animation_timeline: if pref!(layout_animations_test_enabled) {
3416 DomRefCell::new(AnimationTimeline::new_for_testing())
3417 } else {
3418 DomRefCell::new(AnimationTimeline::new())
3419 },
3420 animations: DomRefCell::new(Animations::new()),
3421 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3422 dirty_root: Default::default(),
3423 declarative_refresh: Default::default(),
3424 resize_observers: Default::default(),
3425 fonts: Default::default(),
3426 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3427 status_code,
3428 is_initial_about_blank: Cell::new(is_initial_about_blank),
3429 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3430 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3431 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3432 intersection_observer_task_queued: Cell::new(false),
3433 intersection_observers: Default::default(),
3434 highlighted_dom_node: Default::default(),
3435 adopted_stylesheets: Default::default(),
3436 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3437 pending_scroll_event_targets: Default::default(),
3438 resize_observer_started_observing_target: Cell::new(false),
3439 waiting_on_canvas_image_updates: Cell::new(false),
3440 current_canvas_epoch: RefCell::new(Epoch(0)),
3441 custom_element_reaction_stack,
3442 }
3443 }
3444
3445 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3447 if let Some(csp_list) = self.get_csp_list() {
3448 for policy in &csp_list.0 {
3449 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3450 policy.disposition == PolicyDisposition::Enforce
3451 {
3452 return InsecureRequestsPolicy::Upgrade;
3453 }
3454 }
3455 }
3456
3457 self.inherited_insecure_requests_policy
3458 .get()
3459 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3460 }
3461
3462 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3464 &self.event_handler
3465 }
3466
3467 fn has_pending_scroll_events(&self) -> bool {
3470 !self.pending_scroll_event_targets.borrow().is_empty()
3471 }
3472
3473 pub(crate) fn set_resize_observer_started_observing_target(&self, value: bool) {
3474 self.resize_observer_started_observing_target.set(value);
3475 }
3476
3477 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
3478 self.policy_container.borrow_mut().set_csp_list(csp_list);
3479 }
3480
3481 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
3482 self.policy_container.borrow().csp_list.clone()
3483 }
3484
3485 pub(crate) fn add_script_and_layout_blocker(&self) {
3492 self.script_and_layout_blockers
3493 .set(self.script_and_layout_blockers.get() + 1);
3494 }
3495
3496 pub(crate) fn remove_script_and_layout_blocker(&self) {
3500 assert!(self.script_and_layout_blockers.get() > 0);
3501 self.script_and_layout_blockers
3502 .set(self.script_and_layout_blockers.get() - 1);
3503 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3504 {
3505 let task = self.delayed_tasks.borrow_mut().remove(0);
3506 task.run_box();
3507 }
3508 }
3509
3510 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3512 self.delayed_tasks.borrow_mut().push(Box::new(task));
3513 }
3514
3515 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3518 assert_eq!(
3519 self.script_and_layout_blockers.get(),
3520 0,
3521 "Attempt to use script or layout while DOM not in a stable state"
3522 );
3523 }
3524
3525 #[allow(clippy::too_many_arguments)]
3526 pub(crate) fn new(
3527 window: &Window,
3528 has_browsing_context: HasBrowsingContext,
3529 url: Option<ServoUrl>,
3530 origin: MutableOrigin,
3531 doctype: IsHTMLDocument,
3532 content_type: Option<Mime>,
3533 last_modified: Option<String>,
3534 activity: DocumentActivity,
3535 source: DocumentSource,
3536 doc_loader: DocumentLoader,
3537 referrer: Option<String>,
3538 status_code: Option<u16>,
3539 canceller: FetchCanceller,
3540 is_initial_about_blank: bool,
3541 allow_declarative_shadow_roots: bool,
3542 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3543 has_trustworthy_ancestor_origin: bool,
3544 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3545 can_gc: CanGc,
3546 ) -> DomRoot<Document> {
3547 Self::new_with_proto(
3548 window,
3549 None,
3550 has_browsing_context,
3551 url,
3552 origin,
3553 doctype,
3554 content_type,
3555 last_modified,
3556 activity,
3557 source,
3558 doc_loader,
3559 referrer,
3560 status_code,
3561 canceller,
3562 is_initial_about_blank,
3563 allow_declarative_shadow_roots,
3564 inherited_insecure_requests_policy,
3565 has_trustworthy_ancestor_origin,
3566 custom_element_reaction_stack,
3567 can_gc,
3568 )
3569 }
3570
3571 #[allow(clippy::too_many_arguments)]
3572 fn new_with_proto(
3573 window: &Window,
3574 proto: Option<HandleObject>,
3575 has_browsing_context: HasBrowsingContext,
3576 url: Option<ServoUrl>,
3577 origin: MutableOrigin,
3578 doctype: IsHTMLDocument,
3579 content_type: Option<Mime>,
3580 last_modified: Option<String>,
3581 activity: DocumentActivity,
3582 source: DocumentSource,
3583 doc_loader: DocumentLoader,
3584 referrer: Option<String>,
3585 status_code: Option<u16>,
3586 canceller: FetchCanceller,
3587 is_initial_about_blank: bool,
3588 allow_declarative_shadow_roots: bool,
3589 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3590 has_trustworthy_ancestor_origin: bool,
3591 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3592 can_gc: CanGc,
3593 ) -> DomRoot<Document> {
3594 let document = reflect_dom_object_with_proto(
3595 Box::new(Document::new_inherited(
3596 window,
3597 has_browsing_context,
3598 url,
3599 origin,
3600 doctype,
3601 content_type,
3602 last_modified,
3603 activity,
3604 source,
3605 doc_loader,
3606 referrer,
3607 status_code,
3608 canceller,
3609 is_initial_about_blank,
3610 allow_declarative_shadow_roots,
3611 inherited_insecure_requests_policy,
3612 has_trustworthy_ancestor_origin,
3613 custom_element_reaction_stack,
3614 )),
3615 window,
3616 proto,
3617 can_gc,
3618 );
3619 {
3620 let node = document.upcast::<Node>();
3621 node.set_owner_doc(&document);
3622 }
3623 document
3624 }
3625
3626 pub(crate) fn get_redirect_count(&self) -> u16 {
3627 self.redirect_count.get()
3628 }
3629
3630 pub(crate) fn set_redirect_count(&self, count: u16) {
3631 self.redirect_count.set(count)
3632 }
3633
3634 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3635 if name.is_empty() {
3636 return 0;
3637 }
3638 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3639 }
3640
3641 pub(crate) fn nth_element_by_name(
3642 &self,
3643 index: u32,
3644 name: &DOMString,
3645 ) -> Option<DomRoot<Node>> {
3646 if name.is_empty() {
3647 return None;
3648 }
3649 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3650 }
3651
3652 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3655 let element = match node.downcast::<Element>() {
3656 Some(element) => element,
3657 None => return false,
3658 };
3659 if element.namespace() != &ns!(html) {
3660 return false;
3661 }
3662 element.get_name().is_some_and(|n| *n == **name)
3663 }
3664
3665 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3666 let doc = self.GetDocumentElement();
3667 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3668 maybe_node
3669 .iter()
3670 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3671 .filter(|node| callback(node))
3672 .count() as u32
3673 }
3674
3675 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3676 &self,
3677 index: u32,
3678 callback: F,
3679 ) -> Option<DomRoot<Node>> {
3680 let doc = self.GetDocumentElement();
3681 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3682 maybe_node
3683 .iter()
3684 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3685 .filter(|node| callback(node))
3686 .nth(index as usize)
3687 .map(|n| DomRoot::from_ref(&*n))
3688 }
3689
3690 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3691 self.GetDocumentElement().and_then(DomRoot::downcast)
3692 }
3693
3694 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3696 &self.style_shared_lock
3697 }
3698
3699 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3701 let mut stylesheets = self.stylesheets.borrow_mut();
3708 let have_changed = stylesheets.has_changed();
3709 stylesheets.flush_without_invalidation();
3710 have_changed
3711 }
3712
3713 pub(crate) fn salvageable(&self) -> bool {
3714 self.salvageable.get()
3715 }
3716
3717 pub(crate) fn appropriate_template_contents_owner_document(
3719 &self,
3720 can_gc: CanGc,
3721 ) -> DomRoot<Document> {
3722 self.appropriate_template_contents_owner_document
3723 .or_init(|| {
3724 let doctype = if self.is_html_document {
3725 IsHTMLDocument::HTMLDocument
3726 } else {
3727 IsHTMLDocument::NonHTMLDocument
3728 };
3729 let new_doc = Document::new(
3730 self.window(),
3731 HasBrowsingContext::No,
3732 None,
3733 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3735 doctype,
3736 None,
3737 None,
3738 DocumentActivity::Inactive,
3739 DocumentSource::NotFromParser,
3740 DocumentLoader::new(&self.loader()),
3741 None,
3742 None,
3743 Default::default(),
3744 false,
3745 self.allow_declarative_shadow_roots(),
3746 Some(self.insecure_requests_policy()),
3747 self.has_trustworthy_ancestor_or_current_origin(),
3748 self.custom_element_reaction_stack.clone(),
3749 can_gc,
3750 );
3751 new_doc
3752 .appropriate_template_contents_owner_document
3753 .set(Some(&new_doc));
3754 new_doc
3755 })
3756 }
3757
3758 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
3759 self.id_map
3760 .borrow()
3761 .get(id)
3762 .map(|elements| DomRoot::from_ref(&*elements[0]))
3763 }
3764
3765 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
3766 let map = self.pending_restyles.borrow_mut();
3767 RefMut::map(map, |m| {
3768 &mut m
3769 .entry(Dom::from_ref(el))
3770 .or_insert_with(|| NoTrace(PendingRestyle::default()))
3771 .0
3772 })
3773 }
3774
3775 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
3776 let mut entry = self.ensure_pending_restyle(el);
3782 if entry.snapshot.is_none() {
3783 entry.snapshot = Some(Snapshot::new());
3784 }
3785 if attr.local_name() == &local_name!("style") {
3786 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
3787 }
3788
3789 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
3790 entry.hint.insert(RestyleHint::RESTYLE_SELF);
3791 }
3792
3793 let snapshot = entry.snapshot.as_mut().unwrap();
3794 if attr.local_name() == &local_name!("id") {
3795 if snapshot.id_changed {
3796 return;
3797 }
3798 snapshot.id_changed = true;
3799 } else if attr.local_name() == &local_name!("class") {
3800 if snapshot.class_changed {
3801 return;
3802 }
3803 snapshot.class_changed = true;
3804 } else {
3805 snapshot.other_attributes_changed = true;
3806 }
3807 let local_name = style::LocalName::cast(attr.local_name());
3808 if !snapshot.changed_attrs.contains(local_name) {
3809 snapshot.changed_attrs.push(local_name.clone());
3810 }
3811 if snapshot.attrs.is_none() {
3812 let attrs = el
3813 .attrs()
3814 .iter()
3815 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
3816 .collect();
3817 snapshot.attrs = Some(attrs);
3818 }
3819 }
3820
3821 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
3822 self.policy_container
3823 .borrow_mut()
3824 .set_referrer_policy(policy);
3825 }
3826
3827 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
3828 self.policy_container.borrow().get_referrer_policy()
3829 }
3830
3831 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
3832 if let Some(ref element) = self.target_element.get() {
3833 element.set_target_state(false);
3834 }
3835
3836 self.target_element.set(node);
3837
3838 if let Some(ref element) = self.target_element.get() {
3839 element.set_target_state(true);
3840 }
3841 }
3842
3843 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
3844 self.ignore_destructive_writes_counter
3845 .set(self.ignore_destructive_writes_counter.get() + 1);
3846 }
3847
3848 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
3849 self.ignore_destructive_writes_counter
3850 .set(self.ignore_destructive_writes_counter.get() - 1);
3851 }
3852
3853 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
3854 self.ignore_opens_during_unload_counter.get() > 0
3855 }
3856
3857 fn incr_ignore_opens_during_unload_counter(&self) {
3858 self.ignore_opens_during_unload_counter
3859 .set(self.ignore_opens_during_unload_counter.get() + 1);
3860 }
3861
3862 fn decr_ignore_opens_during_unload_counter(&self) {
3863 self.ignore_opens_during_unload_counter
3864 .set(self.ignore_opens_during_unload_counter.get() - 1);
3865 }
3866
3867 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
3869 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
3871 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
3872 let mut error = false;
3873
3874 match *pending.namespace() {
3877 ns!(mathml) => {
3878 if pending.local_name().as_ref() != "math" {
3879 error = true;
3880 }
3881 },
3882 ns!(svg) => {
3883 if pending.local_name().as_ref() != "svg" {
3884 error = true;
3885 }
3886 },
3887 ns!(html) => (),
3888 _ => error = true,
3889 }
3890 if !pending.fullscreen_element_ready_check() {
3892 error = true;
3893 }
3894
3895 if pref!(dom_fullscreen_test) {
3896 info!("Tests don't really enter fullscreen.");
3899 } else {
3900 warn!("Fullscreen not supported yet");
3903 }
3904
3905 let window = self.window();
3908 if !error {
3910 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
3911 self.send_to_embedder(event);
3912 }
3913
3914 let pipeline_id = self.window().pipeline_id();
3915
3916 let trusted_pending = Trusted::new(pending);
3918 let trusted_promise = TrustedPromise::new(promise.clone());
3919 let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
3920 let script_msg = CommonScriptMsg::Task(
3923 ScriptThreadEventCategory::EnterFullscreen,
3924 handler,
3925 Some(pipeline_id),
3926 TaskSourceName::DOMManipulation,
3927 );
3928 let msg = MainThreadScriptMsg::Common(script_msg);
3929 window.main_thread_script_chan().send(msg).unwrap();
3930
3931 promise
3932 }
3933
3934 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
3936 let global = self.global();
3937 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
3939 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
3940 if self.fullscreen_element.get().is_none() {
3942 promise.reject_error(Error::Type(String::from("fullscreen is null")), can_gc);
3943 return promise;
3944 }
3945 let element = self.fullscreen_element.get().unwrap();
3947
3948 let window = self.window();
3951 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
3953 self.send_to_embedder(event);
3954
3955 let trusted_element = Trusted::new(&*element);
3957 let trusted_promise = TrustedPromise::new(promise.clone());
3958 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
3959 let pipeline_id = Some(global.pipeline_id());
3960 let script_msg = CommonScriptMsg::Task(
3963 ScriptThreadEventCategory::ExitFullscreen,
3964 handler,
3965 pipeline_id,
3966 TaskSourceName::DOMManipulation,
3967 );
3968 let msg = MainThreadScriptMsg::Common(script_msg);
3969 window.main_thread_script_chan().send(msg).unwrap();
3970
3971 promise
3972 }
3973
3974 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
3975 self.fullscreen_element.set(element);
3976 }
3977
3978 pub(crate) fn get_allow_fullscreen(&self) -> bool {
3979 match self.browsing_context() {
3981 None => false,
3983 Some(_) => {
3984 let window = self.window();
3986 if window.is_top_level() {
3987 true
3988 } else {
3989 window
3991 .GetFrameElement()
3992 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
3993 }
3994 },
3995 }
3996 }
3997
3998 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
3999 let map = self.form_id_listener_map.borrow();
4000 if let Some(listeners) = map.get(id) {
4001 for listener in listeners {
4002 listener
4003 .as_maybe_form_control()
4004 .expect("Element must be a form control")
4005 .reset_form_owner(can_gc);
4006 }
4007 }
4008 }
4009
4010 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4011 self.shadow_roots
4012 .borrow_mut()
4013 .insert(Dom::from_ref(shadow_root));
4014 self.invalidate_shadow_roots_stylesheets();
4015 }
4016
4017 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4018 let mut shadow_roots = self.shadow_roots.borrow_mut();
4019 shadow_roots.remove(&Dom::from_ref(shadow_root));
4020 }
4021
4022 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4023 self.shadow_roots_styles_changed.set(true);
4024 }
4025
4026 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4027 self.shadow_roots_styles_changed.get()
4028 }
4029
4030 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4031 if !self.shadow_roots_styles_changed.get() {
4032 return;
4033 }
4034 self.shadow_roots_styles_changed.set(false);
4035 }
4036
4037 pub(crate) fn stylesheet_count(&self) -> usize {
4038 self.stylesheets.borrow().len()
4039 }
4040
4041 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4042 let stylesheets = self.stylesheets.borrow();
4043
4044 stylesheets
4045 .get(Origin::Author, index)
4046 .and_then(|s| s.owner.get_cssom_object())
4047 }
4048
4049 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4056 let stylesheets = &mut *self.stylesheets.borrow_mut();
4057
4058 let insertion_point = stylesheets
4060 .iter()
4061 .map(|(sheet, _origin)| sheet)
4062 .find(|sheet_in_doc| {
4063 match &sheet_in_doc.owner {
4064 StylesheetSource::Element(other_node) => {
4065 owner_node.upcast::<Node>().is_before(other_node.upcast())
4066 },
4067 StylesheetSource::Constructed(_) => true,
4070 }
4071 })
4072 .cloned();
4073
4074 if self.has_browsing_context() {
4075 self.window.layout_mut().add_stylesheet(
4076 sheet.clone(),
4077 insertion_point.as_ref().map(|s| s.sheet.clone()),
4078 );
4079 }
4080
4081 DocumentOrShadowRoot::add_stylesheet(
4082 StylesheetSource::Element(Dom::from_ref(owner_node)),
4083 StylesheetSetRef::Document(stylesheets),
4084 sheet,
4085 insertion_point,
4086 self.style_shared_lock(),
4087 );
4088 }
4089
4090 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4095 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4096 debug_assert!(cssom_stylesheet.is_constructed());
4097
4098 let stylesheets = &mut *self.stylesheets.borrow_mut();
4099 let sheet = cssom_stylesheet.style_stylesheet().clone();
4100
4101 let insertion_point = stylesheets
4102 .iter()
4103 .last()
4104 .map(|(sheet, _origin)| sheet)
4105 .cloned();
4106
4107 if self.has_browsing_context() {
4108 self.window.layout_mut().add_stylesheet(
4109 sheet.clone(),
4110 insertion_point.as_ref().map(|s| s.sheet.clone()),
4111 );
4112 }
4113
4114 DocumentOrShadowRoot::add_stylesheet(
4115 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4116 StylesheetSetRef::Document(stylesheets),
4117 sheet,
4118 insertion_point,
4119 self.style_shared_lock(),
4120 );
4121 }
4122
4123 pub(crate) fn load_web_fonts_from_stylesheet(&self, stylesheet: Arc<Stylesheet>) {
4125 self.window
4126 .layout()
4127 .load_web_fonts_from_stylesheet(stylesheet);
4128 }
4129
4130 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4133 if self.has_browsing_context() {
4134 self.window
4135 .layout_mut()
4136 .remove_stylesheet(stylesheet.clone());
4137 }
4138
4139 DocumentOrShadowRoot::remove_stylesheet(
4140 owner,
4141 stylesheet,
4142 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4143 )
4144 }
4145
4146 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4147 Ref::map(self.id_map.borrow(), |map| {
4148 map.get(id).map(|vec| &**vec).unwrap_or_default()
4149 })
4150 }
4151
4152 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4153 Ref::map(self.name_map.borrow(), |map| {
4154 map.get(name).map(|vec| &**vec).unwrap_or_default()
4155 })
4156 }
4157
4158 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4159 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4160 self.pending_restyles
4161 .borrow_mut()
4162 .drain()
4163 .filter_map(|(elem, restyle)| {
4164 let node = elem.upcast::<Node>();
4165 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4166 return None;
4167 }
4168 node.note_dirty_descendants();
4169 Some((node.to_trusted_node_address(), restyle.0))
4170 })
4171 .collect()
4172 }
4173
4174 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4175 self.animation_timeline.borrow_mut().advance_specific(delta);
4176 let current_timeline_value = self.current_animation_timeline_value();
4177 self.animations
4178 .borrow()
4179 .update_for_new_timeline_value(&self.window, current_timeline_value);
4180 }
4181
4182 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4183 let current_timeline_value = self.current_animation_timeline_value();
4184 self.animations
4185 .borrow()
4186 .mark_animating_nodes_as_dirty(current_timeline_value);
4187 }
4188
4189 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4190 self.animation_timeline.borrow().current_value()
4191 }
4192
4193 pub(crate) fn animations(&self) -> Ref<'_, Animations> {
4194 self.animations.borrow()
4195 }
4196
4197 pub(crate) fn update_animations_post_reflow(&self) {
4198 self.animations
4199 .borrow()
4200 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4201 self.image_animation_manager
4202 .borrow()
4203 .update_rooted_dom_nodes(&self.window, self.current_animation_timeline_value());
4204 }
4205
4206 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4207 self.animations.borrow().cancel_animations_for_node(node);
4208 }
4209
4210 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4212 if !pref!(layout_animations_test_enabled) {
4214 self.animation_timeline.borrow_mut().update();
4215 }
4216
4217 let current_timeline_value = self.current_animation_timeline_value();
4224 self.animations
4225 .borrow()
4226 .update_for_new_timeline_value(&self.window, current_timeline_value);
4227 self.maybe_mark_animating_nodes_as_dirty();
4228
4229 self.window()
4231 .as_global_scope()
4232 .perform_a_microtask_checkpoint(can_gc);
4233
4234 let _realm = enter_realm(self);
4236 self.animations().send_pending_events(self.window(), can_gc);
4237 }
4238
4239 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4240 self.image_animation_manager.borrow()
4241 }
4242
4243 pub(crate) fn set_has_pending_animated_image_update(&self) {
4244 self.has_pending_animated_image_update.set(true);
4245 }
4246
4247 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4249 if self.will_declaratively_refresh() {
4251 return;
4252 }
4253
4254 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4256 Regex::new(
4260 r#"(?xs)
4261 ^
4262 \s* # 3
4263 ((?<time>[0-9]+)|\.) # 5-6
4264 [0-9.]* # 8
4265 (
4266 (
4267 (\s*;|\s*,|\s) # 10.3
4268 \s* # 10.4
4269 )
4270 (
4271 (
4272 (U|u)(R|r)(L|l) # 11.2-11.4
4273 \s*=\s* # 11.5-11.7
4274 )?
4275 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4276 |
4277 (?<url4>(?s-u:.)*)
4278 )
4279 )?
4280 $
4281 "#,
4282 )
4283 .unwrap()
4284 });
4285
4286 let mut url_record = self.url();
4288 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4289 captures
4290 } else {
4291 return;
4292 };
4293 let time = if let Some(time_string) = captures.name("time") {
4294 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4295 } else {
4296 0
4297 };
4298 let captured_url = captures.name("url1").or(captures
4299 .name("url2")
4300 .or(captures.name("url3").or(captures.name("url4"))));
4301
4302 if let Some(url_match) = captured_url {
4304 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4305 Some(&url_record),
4306 &String::from_utf8_lossy(url_match.as_bytes()),
4307 ) {
4308 info!("Refresh to {}", url.debug_compact());
4309 url
4310 } else {
4311 return;
4313 }
4314 }
4315 if self.completely_loaded() {
4317 self.window.as_global_scope().schedule_callback(
4319 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4320 window: DomRoot::from_ref(self.window()),
4321 url: url_record,
4322 }),
4323 Duration::from_secs(time),
4324 );
4325 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4326 } else {
4327 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4328 url: url_record,
4329 time,
4330 });
4331 }
4332 }
4333
4334 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4335 self.declarative_refresh.borrow().is_some()
4336 }
4337 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4338 *self.declarative_refresh.borrow_mut() = Some(refresh);
4339 }
4340
4341 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4343 if self.visibility_state.get() == visibility_state {
4345 return;
4346 }
4347 self.visibility_state.set(visibility_state);
4349 let entry = VisibilityStateEntry::new(
4352 &self.global(),
4353 visibility_state,
4354 CrossProcessInstant::now(),
4355 can_gc,
4356 );
4357 self.window
4358 .Performance()
4359 .queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
4360
4361 if visibility_state == DocumentVisibilityState::Hidden {
4372 self.window
4373 .Navigator()
4374 .GetGamepads()
4375 .iter_mut()
4376 .for_each(|gamepad| {
4377 if let Some(g) = gamepad {
4378 g.vibration_actuator().handle_visibility_change();
4379 }
4380 });
4381 }
4382
4383 self.upcast::<EventTarget>()
4385 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4386 }
4387
4388 pub(crate) fn is_initial_about_blank(&self) -> bool {
4390 self.is_initial_about_blank.get()
4391 }
4392
4393 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4395 self.allow_declarative_shadow_roots.get()
4396 }
4397
4398 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4399 self.has_trustworthy_ancestor_origin.get()
4400 }
4401
4402 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4403 self.has_trustworthy_ancestor_origin.get() ||
4404 self.origin().immutable().is_potentially_trustworthy()
4405 }
4406
4407 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4408 self.highlighted_dom_node.set(node);
4409 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4410 }
4411
4412 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4413 self.highlighted_dom_node.get()
4414 }
4415
4416 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4417 self.custom_element_reaction_stack.clone()
4418 }
4419}
4420
4421#[allow(non_snake_case)]
4422impl DocumentMethods<crate::DomTypeHolder> for Document {
4423 fn Constructor(
4425 window: &Window,
4426 proto: Option<HandleObject>,
4427 can_gc: CanGc,
4428 ) -> Fallible<DomRoot<Document>> {
4429 let doc = window.Document();
4430 let docloader = DocumentLoader::new(&doc.loader());
4431 Ok(Document::new_with_proto(
4432 window,
4433 proto,
4434 HasBrowsingContext::No,
4435 None,
4436 doc.origin().clone(),
4437 IsHTMLDocument::NonHTMLDocument,
4438 None,
4439 None,
4440 DocumentActivity::Inactive,
4441 DocumentSource::NotFromParser,
4442 docloader,
4443 None,
4444 None,
4445 Default::default(),
4446 false,
4447 doc.allow_declarative_shadow_roots(),
4448 Some(doc.insecure_requests_policy()),
4449 doc.has_trustworthy_ancestor_or_current_origin(),
4450 doc.custom_element_reaction_stack(),
4451 can_gc,
4452 ))
4453 }
4454
4455 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
4457 false
4458 }
4459
4460 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4462 self.stylesheet_list.or_init(|| {
4463 StyleSheetList::new(
4464 &self.window,
4465 StyleSheetListOwner::Document(Dom::from_ref(self)),
4466 can_gc,
4467 )
4468 })
4469 }
4470
4471 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4473 self.implementation
4474 .or_init(|| DOMImplementation::new(self, can_gc))
4475 }
4476
4477 fn URL(&self) -> USVString {
4479 USVString(String::from(self.url().as_str()))
4480 }
4481
4482 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4484 self.document_or_shadow_root.get_active_element(
4485 self.get_focused_element(),
4486 self.GetBody(),
4487 self.GetDocumentElement(),
4488 )
4489 }
4490
4491 fn HasFocus(&self) -> bool {
4493 if self.window().parent_info().is_none() {
4515 self.is_fully_active()
4517 } else {
4518 self.is_fully_active() && self.has_focus.get()
4520 }
4521 }
4522
4523 fn Domain(&self) -> DOMString {
4525 if !self.has_browsing_context {
4527 return DOMString::new();
4528 }
4529
4530 match self.origin.effective_domain() {
4532 None => DOMString::new(),
4534 Some(Host::Domain(domain)) => DOMString::from(domain),
4536 Some(host) => DOMString::from(host.to_string()),
4537 }
4538 }
4539
4540 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4542 if !self.has_browsing_context {
4544 return Err(Error::Security);
4545 }
4546
4547 let effective_domain = match self.origin.effective_domain() {
4553 Some(effective_domain) => effective_domain,
4554 None => return Err(Error::Security),
4555 };
4556
4557 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
4559 None => return Err(Error::Security),
4560 Some(host) => host,
4561 };
4562
4563 self.origin.set_domain(host);
4565
4566 Ok(())
4567 }
4568
4569 fn Referrer(&self) -> DOMString {
4571 match self.referrer {
4572 Some(ref referrer) => DOMString::from(referrer.to_string()),
4573 None => DOMString::new(),
4574 }
4575 }
4576
4577 fn DocumentURI(&self) -> USVString {
4579 self.URL()
4580 }
4581
4582 fn CompatMode(&self) -> DOMString {
4584 DOMString::from(match self.quirks_mode.get() {
4585 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4586 QuirksMode::Quirks => "BackCompat",
4587 })
4588 }
4589
4590 fn CharacterSet(&self) -> DOMString {
4592 DOMString::from(self.encoding.get().name())
4593 }
4594
4595 fn Charset(&self) -> DOMString {
4597 self.CharacterSet()
4598 }
4599
4600 fn InputEncoding(&self) -> DOMString {
4602 self.CharacterSet()
4603 }
4604
4605 fn ContentType(&self) -> DOMString {
4607 DOMString::from(self.content_type.to_string())
4608 }
4609
4610 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4612 self.upcast::<Node>()
4613 .children()
4614 .filter_map(DomRoot::downcast)
4615 .next()
4616 }
4617
4618 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4620 self.upcast::<Node>().child_elements().next()
4621 }
4622
4623 fn GetElementsByTagName(
4625 &self,
4626 qualified_name: DOMString,
4627 can_gc: CanGc,
4628 ) -> DomRoot<HTMLCollection> {
4629 let qualified_name = LocalName::from(&*qualified_name);
4630 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4631 return DomRoot::from_ref(entry);
4632 }
4633 let result = HTMLCollection::by_qualified_name(
4634 &self.window,
4635 self.upcast(),
4636 qualified_name.clone(),
4637 can_gc,
4638 );
4639 self.tag_map
4640 .borrow_mut()
4641 .insert(qualified_name, Dom::from_ref(&*result));
4642 result
4643 }
4644
4645 fn GetElementsByTagNameNS(
4647 &self,
4648 maybe_ns: Option<DOMString>,
4649 tag_name: DOMString,
4650 can_gc: CanGc,
4651 ) -> DomRoot<HTMLCollection> {
4652 let ns = namespace_from_domstring(maybe_ns);
4653 let local = LocalName::from(tag_name);
4654 let qname = QualName::new(None, ns, local);
4655 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4656 return DomRoot::from_ref(collection);
4657 }
4658 let result =
4659 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4660 self.tagns_map
4661 .borrow_mut()
4662 .insert(qname, Dom::from_ref(&*result));
4663 result
4664 }
4665
4666 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4668 let class_atoms: Vec<Atom> = split_html_space_chars(&classes).map(Atom::from).collect();
4669 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4670 return DomRoot::from_ref(collection);
4671 }
4672 let result = HTMLCollection::by_atomic_class_name(
4673 &self.window,
4674 self.upcast(),
4675 class_atoms.clone(),
4676 can_gc,
4677 );
4678 self.classes_map
4679 .borrow_mut()
4680 .insert(class_atoms, Dom::from_ref(&*result));
4681 result
4682 }
4683
4684 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4686 self.get_element_by_id(&Atom::from(id))
4687 }
4688
4689 fn CreateElement(
4691 &self,
4692 mut local_name: DOMString,
4693 options: StringOrElementCreationOptions,
4694 can_gc: CanGc,
4695 ) -> Fallible<DomRoot<Element>> {
4696 if !is_valid_element_local_name(&local_name) {
4699 debug!("Not a valid element name");
4700 return Err(Error::InvalidCharacter);
4701 }
4702
4703 if self.is_html_document {
4704 local_name.make_ascii_lowercase();
4705 }
4706
4707 let ns = if self.is_html_document || self.is_xhtml_document() {
4708 ns!(html)
4709 } else {
4710 ns!()
4711 };
4712
4713 let name = QualName::new(None, ns, LocalName::from(local_name));
4714 let is = match options {
4715 StringOrElementCreationOptions::String(_) => None,
4716 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4717 options.is.as_ref().map(|is| LocalName::from(&**is))
4718 },
4719 };
4720 Ok(Element::create(
4721 name,
4722 is,
4723 self,
4724 ElementCreator::ScriptCreated,
4725 CustomElementCreationMode::Synchronous,
4726 None,
4727 can_gc,
4728 ))
4729 }
4730
4731 fn CreateElementNS(
4733 &self,
4734 namespace: Option<DOMString>,
4735 qualified_name: DOMString,
4736 options: StringOrElementCreationOptions,
4737 can_gc: CanGc,
4738 ) -> Fallible<DomRoot<Element>> {
4739 let context = domname::Context::Element;
4742 let (namespace, prefix, local_name) =
4743 domname::validate_and_extract(namespace, &qualified_name, context)?;
4744
4745 let name = QualName::new(prefix, namespace, local_name);
4748 let is = match options {
4749 StringOrElementCreationOptions::String(_) => None,
4750 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4751 options.is.as_ref().map(|is| LocalName::from(&**is))
4752 },
4753 };
4754
4755 Ok(Element::create(
4757 name,
4758 is,
4759 self,
4760 ElementCreator::ScriptCreated,
4761 CustomElementCreationMode::Synchronous,
4762 None,
4763 can_gc,
4764 ))
4765 }
4766
4767 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
4769 if !is_valid_attribute_local_name(&local_name) {
4772 debug!("Not a valid attribute name");
4773 return Err(Error::InvalidCharacter);
4774 }
4775 if self.is_html_document {
4776 local_name.make_ascii_lowercase();
4777 }
4778 let name = LocalName::from(local_name);
4779 let value = AttrValue::String("".to_owned());
4780
4781 Ok(Attr::new(
4782 self,
4783 name.clone(),
4784 value,
4785 name,
4786 ns!(),
4787 None,
4788 None,
4789 can_gc,
4790 ))
4791 }
4792
4793 fn CreateAttributeNS(
4795 &self,
4796 namespace: Option<DOMString>,
4797 qualified_name: DOMString,
4798 can_gc: CanGc,
4799 ) -> Fallible<DomRoot<Attr>> {
4800 let context = domname::Context::Attribute;
4803 let (namespace, prefix, local_name) =
4804 domname::validate_and_extract(namespace, &qualified_name, context)?;
4805 let value = AttrValue::String("".to_owned());
4806 let qualified_name = LocalName::from(qualified_name);
4807 Ok(Attr::new(
4808 self,
4809 local_name,
4810 value,
4811 qualified_name,
4812 namespace,
4813 prefix,
4814 None,
4815 can_gc,
4816 ))
4817 }
4818
4819 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
4821 DocumentFragment::new(self, can_gc)
4822 }
4823
4824 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
4826 Text::new(data, self, can_gc)
4827 }
4828
4829 fn CreateCDATASection(
4831 &self,
4832 data: DOMString,
4833 can_gc: CanGc,
4834 ) -> Fallible<DomRoot<CDATASection>> {
4835 if self.is_html_document {
4837 return Err(Error::NotSupported);
4838 }
4839
4840 if data.contains("]]>") {
4842 return Err(Error::InvalidCharacter);
4843 }
4844
4845 Ok(CDATASection::new(data, self, can_gc))
4847 }
4848
4849 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
4851 Comment::new(data, self, None, can_gc)
4852 }
4853
4854 fn CreateProcessingInstruction(
4856 &self,
4857 target: DOMString,
4858 data: DOMString,
4859 can_gc: CanGc,
4860 ) -> Fallible<DomRoot<ProcessingInstruction>> {
4861 if !matches_name_production(&target) {
4863 return Err(Error::InvalidCharacter);
4864 }
4865
4866 if data.contains("?>") {
4868 return Err(Error::InvalidCharacter);
4869 }
4870
4871 Ok(ProcessingInstruction::new(target, data, self, can_gc))
4873 }
4874
4875 fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
4877 if node.is::<Document>() || node.is::<ShadowRoot>() {
4879 return Err(Error::NotSupported);
4880 }
4881
4882 let clone_children = if deep {
4884 CloneChildrenFlag::CloneChildren
4885 } else {
4886 CloneChildrenFlag::DoNotCloneChildren
4887 };
4888
4889 Ok(Node::clone(node, Some(self), clone_children, can_gc))
4890 }
4891
4892 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
4894 if node.is::<Document>() {
4896 return Err(Error::NotSupported);
4897 }
4898
4899 if node.is::<ShadowRoot>() {
4901 return Err(Error::HierarchyRequest);
4902 }
4903
4904 Node::adopt(node, self, can_gc);
4906
4907 Ok(DomRoot::from_ref(node))
4909 }
4910
4911 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
4913 interface.make_ascii_lowercase();
4914 match &*interface {
4915 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
4916 &self.window,
4917 can_gc,
4918 ))),
4919 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
4920 CompositionEvent::new_uninitialized(&self.window, can_gc),
4921 )),
4922 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
4923 self.window.upcast(),
4924 can_gc,
4925 ))),
4926 "events" | "event" | "htmlevents" | "svgevents" => {
4929 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
4930 },
4931 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
4932 &self.window,
4933 can_gc,
4934 ))),
4935 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
4936 &self.window,
4937 can_gc,
4938 ))),
4939 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
4940 &self.window,
4941 can_gc,
4942 ))),
4943 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
4944 self.window.upcast(),
4945 can_gc,
4946 ))),
4947 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
4948 &self.window,
4949 can_gc,
4950 ))),
4951 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
4952 &self.window,
4953 "".into(),
4954 can_gc,
4955 ))),
4956 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
4957 &self.window,
4958 &TouchList::new(&self.window, &[], can_gc),
4959 &TouchList::new(&self.window, &[], can_gc),
4960 &TouchList::new(&self.window, &[], can_gc),
4961 can_gc,
4962 ))),
4963 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
4964 &self.window,
4965 can_gc,
4966 ))),
4967 _ => Err(Error::NotSupported),
4968 }
4969 }
4970
4971 fn LastModified(&self) -> DOMString {
4973 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
4974 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
4980 }))
4981 }
4982
4983 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
4985 Range::new_with_doc(self, None, can_gc)
4986 }
4987
4988 fn CreateNodeIterator(
4990 &self,
4991 root: &Node,
4992 what_to_show: u32,
4993 filter: Option<Rc<NodeFilter>>,
4994 can_gc: CanGc,
4995 ) -> DomRoot<NodeIterator> {
4996 NodeIterator::new(self, root, what_to_show, filter, can_gc)
4997 }
4998
4999 fn CreateTreeWalker(
5001 &self,
5002 root: &Node,
5003 what_to_show: u32,
5004 filter: Option<Rc<NodeFilter>>,
5005 ) -> DomRoot<TreeWalker> {
5006 TreeWalker::new(self, root, what_to_show, filter)
5007 }
5008
5009 fn Title(&self) -> DOMString {
5011 self.title().unwrap_or_else(|| DOMString::from(""))
5012 }
5013
5014 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5016 let root = match self.GetDocumentElement() {
5017 Some(root) => root,
5018 None => return,
5019 };
5020
5021 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5022 let elem = root.upcast::<Node>().child_elements().find(|node| {
5023 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5024 });
5025 match elem {
5026 Some(elem) => DomRoot::upcast::<Node>(elem),
5027 None => {
5028 let name = QualName::new(None, ns!(svg), local_name!("title"));
5029 let elem = Element::create(
5030 name,
5031 None,
5032 self,
5033 ElementCreator::ScriptCreated,
5034 CustomElementCreationMode::Synchronous,
5035 None,
5036 can_gc,
5037 );
5038 let parent = root.upcast::<Node>();
5039 let child = elem.upcast::<Node>();
5040 parent
5041 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5042 .unwrap()
5043 },
5044 }
5045 } else if root.namespace() == &ns!(html) {
5046 let elem = root
5047 .upcast::<Node>()
5048 .traverse_preorder(ShadowIncluding::No)
5049 .find(|node| node.is::<HTMLTitleElement>());
5050 match elem {
5051 Some(elem) => elem,
5052 None => match self.GetHead() {
5053 Some(head) => {
5054 let name = QualName::new(None, ns!(html), local_name!("title"));
5055 let elem = Element::create(
5056 name,
5057 None,
5058 self,
5059 ElementCreator::ScriptCreated,
5060 CustomElementCreationMode::Synchronous,
5061 None,
5062 can_gc,
5063 );
5064 head.upcast::<Node>()
5065 .AppendChild(elem.upcast(), can_gc)
5066 .unwrap()
5067 },
5068 None => return,
5069 },
5070 }
5071 } else {
5072 return;
5073 };
5074
5075 node.set_text_content_for_element(Some(title), can_gc);
5076 }
5077
5078 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5080 self.get_html_element().and_then(|root| {
5081 root.upcast::<Node>()
5082 .children()
5083 .filter_map(DomRoot::downcast)
5084 .next()
5085 })
5086 }
5087
5088 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5090 self.current_script.get()
5091 }
5092
5093 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5095 self.get_html_element().and_then(|root| {
5096 let node = root.upcast::<Node>();
5097 node.children()
5098 .find(|child| {
5099 matches!(
5100 child.type_id(),
5101 NodeTypeId::Element(ElementTypeId::HTMLElement(
5102 HTMLElementTypeId::HTMLBodyElement,
5103 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5104 HTMLElementTypeId::HTMLFrameSetElement,
5105 ))
5106 )
5107 })
5108 .map(|node| DomRoot::downcast(node).unwrap())
5109 })
5110 }
5111
5112 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5114 let new_body = match new_body {
5116 Some(new_body) => new_body,
5117 None => return Err(Error::HierarchyRequest),
5118 };
5119
5120 let node = new_body.upcast::<Node>();
5121 match node.type_id() {
5122 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5123 NodeTypeId::Element(ElementTypeId::HTMLElement(
5124 HTMLElementTypeId::HTMLFrameSetElement,
5125 )) => {},
5126 _ => return Err(Error::HierarchyRequest),
5127 }
5128
5129 let old_body = self.GetBody();
5131 if old_body.as_deref() == Some(new_body) {
5132 return Ok(());
5133 }
5134
5135 match (self.GetDocumentElement(), &old_body) {
5136 (Some(ref root), Some(child)) => {
5138 let root = root.upcast::<Node>();
5139 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5140 .unwrap();
5141 },
5142
5143 (None, _) => return Err(Error::HierarchyRequest),
5145
5146 (Some(ref root), &None) => {
5148 let root = root.upcast::<Node>();
5149 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5150 },
5151 }
5152 Ok(())
5153 }
5154
5155 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5157 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5158 }
5159
5160 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5162 self.images.or_init(|| {
5163 HTMLCollection::new_with_filter_fn(
5164 &self.window,
5165 self.upcast(),
5166 |element, _| element.is::<HTMLImageElement>(),
5167 can_gc,
5168 )
5169 })
5170 }
5171
5172 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5174 self.embeds.or_init(|| {
5175 HTMLCollection::new_with_filter_fn(
5176 &self.window,
5177 self.upcast(),
5178 |element, _| element.is::<HTMLEmbedElement>(),
5179 can_gc,
5180 )
5181 })
5182 }
5183
5184 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5186 self.Embeds(can_gc)
5187 }
5188
5189 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5191 self.links.or_init(|| {
5192 HTMLCollection::new_with_filter_fn(
5193 &self.window,
5194 self.upcast(),
5195 |element, _| {
5196 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5197 element.has_attribute(&local_name!("href"))
5198 },
5199 can_gc,
5200 )
5201 })
5202 }
5203
5204 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5206 self.forms.or_init(|| {
5207 HTMLCollection::new_with_filter_fn(
5208 &self.window,
5209 self.upcast(),
5210 |element, _| element.is::<HTMLFormElement>(),
5211 can_gc,
5212 )
5213 })
5214 }
5215
5216 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5218 self.scripts.or_init(|| {
5219 HTMLCollection::new_with_filter_fn(
5220 &self.window,
5221 self.upcast(),
5222 |element, _| element.is::<HTMLScriptElement>(),
5223 can_gc,
5224 )
5225 })
5226 }
5227
5228 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5230 self.anchors.or_init(|| {
5231 HTMLCollection::new_with_filter_fn(
5232 &self.window,
5233 self.upcast(),
5234 |element, _| {
5235 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5236 },
5237 can_gc,
5238 )
5239 })
5240 }
5241
5242 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5244 self.applets
5245 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5246 }
5247
5248 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5250 if self.is_fully_active() {
5251 Some(self.window.Location())
5252 } else {
5253 None
5254 }
5255 }
5256
5257 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5259 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5260 }
5261
5262 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5264 self.upcast::<Node>().child_elements().next()
5265 }
5266
5267 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5269 self.upcast::<Node>()
5270 .rev_children()
5271 .filter_map(DomRoot::downcast)
5272 .next()
5273 }
5274
5275 fn ChildElementCount(&self) -> u32 {
5277 self.upcast::<Node>().child_elements().count() as u32
5278 }
5279
5280 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5282 self.upcast::<Node>().prepend(nodes, can_gc)
5283 }
5284
5285 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5287 self.upcast::<Node>().append(nodes, can_gc)
5288 }
5289
5290 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5292 self.upcast::<Node>().replace_children(nodes, can_gc)
5293 }
5294
5295 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5297 let root = self.upcast::<Node>();
5298 root.query_selector(selectors)
5299 }
5300
5301 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5303 let root = self.upcast::<Node>();
5304 root.query_selector_all(selectors)
5305 }
5306
5307 fn ReadyState(&self) -> DocumentReadyState {
5309 self.ready_state.get()
5310 }
5311
5312 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5314 if self.has_browsing_context {
5315 Some(DomRoot::from_ref(&*self.window))
5316 } else {
5317 None
5318 }
5319 }
5320
5321 fn GetCookie(&self) -> Fallible<DOMString> {
5323 if self.is_cookie_averse() {
5324 return Ok(DOMString::new());
5325 }
5326
5327 if !self.origin.is_tuple() {
5328 return Err(Error::Security);
5329 }
5330
5331 let url = self.url();
5332 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5333 let _ = self
5334 .window
5335 .as_global_scope()
5336 .resource_threads()
5337 .send(GetCookiesForUrl(url, tx, NonHTTP));
5338 let cookies = rx.recv().unwrap();
5339 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5340 }
5341
5342 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5344 if self.is_cookie_averse() {
5345 return Ok(());
5346 }
5347
5348 if !self.origin.is_tuple() {
5349 return Err(Error::Security);
5350 }
5351
5352 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5353 vec![cookie]
5354 } else {
5355 vec![]
5356 };
5357
5358 let _ = self
5359 .window
5360 .as_global_scope()
5361 .resource_threads()
5362 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5363 Ok(())
5364 }
5365
5366 fn BgColor(&self) -> DOMString {
5368 self.get_body_attribute(&local_name!("bgcolor"))
5369 }
5370
5371 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5373 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5374 }
5375
5376 fn FgColor(&self) -> DOMString {
5378 self.get_body_attribute(&local_name!("text"))
5379 }
5380
5381 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5383 self.set_body_attribute(&local_name!("text"), value, can_gc)
5384 }
5385
5386 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5388 if name.is_empty() {
5389 return None;
5390 }
5391 let name = Atom::from(name);
5392
5393 let elements_with_name = self.get_elements_with_name(&name);
5396 let name_iter = elements_with_name
5397 .iter()
5398 .filter(|elem| is_named_element_with_name_attribute(elem));
5399 let elements_with_id = self.get_elements_with_id(&name);
5400 let id_iter = elements_with_id
5401 .iter()
5402 .filter(|elem| is_named_element_with_id_attribute(elem));
5403 let mut elements = name_iter.chain(id_iter);
5404
5405 let first = elements.next()?;
5412 if elements.all(|other| first == other) {
5413 if let Some(nested_window_proxy) = first
5414 .downcast::<HTMLIFrameElement>()
5415 .and_then(|iframe| iframe.GetContentWindow())
5416 {
5417 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5418 }
5419
5420 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5422 }
5423
5424 #[derive(JSTraceable, MallocSizeOf)]
5427 struct DocumentNamedGetter {
5428 #[no_trace]
5429 name: Atom,
5430 }
5431 impl CollectionFilter for DocumentNamedGetter {
5432 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5433 let type_ = match elem.upcast::<Node>().type_id() {
5434 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5435 _ => return false,
5436 };
5437 match type_ {
5438 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5439 elem.get_name().as_ref() == Some(&self.name)
5440 },
5441 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5442 name == *self.name ||
5443 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5444 }),
5445 _ => false,
5449 }
5450 }
5451 }
5452 let collection = HTMLCollection::create(
5453 self.window(),
5454 self.upcast(),
5455 Box::new(DocumentNamedGetter { name }),
5456 can_gc,
5457 );
5458 Some(NamedPropertyValue::HTMLCollection(collection))
5459 }
5460
5461 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5463 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5464
5465 let name_map = self.name_map.borrow();
5466 for (name, elements) in &(name_map).0 {
5467 if name.is_empty() {
5468 continue;
5469 }
5470 let mut name_iter = elements
5471 .iter()
5472 .filter(|elem| is_named_element_with_name_attribute(elem));
5473 if let Some(first) = name_iter.next() {
5474 names_with_first_named_element_map.insert(name, first);
5475 }
5476 }
5477 let id_map = self.id_map.borrow();
5478 for (id, elements) in &(id_map).0 {
5479 if id.is_empty() {
5480 continue;
5481 }
5482 let mut id_iter = elements
5483 .iter()
5484 .filter(|elem| is_named_element_with_id_attribute(elem));
5485 if let Some(first) = id_iter.next() {
5486 match names_with_first_named_element_map.entry(id) {
5487 Vacant(entry) => drop(entry.insert(first)),
5488 Occupied(mut entry) => {
5489 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5490 *entry.get_mut() = first;
5491 }
5492 },
5493 }
5494 }
5495 }
5496
5497 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5498 names_with_first_named_element_map
5499 .iter()
5500 .map(|(k, v)| (*k, *v))
5501 .collect();
5502 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5503 if a.1 == b.1 {
5504 a.0.cmp(b.0)
5507 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5508 Ordering::Less
5509 } else {
5510 Ordering::Greater
5511 }
5512 });
5513
5514 names_with_first_named_element_vec
5515 .iter()
5516 .map(|(k, _v)| DOMString::from(&***k))
5517 .collect()
5518 }
5519
5520 fn Clear(&self) {
5522 }
5524
5525 fn CaptureEvents(&self) {
5527 }
5529
5530 fn ReleaseEvents(&self) {
5532 }
5534
5535 global_event_handlers!();
5537
5538 event_handler!(
5540 readystatechange,
5541 GetOnreadystatechange,
5542 SetOnreadystatechange
5543 );
5544
5545 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5547 self.document_or_shadow_root.element_from_point(
5548 x,
5549 y,
5550 self.GetDocumentElement(),
5551 self.has_browsing_context,
5552 )
5553 }
5554
5555 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5557 self.document_or_shadow_root.elements_from_point(
5558 x,
5559 y,
5560 self.GetDocumentElement(),
5561 self.has_browsing_context,
5562 )
5563 }
5564
5565 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5567 if self.quirks_mode() == QuirksMode::Quirks {
5569 if let Some(ref body) = self.GetBody() {
5571 let e = body.upcast::<Element>();
5572 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5576 return Some(DomRoot::from_ref(e));
5577 }
5578 }
5579
5580 return None;
5582 }
5583
5584 self.GetDocumentElement()
5587 }
5588
5589 fn Open(
5591 &self,
5592 _unused1: Option<DOMString>,
5593 _unused2: Option<DOMString>,
5594 can_gc: CanGc,
5595 ) -> Fallible<DomRoot<Document>> {
5596 if !self.is_html_document() {
5598 return Err(Error::InvalidState);
5599 }
5600
5601 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5603 return Err(Error::InvalidState);
5604 }
5605
5606 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5608
5609 if !self.origin.same_origin(&entry_responsible_document.origin) {
5611 return Err(Error::Security);
5612 }
5613
5614 if self
5616 .get_current_parser()
5617 .is_some_and(|parser| parser.is_active())
5618 {
5619 return Ok(DomRoot::from_ref(self));
5620 }
5621
5622 if self.is_prompting_or_unloading() {
5624 return Ok(DomRoot::from_ref(self));
5625 }
5626
5627 if self.active_parser_was_aborted.get() {
5629 return Ok(DomRoot::from_ref(self));
5630 }
5631
5632 self.window().set_navigation_start();
5636
5637 if self.has_browsing_context() {
5640 self.abort(can_gc);
5643 }
5644
5645 for node in self
5647 .upcast::<Node>()
5648 .traverse_preorder(ShadowIncluding::Yes)
5649 {
5650 node.upcast::<EventTarget>().remove_all_listeners();
5651 }
5652
5653 if self.window.Document() == DomRoot::from_ref(self) {
5655 self.window.upcast::<EventTarget>().remove_all_listeners();
5656 }
5657
5658 Node::replace_all(None, self.upcast::<Node>(), can_gc);
5660
5661 if self.is_fully_active() {
5668 let mut new_url = entry_responsible_document.url();
5670
5671 if entry_responsible_document != DomRoot::from_ref(self) {
5673 new_url.set_fragment(None);
5674 }
5675
5676 self.set_url(new_url);
5679 }
5680
5681 self.is_initial_about_blank.set(false);
5683
5684 self.set_quirks_mode(QuirksMode::NoQuirks);
5690
5691 let resource_threads = self.window.as_global_scope().resource_threads().clone();
5697 *self.loader.borrow_mut() =
5698 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
5699 ServoParser::parse_html_script_input(self, self.url());
5700
5701 self.ready_state.set(DocumentReadyState::Loading);
5707
5708 Ok(DomRoot::from_ref(self))
5710 }
5711
5712 fn Open_(
5714 &self,
5715 url: USVString,
5716 target: DOMString,
5717 features: DOMString,
5718 can_gc: CanGc,
5719 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
5720 self.browsing_context()
5721 .ok_or(Error::InvalidAccess)?
5722 .open(url, target, features, can_gc)
5723 }
5724
5725 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5727 self.write(text, false, "Document", "write", can_gc)
5730 }
5731
5732 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5734 self.write(text, true, "Document", "writeln", can_gc)
5737 }
5738
5739 fn Close(&self, can_gc: CanGc) -> ErrorResult {
5741 if !self.is_html_document() {
5742 return Err(Error::InvalidState);
5744 }
5745
5746 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5748 return Err(Error::InvalidState);
5749 }
5750
5751 let parser = match self.get_current_parser() {
5752 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
5753 _ => {
5754 return Ok(());
5756 },
5757 };
5758
5759 parser.close(can_gc);
5761
5762 Ok(())
5763 }
5764
5765 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
5767
5768 event_handler!(
5770 fullscreenchange,
5771 GetOnfullscreenchange,
5772 SetOnfullscreenchange
5773 );
5774
5775 fn FullscreenEnabled(&self) -> bool {
5777 self.get_allow_fullscreen()
5778 }
5779
5780 fn Fullscreen(&self) -> bool {
5782 self.fullscreen_element.get().is_some()
5783 }
5784
5785 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
5787 self.fullscreen_element.get()
5789 }
5790
5791 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
5793 self.exit_fullscreen(can_gc)
5794 }
5795
5796 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
5800 match self.media_controls.borrow().get(&*id) {
5801 Some(m) => Ok(DomRoot::from_ref(m)),
5802 None => Err(Error::InvalidAccess),
5803 }
5804 }
5805
5806 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
5808 if self.has_browsing_context {
5809 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
5810 } else {
5811 None
5812 }
5813 }
5814
5815 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
5817 self.fonts
5818 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
5819 }
5820
5821 fn Hidden(&self) -> bool {
5823 self.visibility_state.get() == DocumentVisibilityState::Hidden
5824 }
5825
5826 fn VisibilityState(&self) -> DocumentVisibilityState {
5828 self.visibility_state.get()
5829 }
5830
5831 fn CreateExpression(
5832 &self,
5833 expression: DOMString,
5834 resolver: Option<Rc<XPathNSResolver>>,
5835 can_gc: CanGc,
5836 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
5837 let global = self.global();
5838 let window = global.as_window();
5839 let evaluator = XPathEvaluator::new(window, None, can_gc);
5840 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateExpression(
5841 &*evaluator,
5842 expression,
5843 resolver,
5844 can_gc,
5845 )
5846 }
5847
5848 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
5849 let global = self.global();
5850 let window = global.as_window();
5851 let evaluator = XPathEvaluator::new(window, None, can_gc);
5852 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
5853 }
5854
5855 fn Evaluate(
5856 &self,
5857 expression: DOMString,
5858 context_node: &Node,
5859 resolver: Option<Rc<XPathNSResolver>>,
5860 type_: u16,
5861 result: Option<&super::types::XPathResult>,
5862 can_gc: CanGc,
5863 ) -> Fallible<DomRoot<super::types::XPathResult>> {
5864 let global = self.global();
5865 let window = global.as_window();
5866 let evaluator = XPathEvaluator::new(window, None, can_gc);
5867 XPathEvaluatorMethods::<crate::DomTypeHolder>::Evaluate(
5868 &*evaluator,
5869 expression,
5870 context_node,
5871 resolver,
5872 type_,
5873 result,
5874 can_gc,
5875 )
5876 }
5877
5878 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
5880 self.adopted_stylesheets_frozen_types.get_or_init(
5881 || {
5882 self.adopted_stylesheets
5883 .borrow()
5884 .clone()
5885 .iter()
5886 .map(|sheet| sheet.as_rooted())
5887 .collect()
5888 },
5889 context,
5890 retval,
5891 can_gc,
5892 );
5893 }
5894
5895 fn SetAdoptedStyleSheets(&self, context: JSContext, val: HandleValue) -> ErrorResult {
5897 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
5898 context,
5899 self.adopted_stylesheets.borrow_mut().as_mut(),
5900 val,
5901 &StyleSheetListOwner::Document(Dom::from_ref(self)),
5902 );
5903
5904 if result.is_ok() {
5906 self.adopted_stylesheets_frozen_types.clear()
5907 }
5908
5909 result
5910 }
5911}
5912
5913fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
5914 if marker.get().is_none() {
5915 marker.set(Some(CrossProcessInstant::now()))
5916 }
5917}
5918
5919pub(crate) fn determine_policy_for_token(token: &str) -> ReferrerPolicy {
5921 match_ignore_ascii_case! { token,
5922 "never" | "no-referrer" => ReferrerPolicy::NoReferrer,
5923 "no-referrer-when-downgrade" => ReferrerPolicy::NoReferrerWhenDowngrade,
5924 "origin" => ReferrerPolicy::Origin,
5925 "same-origin" => ReferrerPolicy::SameOrigin,
5926 "strict-origin" => ReferrerPolicy::StrictOrigin,
5927 "default" | "strict-origin-when-cross-origin" => ReferrerPolicy::StrictOriginWhenCrossOrigin,
5928 "origin-when-cross-origin" => ReferrerPolicy::OriginWhenCrossOrigin,
5929 "always" | "unsafe-url" => ReferrerPolicy::UnsafeUrl,
5930 _ => ReferrerPolicy::EmptyString,
5931 }
5932}
5933
5934#[derive(Clone, Copy, PartialEq)]
5936pub(crate) enum FocusType {
5937 Element, Parent, }
5940
5941#[derive(Clone, Copy, PartialEq)]
5943pub enum FocusInitiator {
5944 Local,
5947 Remote,
5950}
5951
5952pub(crate) enum FocusEventType {
5954 Focus, Blur, }
5957
5958#[derive(JSTraceable, MallocSizeOf)]
5959pub(crate) enum AnimationFrameCallback {
5960 DevtoolsFramerateTick {
5961 actor_name: String,
5962 },
5963 FrameRequestCallback {
5964 #[ignore_malloc_size_of = "Rc is hard"]
5965 callback: Rc<FrameRequestCallback>,
5966 },
5967}
5968
5969impl AnimationFrameCallback {
5970 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
5971 match *self {
5972 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
5973 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
5974 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
5975 devtools_sender.send(msg).unwrap();
5976 },
5977 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
5978 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
5981 },
5982 }
5983 }
5984}
5985
5986#[derive(Default, JSTraceable, MallocSizeOf)]
5987#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
5988struct PendingInOrderScriptVec {
5989 scripts: DomRefCell<VecDeque<PendingScript>>,
5990}
5991
5992impl PendingInOrderScriptVec {
5993 fn is_empty(&self) -> bool {
5994 self.scripts.borrow().is_empty()
5995 }
5996
5997 fn push(&self, element: &HTMLScriptElement) {
5998 self.scripts
5999 .borrow_mut()
6000 .push_back(PendingScript::new(element));
6001 }
6002
6003 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6004 let mut scripts = self.scripts.borrow_mut();
6005 let entry = scripts
6006 .iter_mut()
6007 .find(|entry| &*entry.element == element)
6008 .unwrap();
6009 entry.loaded(result);
6010 }
6011
6012 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6013 let mut scripts = self.scripts.borrow_mut();
6014 let pair = scripts.front_mut()?.take_result()?;
6015 scripts.pop_front();
6016 Some(pair)
6017 }
6018
6019 fn clear(&self) {
6020 *self.scripts.borrow_mut() = Default::default();
6021 }
6022}
6023
6024#[derive(JSTraceable, MallocSizeOf)]
6025#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6026struct PendingScript {
6027 element: Dom<HTMLScriptElement>,
6028 load: Option<ScriptResult>,
6030}
6031
6032impl PendingScript {
6033 fn new(element: &HTMLScriptElement) -> Self {
6034 Self {
6035 element: Dom::from_ref(element),
6036 load: None,
6037 }
6038 }
6039
6040 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6041 Self {
6042 element: Dom::from_ref(element),
6043 load,
6044 }
6045 }
6046
6047 fn loaded(&mut self, result: ScriptResult) {
6048 assert!(self.load.is_none());
6049 self.load = Some(result);
6050 }
6051
6052 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6053 self.load
6054 .take()
6055 .map(|result| (DomRoot::from_ref(&*self.element), result))
6056 }
6057}
6058
6059fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6060 let type_ = match elem.upcast::<Node>().type_id() {
6061 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6062 _ => return false,
6063 };
6064 match type_ {
6065 HTMLElementTypeId::HTMLFormElement |
6066 HTMLElementTypeId::HTMLIFrameElement |
6067 HTMLElementTypeId::HTMLImageElement => true,
6068 _ => false,
6072 }
6073}
6074
6075fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6076 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6080}
6081
6082impl DocumentHelpers for Document {
6083 fn ensure_safe_to_run_script_or_layout(&self) {
6084 Document::ensure_safe_to_run_script_or_layout(self)
6085 }
6086}