1use std::cell::{Cell, RefCell};
6use std::cmp::Ordering;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::default::Default;
10use std::rc::Rc;
11use std::str::FromStr;
12use std::sync::{LazyLock, Mutex};
13use std::time::Duration;
14
15use base::cross_process_instant::CrossProcessInstant;
16use base::id::WebViewId;
17use base::{Epoch, IpcSend, generic_channel};
18use bitflags::bitflags;
19use chrono::Local;
20use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
21use content_security_policy::sandboxing_directive::SandboxingFlagSet;
22use content_security_policy::{CspList, PolicyDisposition};
23use cookie::Cookie;
24use data_url::mime::Mime;
25use devtools_traits::ScriptToDevtoolsControlMsg;
26use dom_struct::dom_struct;
27use embedder_traits::{
28 AllowOrDeny, AnimationState, CustomHandlersAutomationMode, EmbedderMsg, FocusSequenceNumber,
29 Image, LoadStatus,
30};
31use encoding_rs::{Encoding, UTF_8};
32use fonts::WebFontDocumentContext;
33use html5ever::{LocalName, Namespace, QualName, local_name, ns};
34use hyper_serde::Serde;
35use js::rust::{HandleObject, HandleValue, MutableHandleValue};
36use layout_api::{
37 PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
38 TrustedNodeAddress,
39};
40use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
41use net_traits::CookieSource::NonHTTP;
42use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
43use net_traits::ReferrerPolicy;
44use net_traits::policy_container::PolicyContainer;
45use net_traits::pub_domains::is_pub_domain;
46use net_traits::request::{InsecureRequestsPolicy, PreloadedResources, RequestBuilder};
47use net_traits::response::HttpsState;
48use percent_encoding::percent_decode;
49use profile_traits::ipc as profile_ipc;
50use profile_traits::time::TimerMetadataFrameType;
51use regex::bytes::Regex;
52use rustc_hash::{FxBuildHasher, FxHashMap};
53use script_bindings::interfaces::DocumentHelpers;
54use script_bindings::script_runtime::JSContext;
55use script_traits::{DocumentActivity, ProgressiveWebMetricType};
56use servo_arc::Arc;
57use servo_config::pref;
58use servo_media::{ClientContextId, ServoMedia};
59use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
60use style::attr::AttrValue;
61use style::context::QuirksMode;
62use style::invalidation::element::restyle_hints::RestyleHint;
63use style::selector_parser::Snapshot;
64use style::shared_lock::SharedRwLock as StyleSharedRwLock;
65use style::str::{split_html_space_chars, str_join};
66use style::stylesheet_set::DocumentStylesheetSet;
67use style::stylesheets::{Origin, OriginSet, Stylesheet};
68use stylo_atoms::Atom;
69use url::Host;
70
71use crate::animation_timeline::AnimationTimeline;
72use crate::animations::Animations;
73use crate::document_loader::{DocumentLoader, LoadType};
74use crate::dom::attr::Attr;
75use crate::dom::beforeunloadevent::BeforeUnloadEvent;
76use crate::dom::bindings::callback::ExceptionHandling;
77use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
78use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEvent_Binding::BeforeUnloadEventMethods;
79use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
80 DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
81};
82use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPosition;
83use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
84use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
85use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
86use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
87use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
88use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
89use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
90use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionName;
91use crate::dom::bindings::codegen::Bindings::WindowBinding::{
92 FrameRequestCallback, ScrollBehavior, WindowMethods,
93};
94use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
95use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
96use crate::dom::bindings::codegen::UnionTypes::{
97 NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
98};
99use crate::dom::bindings::domname::{
100 self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
101};
102use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
103use crate::dom::bindings::frozenarray::CachedFrozenArray;
104use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
105use crate::dom::bindings::num::Finite;
106use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
107use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
108use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
109use crate::dom::bindings::str::{DOMString, USVString};
110use crate::dom::bindings::trace::{HashMapTracedValues, NoTrace};
111use crate::dom::bindings::weakref::DOMTracker;
112use crate::dom::bindings::xmlname::matches_name_production;
113use crate::dom::cdatasection::CDATASection;
114use crate::dom::comment::Comment;
115use crate::dom::compositionevent::CompositionEvent;
116use crate::dom::css::cssstylesheet::CSSStyleSheet;
117use crate::dom::css::fontfaceset::FontFaceSet;
118use crate::dom::css::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
119use crate::dom::customelementregistry::{CustomElementDefinition, CustomElementReactionStack};
120use crate::dom::customevent::CustomEvent;
121use crate::dom::document_embedder_controls::DocumentEmbedderControls;
122use crate::dom::document_event_handler::DocumentEventHandler;
123use crate::dom::documentfragment::DocumentFragment;
124use crate::dom::documentorshadowroot::{
125 DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
126};
127use crate::dom::documenttype::DocumentType;
128use crate::dom::domimplementation::DOMImplementation;
129use crate::dom::element::{
130 CustomElementCreationMode, Element, ElementCreator, ElementPerformFullscreenEnter,
131 ElementPerformFullscreenExit,
132};
133use crate::dom::event::{Event, EventBubbles, EventCancelable};
134use crate::dom::eventtarget::EventTarget;
135use crate::dom::focusevent::FocusEvent;
136use crate::dom::globalscope::GlobalScope;
137use crate::dom::hashchangeevent::HashChangeEvent;
138use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
139use crate::dom::html::htmlareaelement::HTMLAreaElement;
140use crate::dom::html::htmlbaseelement::HTMLBaseElement;
141use crate::dom::html::htmlcollection::{CollectionFilter, HTMLCollection};
142use crate::dom::html::htmlelement::HTMLElement;
143use crate::dom::html::htmlembedelement::HTMLEmbedElement;
144use crate::dom::html::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement};
145use crate::dom::html::htmlheadelement::HTMLHeadElement;
146use crate::dom::html::htmlhtmlelement::HTMLHtmlElement;
147use crate::dom::html::htmliframeelement::HTMLIFrameElement;
148use crate::dom::html::htmlimageelement::HTMLImageElement;
149use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
150use crate::dom::html::htmltitleelement::HTMLTitleElement;
151use crate::dom::htmldetailselement::DetailsNameGroups;
152use crate::dom::intersectionobserver::IntersectionObserver;
153use crate::dom::keyboardevent::KeyboardEvent;
154use crate::dom::largestcontentfulpaint::LargestContentfulPaint;
155use crate::dom::location::{Location, NavigationType};
156use crate::dom::messageevent::MessageEvent;
157use crate::dom::mouseevent::MouseEvent;
158use crate::dom::node::{
159 CloneChildrenFlag, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding,
160};
161use crate::dom::nodeiterator::NodeIterator;
162use crate::dom::nodelist::NodeList;
163use crate::dom::pagetransitionevent::PageTransitionEvent;
164use crate::dom::performance::performanceentry::PerformanceEntry;
165use crate::dom::performance::performancepainttiming::PerformancePaintTiming;
166use crate::dom::processinginstruction::ProcessingInstruction;
167use crate::dom::promise::Promise;
168use crate::dom::range::Range;
169use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
170use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement, ScrollingBox};
171use crate::dom::selection::Selection;
172use crate::dom::servoparser::ServoParser;
173use crate::dom::shadowroot::ShadowRoot;
174use crate::dom::storageevent::StorageEvent;
175use crate::dom::text::Text;
176use crate::dom::touchevent::TouchEvent as DomTouchEvent;
177use crate::dom::touchlist::TouchList;
178use crate::dom::treewalker::TreeWalker;
179use crate::dom::trustedhtml::TrustedHTML;
180use crate::dom::types::{HTMLCanvasElement, VisibilityStateEntry};
181use crate::dom::uievent::UIEvent;
182use crate::dom::virtualmethods::vtable_for;
183use crate::dom::websocket::WebSocket;
184use crate::dom::window::Window;
185use crate::dom::windowproxy::WindowProxy;
186use crate::dom::xpathevaluator::XPathEvaluator;
187use crate::dom::xpathexpression::XPathExpression;
188use crate::fetch::FetchCanceller;
189use crate::iframe_collection::IFrameCollection;
190use crate::image_animation::ImageAnimationManager;
191use crate::messaging::{CommonScriptMsg, MainThreadScriptMsg};
192use crate::mime::{APPLICATION, CHARSET};
193use crate::network_listener::{FetchResponseListener, NetworkListener};
194use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
195use crate::script_runtime::{CanGc, ScriptThreadEventCategory};
196use crate::script_thread::ScriptThread;
197use crate::stylesheet_set::StylesheetSetRef;
198use crate::task::NonSendTaskBox;
199use crate::task_source::TaskSourceName;
200use crate::timers::OneshotTimerCallback;
201use crate::xpath::parse_expression;
202
203#[derive(Clone, Copy, PartialEq)]
204pub(crate) enum FireMouseEventType {
205 Move,
206 Over,
207 Out,
208 Enter,
209 Leave,
210}
211
212impl FireMouseEventType {
213 pub(crate) fn as_str(&self) -> &str {
214 match *self {
215 FireMouseEventType::Move => "mousemove",
216 FireMouseEventType::Over => "mouseover",
217 FireMouseEventType::Out => "mouseout",
218 FireMouseEventType::Enter => "mouseenter",
219 FireMouseEventType::Leave => "mouseleave",
220 }
221 }
222}
223
224#[derive(JSTraceable, MallocSizeOf)]
225pub(crate) struct RefreshRedirectDue {
226 #[no_trace]
227 pub(crate) url: ServoUrl,
228 #[ignore_malloc_size_of = "non-owning"]
229 pub(crate) window: DomRoot<Window>,
230}
231impl RefreshRedirectDue {
232 pub(crate) fn invoke(self, can_gc: CanGc) {
233 self.window.Location().navigate(
234 self.url.clone(),
235 NavigationHistoryBehavior::Replace,
236 NavigationType::DeclarativeRefresh,
237 can_gc,
238 );
239 }
240}
241
242#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
243pub(crate) enum IsHTMLDocument {
244 HTMLDocument,
245 NonHTMLDocument,
246}
247
248#[derive(JSTraceable, MallocSizeOf)]
249#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
250struct FocusTransaction {
251 element: Option<Dom<Element>>,
253 has_focus: bool,
255 focus_options: FocusOptions,
257}
258
259#[derive(JSTraceable, MallocSizeOf)]
261pub(crate) enum DeclarativeRefresh {
262 PendingLoad {
263 #[no_trace]
264 url: ServoUrl,
265 time: u64,
266 },
267 CreatedAfterLoad,
268}
269
270#[derive(Clone, Copy, Debug, Default, JSTraceable, MallocSizeOf)]
273pub(crate) struct RenderingUpdateReason(u8);
274
275bitflags! {
276 impl RenderingUpdateReason: u8 {
277 const ResizeObserverStartedObservingTarget = 1 << 0;
280 const IntersectionObserverStartedObservingTarget = 1 << 1;
283 const FontReadyPromiseFulfilled = 1 << 2;
287 }
288}
289
290#[dom_struct]
292pub(crate) struct Document {
293 node: Node,
294 document_or_shadow_root: DocumentOrShadowRoot,
295 window: Dom<Window>,
296 implementation: MutNullableDom<DOMImplementation>,
297 #[ignore_malloc_size_of = "type from external crate"]
298 #[no_trace]
299 content_type: Mime,
300 last_modified: Option<String>,
301 #[no_trace]
302 encoding: Cell<&'static Encoding>,
303 has_browsing_context: bool,
304 is_html_document: bool,
305 #[no_trace]
306 activity: Cell<DocumentActivity>,
307 #[no_trace]
308 url: DomRefCell<ServoUrl>,
309 #[ignore_malloc_size_of = "defined in selectors"]
310 #[no_trace]
311 quirks_mode: Cell<QuirksMode>,
312 event_handler: DocumentEventHandler,
314 embedder_controls: DocumentEmbedderControls,
316 id_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
319 name_map: DomRefCell<HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>>,
320 tag_map: DomRefCell<HashMapTracedValues<LocalName, Dom<HTMLCollection>, FxBuildHasher>>,
321 tagns_map: DomRefCell<HashMapTracedValues<QualName, Dom<HTMLCollection>, FxBuildHasher>>,
322 classes_map: DomRefCell<HashMapTracedValues<Vec<Atom>, Dom<HTMLCollection>>>,
323 images: MutNullableDom<HTMLCollection>,
324 embeds: MutNullableDom<HTMLCollection>,
325 links: MutNullableDom<HTMLCollection>,
326 forms: MutNullableDom<HTMLCollection>,
327 scripts: MutNullableDom<HTMLCollection>,
328 anchors: MutNullableDom<HTMLCollection>,
329 applets: MutNullableDom<HTMLCollection>,
330 iframes: RefCell<IFrameCollection>,
332 #[no_trace]
335 style_shared_lock: StyleSharedRwLock,
336 #[custom_trace]
338 stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
339 stylesheet_list: MutNullableDom<StyleSheetList>,
340 ready_state: Cell<DocumentReadyState>,
341 domcontentloaded_dispatched: Cell<bool>,
343 focus_transaction: DomRefCell<Option<FocusTransaction>>,
345 focused: MutNullableDom<Element>,
347 #[no_trace]
349 focus_sequence: Cell<FocusSequenceNumber>,
350 has_focus: Cell<bool>,
354 current_script: MutNullableDom<HTMLScriptElement>,
356 pending_parsing_blocking_script: DomRefCell<Option<PendingScript>>,
358 script_blocking_stylesheets_count: Cell<u32>,
360 render_blocking_element_count: Cell<u32>,
363 deferred_scripts: PendingInOrderScriptVec,
365 asap_in_order_scripts_list: PendingInOrderScriptVec,
367 asap_scripts_set: DomRefCell<Vec<Dom<HTMLScriptElement>>>,
369 animation_frame_ident: Cell<u32>,
372 animation_frame_list: DomRefCell<VecDeque<(u32, Option<AnimationFrameCallback>)>>,
375 running_animation_callbacks: Cell<bool>,
380 loader: DomRefCell<DocumentLoader>,
382 current_parser: MutNullableDom<ServoParser>,
384 base_element: MutNullableDom<HTMLBaseElement>,
386 appropriate_template_contents_owner_document: MutNullableDom<Document>,
389 pending_restyles: DomRefCell<FxHashMap<Dom<Element>, NoTrace<PendingRestyle>>>,
392 #[no_trace]
396 needs_restyle: Cell<RestyleReason>,
397 #[no_trace]
400 dom_interactive: Cell<Option<CrossProcessInstant>>,
401 #[no_trace]
402 dom_content_loaded_event_start: Cell<Option<CrossProcessInstant>>,
403 #[no_trace]
404 dom_content_loaded_event_end: Cell<Option<CrossProcessInstant>>,
405 #[no_trace]
406 dom_complete: Cell<Option<CrossProcessInstant>>,
407 #[no_trace]
408 top_level_dom_complete: Cell<Option<CrossProcessInstant>>,
409 #[no_trace]
410 load_event_start: Cell<Option<CrossProcessInstant>>,
411 #[no_trace]
412 load_event_end: Cell<Option<CrossProcessInstant>>,
413 #[no_trace]
414 unload_event_start: Cell<Option<CrossProcessInstant>>,
415 #[no_trace]
416 unload_event_end: Cell<Option<CrossProcessInstant>>,
417 #[no_trace]
419 https_state: Cell<HttpsState>,
420 #[no_trace]
422 origin: MutableOrigin,
423 referrer: Option<String>,
425 target_element: MutNullableDom<Element>,
427 #[no_trace]
429 policy_container: DomRefCell<PolicyContainer>,
430 #[no_trace]
432 #[conditional_malloc_size_of]
433 preloaded_resources: PreloadedResources,
434 ignore_destructive_writes_counter: Cell<u32>,
436 ignore_opens_during_unload_counter: Cell<u32>,
438 spurious_animation_frames: Cell<u8>,
442
443 dom_count: Cell<u32>,
449 fullscreen_element: MutNullableDom<Element>,
451 form_id_listener_map:
458 DomRefCell<HashMapTracedValues<Atom, HashSet<Dom<Element>>, FxBuildHasher>>,
459 #[no_trace]
460 interactive_time: DomRefCell<ProgressiveWebMetrics>,
461 #[no_trace]
462 tti_window: DomRefCell<InteractiveWindow>,
463 canceller: FetchCanceller,
465 throw_on_dynamic_markup_insertion_counter: Cell<u64>,
467 page_showing: Cell<bool>,
469 salvageable: Cell<bool>,
471 active_parser_was_aborted: Cell<bool>,
473 fired_unload: Cell<bool>,
475 responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
477 redirect_count: Cell<u16>,
479 script_and_layout_blockers: Cell<u32>,
481 #[ignore_malloc_size_of = "Measuring trait objects is hard"]
483 delayed_tasks: DomRefCell<Vec<Box<dyn NonSendTaskBox>>>,
484 completely_loaded: Cell<bool>,
486 shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>,
488 shadow_roots_styles_changed: Cell<bool>,
490 media_controls: DomRefCell<HashMap<String, Dom<ShadowRoot>>>,
496 dirty_canvases: DomRefCell<Vec<Dom<HTMLCanvasElement>>>,
499 has_pending_animated_image_update: Cell<bool>,
501 selection: MutNullableDom<Selection>,
503 animation_timeline: DomRefCell<AnimationTimeline>,
506 animations: Animations,
508 image_animation_manager: DomRefCell<ImageAnimationManager>,
510 dirty_root: MutNullableDom<Element>,
512 declarative_refresh: DomRefCell<Option<DeclarativeRefresh>>,
514 resize_observers: DomRefCell<Vec<Dom<ResizeObserver>>>,
523 fonts: MutNullableDom<FontFaceSet>,
526 visibility_state: Cell<DocumentVisibilityState>,
528 status_code: Option<u16>,
530 is_initial_about_blank: Cell<bool>,
532 allow_declarative_shadow_roots: Cell<bool>,
534 #[no_trace]
536 inherited_insecure_requests_policy: Cell<Option<InsecureRequestsPolicy>>,
537 has_trustworthy_ancestor_origin: Cell<bool>,
539 intersection_observer_task_queued: Cell<bool>,
541 intersection_observers: DomRefCell<Vec<Dom<IntersectionObserver>>>,
553 highlighted_dom_node: MutNullableDom<Node>,
555 adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
558 #[ignore_malloc_size_of = "mozjs"]
560 adopted_stylesheets_frozen_types: CachedFrozenArray,
561 pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
563 rendering_update_reasons: Cell<RenderingUpdateReason>,
565 waiting_on_canvas_image_updates: Cell<bool>,
569 #[no_trace]
577 current_rendering_epoch: Cell<Epoch>,
578 #[conditional_malloc_size_of]
580 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
581 #[no_trace]
582 active_sandboxing_flag_set: Cell<SandboxingFlagSet>,
584 #[no_trace]
585 creation_sandboxing_flag_set: Cell<SandboxingFlagSet>,
592 #[no_trace]
594 #[ignore_malloc_size_of = "TODO: unimplemented on Image"]
595 favicon: RefCell<Option<Image>>,
596
597 websockets: DOMTracker<WebSocket>,
599
600 details_name_groups: DomRefCell<Option<DetailsNameGroups>>,
602
603 #[no_trace]
605 protocol_handler_automation_mode: RefCell<CustomHandlersAutomationMode>,
606
607 layout_animations_test_enabled: bool,
609}
610
611impl Document {
612 fn unloading_cleanup_steps(&self) {
614 if self.close_outstanding_websockets() {
617 self.salvageable.set(false);
619 }
620
621 if !self.salvageable.get() {
626 let global_scope = self.window.as_global_scope();
627
628 global_scope.close_event_sources();
630
631 let msg = ScriptToConstellationMessage::DiscardDocument;
636 let _ = global_scope.script_to_constellation_chan().send(msg);
637 }
638 }
639
640 pub(crate) fn track_websocket(&self, websocket: &WebSocket) {
641 self.websockets.track(websocket);
642 }
643
644 fn close_outstanding_websockets(&self) -> bool {
645 let mut closed_any_websocket = false;
646 self.websockets.for_each(|websocket: DomRoot<WebSocket>| {
647 if websocket.make_disappear() {
648 closed_any_websocket = true;
649 }
650 });
651 closed_any_websocket
652 }
653
654 pub(crate) fn note_node_with_dirty_descendants(&self, node: &Node) {
655 debug_assert!(*node.owner_doc() == *self);
656 if !node.is_connected() {
657 return;
658 }
659
660 let parent = match node.parent_in_flat_tree() {
661 Some(parent) => parent,
662 None => {
663 let document_element = match self.GetDocumentElement() {
666 Some(element) => element,
667 None => return,
668 };
669 if let Some(dirty_root) = self.dirty_root.get() {
670 for ancestor in dirty_root
673 .upcast::<Node>()
674 .inclusive_ancestors_in_flat_tree()
675 {
676 if ancestor.is::<Element>() {
677 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
678 }
679 }
680 }
681 self.dirty_root.set(Some(&document_element));
682 return;
683 },
684 };
685
686 if parent.is::<Element>() {
687 if !parent.is_styled() {
688 return;
689 }
690
691 if parent.is_display_none() {
692 return;
693 }
694 }
695
696 let element_parent: DomRoot<Element>;
697 let element = match node.downcast::<Element>() {
698 Some(element) => element,
699 None => {
700 match DomRoot::downcast::<Element>(parent) {
703 Some(parent) => {
704 element_parent = parent;
705 &element_parent
706 },
707 None => {
708 return;
712 },
713 }
714 },
715 };
716
717 let dirty_root = match self.dirty_root.get() {
718 Some(root) if root.is_connected() => root,
719 _ => {
720 element
721 .upcast::<Node>()
722 .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
723 self.dirty_root.set(Some(element));
724 return;
725 },
726 };
727
728 for ancestor in element.upcast::<Node>().inclusive_ancestors_in_flat_tree() {
729 if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
730 return;
731 }
732
733 if ancestor.is::<Element>() {
734 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
735 }
736 }
737
738 let new_dirty_root = element
739 .upcast::<Node>()
740 .common_ancestor_in_flat_tree(dirty_root.upcast())
741 .expect("Couldn't find common ancestor");
742
743 let mut has_dirty_descendants = true;
744 for ancestor in dirty_root
745 .upcast::<Node>()
746 .inclusive_ancestors_in_flat_tree()
747 {
748 ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
749 has_dirty_descendants &= *ancestor != *new_dirty_root;
750 }
751
752 self.dirty_root
753 .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
754 }
755
756 pub(crate) fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
757 self.dirty_root.take()
758 }
759
760 #[inline]
761 pub(crate) fn loader(&self) -> Ref<'_, DocumentLoader> {
762 self.loader.borrow()
763 }
764
765 #[inline]
766 pub(crate) fn loader_mut(&self) -> RefMut<'_, DocumentLoader> {
767 self.loader.borrow_mut()
768 }
769
770 #[inline]
771 pub(crate) fn has_browsing_context(&self) -> bool {
772 self.has_browsing_context
773 }
774
775 #[inline]
777 pub(crate) fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> {
778 if self.has_browsing_context {
779 self.window.undiscarded_window_proxy()
780 } else {
781 None
782 }
783 }
784
785 pub(crate) fn webview_id(&self) -> WebViewId {
786 self.window.webview_id()
787 }
788
789 #[inline]
790 pub(crate) fn window(&self) -> &Window {
791 &self.window
792 }
793
794 #[inline]
795 pub(crate) fn is_html_document(&self) -> bool {
796 self.is_html_document
797 }
798
799 pub(crate) fn is_xhtml_document(&self) -> bool {
800 self.content_type.matches(APPLICATION, "xhtml+xml")
801 }
802
803 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
804 self.https_state.set(https_state);
805 }
806
807 pub(crate) fn is_fully_active(&self) -> bool {
808 self.activity.get() == DocumentActivity::FullyActive
809 }
810
811 pub(crate) fn is_active(&self) -> bool {
812 self.activity.get() != DocumentActivity::Inactive
813 }
814
815 #[inline]
816 pub(crate) fn current_rendering_epoch(&self) -> Epoch {
817 self.current_rendering_epoch.get()
818 }
819
820 pub(crate) fn set_activity(&self, activity: DocumentActivity, can_gc: CanGc) {
821 assert!(self.has_browsing_context);
823 if activity == self.activity.get() {
824 return;
825 }
826
827 self.activity.set(activity);
829 let media = ServoMedia::get();
830 let pipeline_id = self.window().pipeline_id();
831 let client_context_id =
832 ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
833
834 if activity != DocumentActivity::FullyActive {
835 self.window().suspend(can_gc);
836 media.suspend(&client_context_id);
837 return;
838 }
839
840 self.title_changed();
841 self.notify_embedder_favicon();
842 self.dirty_all_nodes();
843 self.window().resume(can_gc);
844 media.resume(&client_context_id);
845
846 if self.ready_state.get() != DocumentReadyState::Complete {
847 return;
848 }
849
850 let document = Trusted::new(self);
854 self.owner_global()
855 .task_manager()
856 .dom_manipulation_task_source()
857 .queue(task!(fire_pageshow_event: move || {
858 let document = document.root();
859 let window = document.window();
860 if document.page_showing.get() {
862 return;
863 }
864 document.page_showing.set(true);
866 document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
868 let event = PageTransitionEvent::new(
871 window,
872 atom!("pageshow"),
873 false, false, true, CanGc::note(),
877 );
878 let event = event.upcast::<Event>();
879 event.set_trusted(true);
880 window.dispatch_event_with_target_override(event, CanGc::note());
881 }))
882 }
883
884 pub(crate) fn origin(&self) -> &MutableOrigin {
885 &self.origin
886 }
887
888 pub(crate) fn set_protocol_handler_automation_mode(&self, mode: CustomHandlersAutomationMode) {
889 *self.protocol_handler_automation_mode.borrow_mut() = mode;
890 }
891
892 pub(crate) fn url(&self) -> ServoUrl {
894 self.url.borrow().clone()
895 }
896
897 pub(crate) fn set_url(&self, url: ServoUrl) {
898 *self.url.borrow_mut() = url;
899 }
900
901 pub(crate) fn fallback_base_url(&self) -> ServoUrl {
903 let document_url = self.url();
905 if document_url.as_str() == "about:srcdoc" {
906 let base_url = self
907 .browsing_context()
908 .and_then(|browsing_context| browsing_context.creator_base_url());
909
910 if base_url.is_none() {
912 error!("about:srcdoc page should always have a creator base URL");
913 }
914
915 return base_url.unwrap_or(document_url);
917 }
918
919 if document_url.matches_about_blank() {
922 return self
923 .browsing_context()
924 .and_then(|browsing_context| browsing_context.creator_base_url())
925 .unwrap_or(document_url);
926 }
927
928 document_url
930 }
931
932 pub(crate) fn base_url(&self) -> ServoUrl {
934 match self.base_element() {
935 None => self.fallback_base_url(),
937 Some(base) => base.frozen_base_url(),
939 }
940 }
941
942 pub(crate) fn add_restyle_reason(&self, reason: RestyleReason) {
943 self.needs_restyle.set(self.needs_restyle.get() | reason)
944 }
945
946 pub(crate) fn clear_restyle_reasons(&self) {
947 self.needs_restyle.set(RestyleReason::empty());
948 }
949
950 pub(crate) fn restyle_reason(&self) -> RestyleReason {
951 let mut condition = self.needs_restyle.get();
952 if self.stylesheets.borrow().has_changed() {
953 condition.insert(RestyleReason::StylesheetsChanged);
954 }
955
956 if let Some(root) = self.GetDocumentElement() {
960 if root.upcast::<Node>().has_dirty_descendants() {
961 condition.insert(RestyleReason::DOMChanged);
962 }
963 }
964
965 if !self.pending_restyles.borrow().is_empty() {
966 condition.insert(RestyleReason::PendingRestyles);
967 }
968
969 condition
970 }
971
972 pub(crate) fn base_element(&self) -> Option<DomRoot<HTMLBaseElement>> {
974 self.base_element.get()
975 }
976
977 pub(crate) fn refresh_base_element(&self) {
980 let base = self
981 .upcast::<Node>()
982 .traverse_preorder(ShadowIncluding::No)
983 .filter_map(DomRoot::downcast::<HTMLBaseElement>)
984 .find(|element| {
985 element
986 .upcast::<Element>()
987 .has_attribute(&local_name!("href"))
988 });
989 self.base_element.set(base.as_deref());
990 }
991
992 pub(crate) fn dom_count(&self) -> u32 {
993 self.dom_count.get()
994 }
995
996 pub(crate) fn increment_dom_count(&self) {
1000 self.dom_count.set(self.dom_count.get() + 1);
1001 }
1002
1003 pub(crate) fn decrement_dom_count(&self) {
1005 self.dom_count.set(self.dom_count.get() - 1);
1006 }
1007
1008 pub(crate) fn quirks_mode(&self) -> QuirksMode {
1009 self.quirks_mode.get()
1010 }
1011
1012 pub(crate) fn set_quirks_mode(&self, new_mode: QuirksMode) {
1013 let old_mode = self.quirks_mode.replace(new_mode);
1014
1015 if old_mode != new_mode {
1016 self.window.layout_mut().set_quirks_mode(new_mode);
1017 }
1018 }
1019
1020 pub(crate) fn encoding(&self) -> &'static Encoding {
1021 self.encoding.get()
1022 }
1023
1024 pub(crate) fn set_encoding(&self, encoding: &'static Encoding) {
1025 self.encoding.set(encoding);
1026 }
1027
1028 pub(crate) fn content_and_heritage_changed(&self, node: &Node) {
1029 if node.is_connected() {
1030 node.note_dirty_descendants();
1031 }
1032
1033 node.dirty(NodeDamage::ContentOrHeritage);
1036 }
1037
1038 pub(crate) fn unregister_element_id(&self, to_unregister: &Element, id: Atom, can_gc: CanGc) {
1040 self.document_or_shadow_root
1041 .unregister_named_element(&self.id_map, to_unregister, &id);
1042 self.reset_form_owner_for_listeners(&id, can_gc);
1043 }
1044
1045 pub(crate) fn register_element_id(&self, element: &Element, id: Atom, can_gc: CanGc) {
1047 let root = self.GetDocumentElement().expect(
1048 "The element is in the document, so there must be a document \
1049 element.",
1050 );
1051 self.document_or_shadow_root.register_named_element(
1052 &self.id_map,
1053 element,
1054 &id,
1055 DomRoot::from_ref(root.upcast::<Node>()),
1056 );
1057 self.reset_form_owner_for_listeners(&id, can_gc);
1058 }
1059
1060 pub(crate) fn unregister_element_name(&self, to_unregister: &Element, name: Atom) {
1062 self.document_or_shadow_root
1063 .unregister_named_element(&self.name_map, to_unregister, &name);
1064 }
1065
1066 pub(crate) fn register_element_name(&self, element: &Element, name: Atom) {
1068 let root = self.GetDocumentElement().expect(
1069 "The element is in the document, so there must be a document \
1070 element.",
1071 );
1072 self.document_or_shadow_root.register_named_element(
1073 &self.name_map,
1074 element,
1075 &name,
1076 DomRoot::from_ref(root.upcast::<Node>()),
1077 );
1078 }
1079
1080 pub(crate) fn register_form_id_listener<T: ?Sized + FormControl>(
1081 &self,
1082 id: DOMString,
1083 listener: &T,
1084 ) {
1085 let mut map = self.form_id_listener_map.borrow_mut();
1086 let listener = listener.to_element();
1087 let set = map.entry(Atom::from(id)).or_default();
1088 set.insert(Dom::from_ref(listener));
1089 }
1090
1091 pub(crate) fn unregister_form_id_listener<T: ?Sized + FormControl>(
1092 &self,
1093 id: DOMString,
1094 listener: &T,
1095 ) {
1096 let mut map = self.form_id_listener_map.borrow_mut();
1097 if let Occupied(mut entry) = map.entry(Atom::from(id)) {
1098 entry
1099 .get_mut()
1100 .remove(&Dom::from_ref(listener.to_element()));
1101 if entry.get().is_empty() {
1102 entry.remove();
1103 }
1104 }
1105 }
1106
1107 pub(crate) fn find_fragment_node(&self, fragid: &str) -> Option<DomRoot<Element>> {
1110 percent_decode(fragid.as_bytes())
1114 .decode_utf8()
1115 .ok()
1116 .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
1118 .or_else(|| self.get_anchor_by_name(fragid))
1120 }
1122
1123 pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) {
1127 let target = self.find_fragment_node(fragment);
1128
1129 self.set_target_element(target.as_deref());
1131
1132 let point = target
1133 .as_ref()
1134 .map(|element| {
1135 let rect = element.upcast::<Node>().border_box().unwrap_or_default();
1140
1141 let device_pixel_ratio = self.window.device_pixel_ratio().get();
1146 (
1147 rect.origin.x.to_nearest_pixel(device_pixel_ratio),
1148 rect.origin.y.to_nearest_pixel(device_pixel_ratio),
1149 )
1150 })
1151 .or_else(|| {
1152 if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
1153 Some((0.0, 0.0))
1156 } else {
1157 None
1158 }
1159 });
1160
1161 if let Some((x, y)) = point {
1162 self.window.scroll(x, y, ScrollBehavior::Instant)
1163 }
1164 }
1165
1166 fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
1167 let name = Atom::from(name);
1168 self.name_map.borrow().get(&name).and_then(|elements| {
1169 elements
1170 .iter()
1171 .find(|e| e.is::<HTMLAnchorElement>())
1172 .map(|e| DomRoot::from_ref(&**e))
1173 })
1174 }
1175
1176 pub(crate) fn set_ready_state(&self, state: DocumentReadyState, can_gc: CanGc) {
1178 match state {
1179 DocumentReadyState::Loading => {
1180 if self.window().is_top_level() {
1181 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1182 self.webview_id(),
1183 LoadStatus::Started,
1184 ));
1185 self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
1186 }
1187 },
1188 DocumentReadyState::Complete => {
1189 if self.window().is_top_level() {
1190 self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged(
1191 self.webview_id(),
1192 LoadStatus::Complete,
1193 ));
1194 }
1195 update_with_current_instant(&self.dom_complete);
1196 },
1197 DocumentReadyState::Interactive => update_with_current_instant(&self.dom_interactive),
1198 };
1199
1200 self.ready_state.set(state);
1201
1202 self.upcast::<EventTarget>()
1203 .fire_event(atom!("readystatechange"), can_gc);
1204 }
1205
1206 pub(crate) fn scripting_enabled(&self) -> bool {
1209 self.has_browsing_context() &&
1212 !self.has_active_sandboxing_flag(
1216 SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
1217 )
1218 }
1219
1220 pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
1223 self.focused.get()
1224 }
1225
1226 pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
1231 self.focus_sequence.get()
1232 }
1233
1234 fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
1236 self.focus_sequence.set(FocusSequenceNumber(
1237 self.focus_sequence
1238 .get()
1239 .0
1240 .checked_add(1)
1241 .expect("too many focus messages have been sent"),
1242 ));
1243 self.focus_sequence.get()
1244 }
1245
1246 pub(crate) fn has_focus_transaction(&self) -> bool {
1247 self.focus_transaction.borrow().is_some()
1248 }
1249
1250 pub(crate) fn begin_focus_transaction(&self) {
1253 *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
1255 element: self.focused.get().as_deref().map(Dom::from_ref),
1256 has_focus: self.has_focus.get(),
1257 focus_options: FocusOptions {
1258 preventScroll: true,
1259 },
1260 });
1261 }
1262
1263 pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
1265 if Some(not_focusable) != self.focused.get().as_deref() {
1268 return;
1269 }
1270
1271 let implicit_transaction = self.focus_transaction.borrow().is_none();
1272
1273 if implicit_transaction {
1274 self.begin_focus_transaction();
1275 }
1276
1277 {
1280 let mut focus_transaction = self.focus_transaction.borrow_mut();
1281 focus_transaction.as_mut().unwrap().element = None;
1282 }
1283
1284 if implicit_transaction {
1285 self.commit_focus_transaction(FocusInitiator::Local, can_gc);
1286 }
1287 }
1288
1289 pub(crate) fn request_focus(
1292 &self,
1293 elem: Option<&Element>,
1294 focus_initiator: FocusInitiator,
1295 can_gc: CanGc,
1296 ) {
1297 self.request_focus_with_options(
1298 elem,
1299 focus_initiator,
1300 FocusOptions {
1301 preventScroll: true,
1302 },
1303 can_gc,
1304 );
1305 }
1306
1307 pub(crate) fn request_focus_with_options(
1313 &self,
1314 elem: Option<&Element>,
1315 focus_initiator: FocusInitiator,
1316 focus_options: FocusOptions,
1317 can_gc: CanGc,
1318 ) {
1319 if elem.is_some_and(|e| !e.is_focusable_area()) {
1322 return;
1323 }
1324
1325 let implicit_transaction = self.focus_transaction.borrow().is_none();
1326
1327 if implicit_transaction {
1328 self.begin_focus_transaction();
1329 }
1330
1331 {
1332 let mut focus_transaction = self.focus_transaction.borrow_mut();
1333 let focus_transaction = focus_transaction.as_mut().unwrap();
1334 focus_transaction.element = elem.map(Dom::from_ref);
1335 focus_transaction.has_focus = true;
1336 focus_transaction.focus_options = focus_options;
1337 }
1338
1339 if implicit_transaction {
1340 self.commit_focus_transaction(focus_initiator, can_gc);
1341 }
1342 }
1343
1344 pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
1348 if self.window().parent_info().is_none() {
1349 warn!("Top-level document cannot be unfocused");
1350 return;
1351 }
1352
1353 assert!(
1356 self.focus_transaction.borrow().is_none(),
1357 "there mustn't be an in-progress focus transaction at this point"
1358 );
1359
1360 self.begin_focus_transaction();
1362
1363 {
1365 let mut focus_transaction = self.focus_transaction.borrow_mut();
1366 focus_transaction.as_mut().unwrap().has_focus = false;
1367 }
1368
1369 self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
1371 }
1372
1373 pub(crate) fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
1376 let (mut new_focused, new_focus_state, prevent_scroll) = {
1377 let focus_transaction = self.focus_transaction.borrow();
1378 let focus_transaction = focus_transaction
1379 .as_ref()
1380 .expect("no focus transaction in progress");
1381 (
1382 focus_transaction
1383 .element
1384 .as_ref()
1385 .map(|e| DomRoot::from_ref(&**e)),
1386 focus_transaction.has_focus,
1387 focus_transaction.focus_options.preventScroll,
1388 )
1389 };
1390 *self.focus_transaction.borrow_mut() = None;
1391
1392 if !new_focus_state {
1393 if new_focused.take().is_some() {
1396 trace!(
1397 "Forgetting the document's focused area because the \
1398 document's container was removed from the top-level BC's \
1399 focus chain"
1400 );
1401 }
1402 }
1403
1404 let old_focused = self.focused.get();
1405 let old_focus_state = self.has_focus.get();
1406
1407 debug!(
1408 "Committing focus transaction: {:?} → {:?}",
1409 (&old_focused, old_focus_state),
1410 (&new_focused, new_focus_state),
1411 );
1412
1413 let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
1416 let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
1417
1418 let trace_focus_chain = |name, element, doc| {
1419 trace!(
1420 "{} local focus chain: {}",
1421 name,
1422 match (element, doc) {
1423 (Some(e), _) => format!("[{:?}, document]", e),
1424 (None, true) => "[document]".to_owned(),
1425 (None, false) => "[]".to_owned(),
1426 }
1427 );
1428 };
1429
1430 trace_focus_chain("Old", old_focused_filtered, old_focus_state);
1431 trace_focus_chain("New", new_focused_filtered, new_focus_state);
1432
1433 if old_focused_filtered != new_focused_filtered {
1434 if let Some(elem) = &old_focused_filtered {
1435 let node = elem.upcast::<Node>();
1436 elem.set_focus_state(false);
1437 if node.is_connected() {
1439 self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
1440 }
1441 }
1442 }
1443
1444 if old_focus_state != new_focus_state && !new_focus_state {
1445 self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
1446 }
1447
1448 self.focused.set(new_focused.as_deref());
1449 self.has_focus.set(new_focus_state);
1450
1451 if old_focus_state != new_focus_state && new_focus_state {
1452 self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
1453 }
1454
1455 if old_focused_filtered != new_focused_filtered {
1456 if let Some(elem) = &new_focused_filtered {
1457 elem.set_focus_state(true);
1458 let node = elem.upcast::<Node>();
1459 self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
1461
1462 if !prevent_scroll {
1465 let scroll_axis = ScrollAxisState {
1468 position: ScrollLogicalPosition::Center,
1469 requirement: ScrollRequirement::IfNotVisible,
1470 };
1471
1472 elem.scroll_into_view_with_options(
1476 ScrollBehavior::Smooth,
1477 scroll_axis,
1478 scroll_axis,
1479 None,
1480 None,
1481 );
1482 }
1483 }
1484 }
1485
1486 if focus_initiator != FocusInitiator::Local {
1487 return;
1488 }
1489
1490 match (old_focus_state, new_focus_state) {
1493 (_, true) => {
1494 let child_browsing_context_id = new_focused
1515 .as_ref()
1516 .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
1517 .and_then(|iframe| iframe.browsing_context_id());
1518
1519 let sequence = self.increment_fetch_focus_sequence();
1520
1521 debug!(
1522 "Advertising the focus request to the constellation \
1523 with sequence number {} and child BC ID {}",
1524 sequence,
1525 child_browsing_context_id
1526 .as_ref()
1527 .map(|id| id as &dyn std::fmt::Display)
1528 .unwrap_or(&"(none)"),
1529 );
1530
1531 self.window()
1532 .send_to_constellation(ScriptToConstellationMessage::Focus(
1533 child_browsing_context_id,
1534 sequence,
1535 ));
1536 },
1537 (false, false) => {
1538 },
1541 (true, false) => {
1542 unreachable!(
1543 "Can't lose the document's focus without specifying \
1544 another one to focus"
1545 );
1546 },
1547 }
1548 }
1549
1550 pub(crate) fn title_changed(&self) {
1552 if self.browsing_context().is_some() {
1553 self.send_title_to_embedder();
1554 let title = String::from(self.Title());
1555 self.window
1556 .send_to_constellation(ScriptToConstellationMessage::TitleChanged(
1557 self.window.pipeline_id(),
1558 title.clone(),
1559 ));
1560 if let Some(chan) = self.window.as_global_scope().devtools_chan() {
1561 let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
1562 self.window.pipeline_id(),
1563 title,
1564 ));
1565 }
1566 }
1567 }
1568
1569 fn title(&self) -> Option<DOMString> {
1573 let title = self.GetDocumentElement().and_then(|root| {
1574 if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
1575 root.upcast::<Node>()
1577 .child_elements()
1578 .find(|node| {
1579 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
1580 })
1581 .map(DomRoot::upcast::<Node>)
1582 } else {
1583 root.upcast::<Node>()
1585 .traverse_preorder(ShadowIncluding::No)
1586 .find(|node| node.is::<HTMLTitleElement>())
1587 }
1588 });
1589
1590 title.map(|title| {
1591 let value = title.child_text_content();
1593 DOMString::from(str_join(value.str().split_html_space_characters(), " "))
1594 })
1595 }
1596
1597 pub(crate) fn send_title_to_embedder(&self) {
1599 let window = self.window();
1600 if window.is_top_level() {
1601 let title = self.title().map(String::from);
1602 self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
1603 }
1604 }
1605
1606 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
1607 let window = self.window();
1608 window.send_to_embedder(msg);
1609 }
1610
1611 pub(crate) fn dirty_all_nodes(&self) {
1612 let root = match self.GetDocumentElement() {
1613 Some(root) => root,
1614 None => return,
1615 };
1616 for node in root
1617 .upcast::<Node>()
1618 .traverse_preorder(ShadowIncluding::Yes)
1619 {
1620 node.dirty(NodeDamage::Other)
1621 }
1622 }
1623
1624 pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
1626 rooted_vec!(let notify_list <- self.pending_scroll_event_targets.take().into_iter());
1638 for target in notify_list.iter() {
1639 if target.downcast::<Document>().is_some() {
1640 target.fire_bubbling_event(Atom::from("scroll"), can_gc);
1643 } else if target.downcast::<Element>().is_some() {
1644 target.fire_event(Atom::from("scroll"), can_gc);
1647 }
1648 }
1649
1650 }
1654
1655 pub(crate) fn handle_viewport_scroll_event(&self) {
1659 let target = self.upcast::<EventTarget>();
1668 if self
1669 .pending_scroll_event_targets
1670 .borrow()
1671 .iter()
1672 .any(|other_target| *other_target == target)
1673 {
1674 return;
1675 }
1676
1677 self.pending_scroll_event_targets
1680 .borrow_mut()
1681 .push(Dom::from_ref(target));
1682 }
1683
1684 pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
1688 let target = element.upcast::<EventTarget>();
1698 if self
1699 .pending_scroll_event_targets
1700 .borrow()
1701 .iter()
1702 .any(|other_target| *other_target == target)
1703 {
1704 return;
1705 }
1706
1707 self.pending_scroll_event_targets
1710 .borrow_mut()
1711 .push(Dom::from_ref(target));
1712 }
1713
1714 pub(crate) fn node_from_nodes_and_strings(
1716 &self,
1717 mut nodes: Vec<NodeOrString>,
1718 can_gc: CanGc,
1719 ) -> Fallible<DomRoot<Node>> {
1720 if nodes.len() == 1 {
1721 Ok(match nodes.pop().unwrap() {
1722 NodeOrString::Node(node) => node,
1723 NodeOrString::String(string) => {
1724 DomRoot::upcast(self.CreateTextNode(string, can_gc))
1725 },
1726 })
1727 } else {
1728 let fragment = DomRoot::upcast::<Node>(self.CreateDocumentFragment(can_gc));
1729 for node in nodes {
1730 match node {
1731 NodeOrString::Node(node) => {
1732 fragment.AppendChild(&node, can_gc)?;
1733 },
1734 NodeOrString::String(string) => {
1735 let node = DomRoot::upcast::<Node>(self.CreateTextNode(string, can_gc));
1736 fragment.AppendChild(&node, can_gc).unwrap();
1739 },
1740 }
1741 }
1742 Ok(fragment)
1743 }
1744 }
1745
1746 pub(crate) fn get_body_attribute(&self, local_name: &LocalName) -> DOMString {
1747 match self.GetBody() {
1748 Some(ref body) if body.is_body_element() => {
1749 body.upcast::<Element>().get_string_attribute(local_name)
1750 },
1751 _ => DOMString::new(),
1752 }
1753 }
1754
1755 pub(crate) fn set_body_attribute(
1756 &self,
1757 local_name: &LocalName,
1758 value: DOMString,
1759 can_gc: CanGc,
1760 ) {
1761 if let Some(ref body) = self.GetBody().filter(|elem| elem.is_body_element()) {
1762 let body = body.upcast::<Element>();
1763 let value = body.parse_attribute(&ns!(), local_name, value);
1764 body.set_attribute(local_name, value, can_gc);
1765 }
1766 }
1767
1768 pub(crate) fn set_current_script(&self, script: Option<&HTMLScriptElement>) {
1769 self.current_script.set(script);
1770 }
1771
1772 pub(crate) fn get_script_blocking_stylesheets_count(&self) -> u32 {
1773 self.script_blocking_stylesheets_count.get()
1774 }
1775
1776 pub(crate) fn increment_script_blocking_stylesheet_count(&self) {
1777 let count_cell = &self.script_blocking_stylesheets_count;
1778 count_cell.set(count_cell.get() + 1);
1779 }
1780
1781 pub(crate) fn decrement_script_blocking_stylesheet_count(&self) {
1782 let count_cell = &self.script_blocking_stylesheets_count;
1783 assert!(count_cell.get() > 0);
1784 count_cell.set(count_cell.get() - 1);
1785 }
1786
1787 pub(crate) fn render_blocking_element_count(&self) -> u32 {
1788 self.render_blocking_element_count.get()
1789 }
1790
1791 pub(crate) fn increment_render_blocking_element_count(&self) {
1792 let count_cell = &self.render_blocking_element_count;
1793 count_cell.set(count_cell.get() + 1);
1794 }
1795
1796 pub(crate) fn decrement_render_blocking_element_count(&self) {
1797 let count_cell = &self.render_blocking_element_count;
1798 assert!(count_cell.get() > 0);
1799 count_cell.set(count_cell.get() - 1);
1800 }
1801
1802 pub(crate) fn invalidate_stylesheets(&self) {
1803 self.stylesheets.borrow_mut().force_dirty(OriginSet::all());
1804
1805 if let Some(element) = self.GetDocumentElement() {
1809 element.upcast::<Node>().dirty(NodeDamage::Style);
1810 }
1811 }
1812
1813 pub(crate) fn has_active_request_animation_frame_callbacks(&self) -> bool {
1816 !self.animation_frame_list.borrow().is_empty()
1817 }
1818
1819 pub(crate) fn request_animation_frame(&self, callback: AnimationFrameCallback) -> u32 {
1821 let ident = self.animation_frame_ident.get() + 1;
1822 self.animation_frame_ident.set(ident);
1823
1824 let had_animation_frame_callbacks;
1825 {
1826 let mut animation_frame_list = self.animation_frame_list.borrow_mut();
1827 had_animation_frame_callbacks = !animation_frame_list.is_empty();
1828 animation_frame_list.push_back((ident, Some(callback)));
1829 }
1830
1831 if !self.running_animation_callbacks.get() && !had_animation_frame_callbacks {
1837 self.window().send_to_constellation(
1838 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1839 AnimationState::AnimationCallbacksPresent,
1840 ),
1841 );
1842 }
1843
1844 ident
1845 }
1846
1847 pub(crate) fn cancel_animation_frame(&self, ident: u32) {
1849 let mut list = self.animation_frame_list.borrow_mut();
1850 if let Some(pair) = list.iter_mut().find(|pair| pair.0 == ident) {
1851 pair.1 = None;
1852 }
1853 }
1854
1855 pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
1857 let _realm = enter_realm(self);
1858
1859 self.running_animation_callbacks.set(true);
1860 let timing = self.global().performance().Now();
1861
1862 let num_callbacks = self.animation_frame_list.borrow().len();
1863 for _ in 0..num_callbacks {
1864 let (_, maybe_callback) = self.animation_frame_list.borrow_mut().pop_front().unwrap();
1865 if let Some(callback) = maybe_callback {
1866 callback.call(self, *timing, can_gc);
1867 }
1868 }
1869 self.running_animation_callbacks.set(false);
1870
1871 if self.animation_frame_list.borrow().is_empty() {
1872 self.window().send_to_constellation(
1873 ScriptToConstellationMessage::ChangeRunningAnimationsState(
1874 AnimationState::NoAnimationCallbacksPresent,
1875 ),
1876 );
1877 }
1878 }
1879
1880 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
1881 self.policy_container.borrow()
1882 }
1883
1884 pub(crate) fn set_policy_container(&self, policy_container: PolicyContainer) {
1885 *self.policy_container.borrow_mut() = policy_container;
1886 }
1887
1888 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
1889 self.policy_container.borrow_mut().set_csp_list(csp_list);
1890 }
1891
1892 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
1893 self.policy_container.borrow().csp_list.clone()
1894 }
1895
1896 pub(crate) fn preloaded_resources(&self) -> PreloadedResources {
1897 self.preloaded_resources.clone()
1898 }
1899
1900 pub(crate) fn prepare_request(&self, request: RequestBuilder) -> RequestBuilder {
1904 request
1905 .policy_container(self.policy_container().to_owned())
1906 .https_state(self.https_state.get())
1907 }
1908
1909 pub(crate) fn fetch<Listener: FetchResponseListener>(
1910 &self,
1911 load: LoadType,
1912 mut request: RequestBuilder,
1913 listener: Listener,
1914 ) {
1915 request = request
1916 .insecure_requests_policy(self.insecure_requests_policy())
1917 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1918 let callback = NetworkListener {
1919 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1920 task_source: self
1921 .owner_global()
1922 .task_manager()
1923 .networking_task_source()
1924 .into(),
1925 }
1926 .into_callback();
1927 self.loader_mut()
1928 .fetch_async_with_callback(load, request, callback);
1929 }
1930
1931 pub(crate) fn fetch_background<Listener: FetchResponseListener>(
1932 &self,
1933 mut request: RequestBuilder,
1934 listener: Listener,
1935 ) {
1936 request = request
1937 .insecure_requests_policy(self.insecure_requests_policy())
1938 .has_trustworthy_ancestor_origin(self.has_trustworthy_ancestor_or_current_origin());
1939 let callback = NetworkListener {
1940 context: std::sync::Arc::new(Mutex::new(Some(listener))),
1941 task_source: self
1942 .owner_global()
1943 .task_manager()
1944 .networking_task_source()
1945 .into(),
1946 }
1947 .into_callback();
1948 self.loader_mut().fetch_async_background(request, callback);
1949 }
1950
1951 pub(crate) fn finish_load(&self, load: LoadType, can_gc: CanGc) {
1954 debug!("Document got finish_load: {:?}", load);
1956 self.loader.borrow_mut().finish_load(&load);
1957
1958 match load {
1959 LoadType::Stylesheet(_) => {
1960 self.process_pending_parsing_blocking_script(can_gc);
1963
1964 self.process_deferred_scripts(can_gc);
1966 },
1967 LoadType::PageSource(_) => {
1968 if self.has_browsing_context && self.is_fully_active() {
1971 self.window().allow_layout_if_necessary();
1972 }
1973
1974 self.process_deferred_scripts(can_gc);
1979 },
1980 _ => {},
1981 }
1982
1983 let loader = self.loader.borrow();
1990
1991 if self.top_level_dom_complete.get().is_none() && loader.is_only_blocked_by_iframes() {
1993 update_with_current_instant(&self.top_level_dom_complete);
1994 }
1995
1996 if loader.is_blocked() || loader.events_inhibited() {
1997 return;
1999 }
2000
2001 ScriptThread::mark_document_with_no_blocked_loads(self);
2002 }
2003
2004 pub(crate) fn prompt_to_unload(&self, recursive_flag: bool, can_gc: CanGc) -> bool {
2006 self.incr_ignore_opens_during_unload_counter();
2009 let beforeunload_event = BeforeUnloadEvent::new(
2011 &self.window,
2012 atom!("beforeunload"),
2013 EventBubbles::Bubbles,
2014 EventCancelable::Cancelable,
2015 can_gc,
2016 );
2017 let event = beforeunload_event.upcast::<Event>();
2018 event.set_trusted(true);
2019 let event_target = self.window.upcast::<EventTarget>();
2020 let has_listeners = event_target.has_listeners_for(&atom!("beforeunload"));
2021 self.window
2022 .dispatch_event_with_target_override(event, can_gc);
2023 if has_listeners {
2026 self.salvageable.set(false);
2027 }
2028 let mut can_unload = true;
2029 let default_prevented = event.DefaultPrevented();
2031 let return_value_not_empty = !event
2032 .downcast::<BeforeUnloadEvent>()
2033 .unwrap()
2034 .ReturnValue()
2035 .is_empty();
2036 if default_prevented || return_value_not_empty {
2037 let (chan, port) = generic_channel::channel().expect("Failed to create IPC channel!");
2038 let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
2039 self.send_to_embedder(msg);
2040 can_unload = port.recv().unwrap() == AllowOrDeny::Allow;
2041 }
2042 if !recursive_flag {
2044 let iframes: Vec<_> = self.iframes().iter().collect();
2047 for iframe in &iframes {
2048 let document = iframe.owner_document();
2050 can_unload = document.prompt_to_unload(true, can_gc);
2051 if !document.salvageable() {
2052 self.salvageable.set(false);
2053 }
2054 if !can_unload {
2055 break;
2056 }
2057 }
2058 }
2059 self.decr_ignore_opens_during_unload_counter();
2061 can_unload
2062 }
2063
2064 pub(crate) fn unload(&self, recursive_flag: bool, can_gc: CanGc) {
2066 self.incr_ignore_opens_during_unload_counter();
2069 if self.page_showing.get() {
2071 self.page_showing.set(false);
2073 let event = PageTransitionEvent::new(
2076 &self.window,
2077 atom!("pagehide"),
2078 false, false, self.salvageable.get(), can_gc,
2082 );
2083 let event = event.upcast::<Event>();
2084 event.set_trusted(true);
2085 self.window
2086 .dispatch_event_with_target_override(event, can_gc);
2087 self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
2089 }
2090 if !self.fired_unload.get() {
2092 let event = Event::new(
2093 self.window.upcast(),
2094 atom!("unload"),
2095 EventBubbles::Bubbles,
2096 EventCancelable::Cancelable,
2097 can_gc,
2098 );
2099 event.set_trusted(true);
2100 let event_target = self.window.upcast::<EventTarget>();
2101 let has_listeners = event_target.has_listeners_for(&atom!("unload"));
2102 self.window
2103 .dispatch_event_with_target_override(&event, can_gc);
2104 self.fired_unload.set(true);
2105 if has_listeners {
2107 self.salvageable.set(false);
2108 }
2109 }
2110 if !recursive_flag {
2114 let iframes: Vec<_> = self.iframes().iter().collect();
2117 for iframe in &iframes {
2118 let document = iframe.owner_document();
2120 document.unload(true, can_gc);
2121 if !document.salvageable() {
2122 self.salvageable.set(false);
2123 }
2124 }
2125 }
2126
2127 self.unloading_cleanup_steps();
2129
2130 self.window.as_global_scope().clean_up_all_file_resources();
2132
2133 self.decr_ignore_opens_during_unload_counter();
2135 }
2136
2137 pub(crate) fn maybe_queue_document_completion(&self) {
2139 let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
2141 Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
2142 None => false,
2143 };
2144
2145 let not_ready_for_load = self.loader.borrow().is_blocked() ||
2150 !self.is_fully_active() ||
2151 is_in_delaying_load_events_mode;
2152
2153 if not_ready_for_load {
2154 return;
2156 }
2157
2158 assert!(!self.loader.borrow().events_inhibited());
2159 self.loader.borrow_mut().inhibit_events();
2160
2161 debug!("Document loads are complete.");
2164 let document = Trusted::new(self);
2165 self.owner_global()
2166 .task_manager()
2167 .dom_manipulation_task_source()
2168 .queue(task!(fire_load_event: move || {
2169 let document = document.root();
2170 let window = document.window();
2171 if !window.is_alive() {
2172 return;
2173 }
2174
2175 document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
2177
2178 if document.browsing_context().is_none() {
2180 return;
2181 }
2182 let event = Event::new(
2183 window.upcast(),
2184 atom!("load"),
2185 EventBubbles::DoesNotBubble,
2186 EventCancelable::NotCancelable,
2187 CanGc::note(),
2188 );
2189 event.set_trusted(true);
2190
2191 update_with_current_instant(&document.load_event_start);
2193
2194 debug!("About to dispatch load for {:?}", document.url());
2195 window.dispatch_event_with_target_override(&event, CanGc::note());
2196
2197 update_with_current_instant(&document.load_event_end);
2199
2200 if let Some(fragment) = document.url().fragment() {
2201 document.check_and_scroll_fragment(fragment);
2202 }
2203 }));
2204
2205 let document = Trusted::new(self);
2207 if document.root().browsing_context().is_some() {
2208 self.owner_global()
2209 .task_manager()
2210 .dom_manipulation_task_source()
2211 .queue(task!(fire_pageshow_event: move || {
2212 let document = document.root();
2213 let window = document.window();
2214 if document.page_showing.get() || !window.is_alive() {
2215 return;
2216 }
2217
2218 document.page_showing.set(true);
2219
2220 let event = PageTransitionEvent::new(
2221 window,
2222 atom!("pageshow"),
2223 false, false, false, CanGc::note(),
2227 );
2228 let event = event.upcast::<Event>();
2229 event.set_trusted(true);
2230
2231 window.dispatch_event_with_target_override(event, CanGc::note());
2232 }));
2233 }
2234
2235 #[cfg(feature = "webxr")]
2250 if pref!(dom_webxr_sessionavailable) && self.window.is_top_level() {
2251 self.window.Navigator().Xr().dispatch_sessionavailable();
2252 }
2253
2254 let document = Trusted::new(self);
2258 if document.root().browsing_context().is_some() {
2259 self.owner_global()
2260 .task_manager()
2261 .dom_manipulation_task_source()
2262 .queue(task!(completely_loaded: move || {
2263 let document = document.root();
2264 document.completely_loaded.set(true);
2265 if let Some(DeclarativeRefresh::PendingLoad {
2266 url,
2267 time
2268 }) = &*document.declarative_refresh.borrow() {
2269 document.window.as_global_scope().schedule_callback(
2271 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
2272 window: DomRoot::from_ref(document.window()),
2273 url: url.clone(),
2274 }),
2275 Duration::from_secs(*time),
2276 );
2277 }
2278 document.notify_constellation_load();
2281 }));
2282 }
2283 }
2284
2285 pub(crate) fn completely_loaded(&self) -> bool {
2286 self.completely_loaded.get()
2287 }
2288
2289 pub(crate) fn set_pending_parsing_blocking_script(
2291 &self,
2292 script: &HTMLScriptElement,
2293 load: Option<ScriptResult>,
2294 ) {
2295 assert!(!self.has_pending_parsing_blocking_script());
2296 *self.pending_parsing_blocking_script.borrow_mut() =
2297 Some(PendingScript::new_with_load(script, load));
2298 }
2299
2300 pub(crate) fn has_pending_parsing_blocking_script(&self) -> bool {
2302 self.pending_parsing_blocking_script.borrow().is_some()
2303 }
2304
2305 pub(crate) fn pending_parsing_blocking_script_loaded(
2307 &self,
2308 element: &HTMLScriptElement,
2309 result: ScriptResult,
2310 can_gc: CanGc,
2311 ) {
2312 {
2313 let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
2314 let entry = blocking_script.as_mut().unwrap();
2315 assert!(&*entry.element == element);
2316 entry.loaded(result);
2317 }
2318 self.process_pending_parsing_blocking_script(can_gc);
2319 }
2320
2321 fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) {
2322 if self.script_blocking_stylesheets_count.get() > 0 {
2323 return;
2324 }
2325 let pair = self
2326 .pending_parsing_blocking_script
2327 .borrow_mut()
2328 .as_mut()
2329 .and_then(PendingScript::take_result);
2330 if let Some((element, result)) = pair {
2331 *self.pending_parsing_blocking_script.borrow_mut() = None;
2332 self.get_current_parser()
2333 .unwrap()
2334 .resume_with_pending_parsing_blocking_script(&element, result, can_gc);
2335 }
2336 }
2337
2338 pub(crate) fn add_asap_script(&self, script: &HTMLScriptElement) {
2340 self.asap_scripts_set
2341 .borrow_mut()
2342 .push(Dom::from_ref(script));
2343 }
2344
2345 pub(crate) fn asap_script_loaded(
2348 &self,
2349 element: &HTMLScriptElement,
2350 result: ScriptResult,
2351 can_gc: CanGc,
2352 ) {
2353 {
2354 let mut scripts = self.asap_scripts_set.borrow_mut();
2355 let idx = scripts
2356 .iter()
2357 .position(|entry| &**entry == element)
2358 .unwrap();
2359 scripts.swap_remove(idx);
2360 }
2361 element.execute(result, can_gc);
2362 }
2363
2364 pub(crate) fn push_asap_in_order_script(&self, script: &HTMLScriptElement) {
2366 self.asap_in_order_scripts_list.push(script);
2367 }
2368
2369 pub(crate) fn asap_in_order_script_loaded(
2372 &self,
2373 element: &HTMLScriptElement,
2374 result: ScriptResult,
2375 can_gc: CanGc,
2376 ) {
2377 self.asap_in_order_scripts_list.loaded(element, result);
2378 while let Some((element, result)) = self
2379 .asap_in_order_scripts_list
2380 .take_next_ready_to_be_executed()
2381 {
2382 element.execute(result, can_gc);
2383 }
2384 }
2385
2386 pub(crate) fn add_deferred_script(&self, script: &HTMLScriptElement) {
2388 self.deferred_scripts.push(script);
2389 }
2390
2391 pub(crate) fn deferred_script_loaded(
2394 &self,
2395 element: &HTMLScriptElement,
2396 result: ScriptResult,
2397 can_gc: CanGc,
2398 ) {
2399 self.deferred_scripts.loaded(element, result);
2400 self.process_deferred_scripts(can_gc);
2401 }
2402
2403 fn process_deferred_scripts(&self, can_gc: CanGc) {
2405 if self.ready_state.get() != DocumentReadyState::Interactive {
2406 return;
2407 }
2408 loop {
2410 if self.script_blocking_stylesheets_count.get() > 0 {
2411 return;
2412 }
2413 if let Some((element, result)) = self.deferred_scripts.take_next_ready_to_be_executed()
2414 {
2415 element.execute(result, can_gc);
2416 } else {
2417 break;
2418 }
2419 }
2420 if self.deferred_scripts.is_empty() {
2421 self.maybe_dispatch_dom_content_loaded();
2423 }
2424 }
2425
2426 pub(crate) fn maybe_dispatch_dom_content_loaded(&self) {
2428 if self.domcontentloaded_dispatched.get() {
2429 return;
2430 }
2431 self.domcontentloaded_dispatched.set(true);
2432 assert_ne!(
2433 self.ReadyState(),
2434 DocumentReadyState::Complete,
2435 "Complete before DOMContentLoaded?"
2436 );
2437
2438 update_with_current_instant(&self.dom_content_loaded_event_start);
2439
2440 let document = Trusted::new(self);
2442 self.owner_global()
2443 .task_manager()
2444 .dom_manipulation_task_source()
2445 .queue(
2446 task!(fire_dom_content_loaded_event: move || {
2447 let document = document.root();
2448 document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
2449 update_with_current_instant(&document.dom_content_loaded_event_end);
2450 })
2451 );
2452
2453 self.interactive_time
2455 .borrow()
2456 .maybe_set_tti(InteractiveFlag::DOMContentLoaded);
2457
2458 }
2461
2462 pub(crate) fn abort(&self, can_gc: CanGc) {
2464 self.loader.borrow_mut().inhibit_events();
2466
2467 for iframe in self.iframes().iter() {
2469 if let Some(document) = iframe.GetContentDocument() {
2470 document.abort(can_gc);
2472 }
2474 }
2475
2476 self.script_blocking_stylesheets_count.set(0);
2478 *self.pending_parsing_blocking_script.borrow_mut() = None;
2479 *self.asap_scripts_set.borrow_mut() = vec![];
2480 self.asap_in_order_scripts_list.clear();
2481 self.deferred_scripts.clear();
2482 let loads_cancelled = self.loader.borrow_mut().cancel_all_loads();
2483 let event_sources_canceled = self.window.as_global_scope().close_event_sources();
2484 if loads_cancelled || event_sources_canceled {
2485 self.salvageable.set(false);
2487 };
2488
2489 self.owner_global()
2494 .task_manager()
2495 .cancel_pending_tasks_for_source(TaskSourceName::Networking);
2496
2497 if let Some(parser) = self.get_current_parser() {
2499 self.active_parser_was_aborted.set(true);
2500 parser.abort(can_gc);
2501 self.salvageable.set(false);
2502 }
2503 }
2504
2505 pub(crate) fn notify_constellation_load(&self) {
2506 self.window()
2507 .send_to_constellation(ScriptToConstellationMessage::LoadComplete);
2508 }
2509
2510 pub(crate) fn set_current_parser(&self, script: Option<&ServoParser>) {
2511 self.current_parser.set(script);
2512 }
2513
2514 pub(crate) fn get_current_parser(&self) -> Option<DomRoot<ServoParser>> {
2515 self.current_parser.get()
2516 }
2517
2518 pub(crate) fn get_current_parser_line(&self) -> u32 {
2519 self.get_current_parser()
2520 .map(|parser| parser.get_current_line())
2521 .unwrap_or(0)
2522 }
2523
2524 pub(crate) fn iframes(&self) -> Ref<'_, IFrameCollection> {
2527 self.iframes.borrow_mut().validate(self);
2528 self.iframes.borrow()
2529 }
2530
2531 pub(crate) fn iframes_mut(&self) -> RefMut<'_, IFrameCollection> {
2534 self.iframes.borrow_mut().validate(self);
2535 self.iframes.borrow_mut()
2536 }
2537
2538 pub(crate) fn invalidate_iframes_collection(&self) {
2539 self.iframes.borrow_mut().invalidate();
2540 }
2541
2542 pub(crate) fn get_dom_interactive(&self) -> Option<CrossProcessInstant> {
2543 self.dom_interactive.get()
2544 }
2545
2546 pub(crate) fn set_navigation_start(&self, navigation_start: CrossProcessInstant) {
2547 self.interactive_time
2548 .borrow_mut()
2549 .set_navigation_start(navigation_start);
2550 }
2551
2552 pub(crate) fn get_interactive_metrics(&self) -> Ref<'_, ProgressiveWebMetrics> {
2553 self.interactive_time.borrow()
2554 }
2555
2556 pub(crate) fn has_recorded_tti_metric(&self) -> bool {
2557 self.get_interactive_metrics().get_tti().is_some()
2558 }
2559
2560 pub(crate) fn get_dom_content_loaded_event_start(&self) -> Option<CrossProcessInstant> {
2561 self.dom_content_loaded_event_start.get()
2562 }
2563
2564 pub(crate) fn get_dom_content_loaded_event_end(&self) -> Option<CrossProcessInstant> {
2565 self.dom_content_loaded_event_end.get()
2566 }
2567
2568 pub(crate) fn get_dom_complete(&self) -> Option<CrossProcessInstant> {
2569 self.dom_complete.get()
2570 }
2571
2572 pub(crate) fn get_top_level_dom_complete(&self) -> Option<CrossProcessInstant> {
2573 self.top_level_dom_complete.get()
2574 }
2575
2576 pub(crate) fn get_load_event_start(&self) -> Option<CrossProcessInstant> {
2577 self.load_event_start.get()
2578 }
2579
2580 pub(crate) fn get_load_event_end(&self) -> Option<CrossProcessInstant> {
2581 self.load_event_end.get()
2582 }
2583
2584 pub(crate) fn get_unload_event_start(&self) -> Option<CrossProcessInstant> {
2585 self.unload_event_start.get()
2586 }
2587
2588 pub(crate) fn get_unload_event_end(&self) -> Option<CrossProcessInstant> {
2589 self.unload_event_end.get()
2590 }
2591
2592 pub(crate) fn start_tti(&self) {
2593 if self.get_interactive_metrics().needs_tti() {
2594 self.tti_window.borrow_mut().start_window();
2595 }
2596 }
2597
2598 pub(crate) fn record_tti_if_necessary(&self) {
2602 if self.has_recorded_tti_metric() {
2603 return;
2604 }
2605 if self.tti_window.borrow().needs_check() {
2606 self.get_interactive_metrics()
2607 .maybe_set_tti(InteractiveFlag::TimeToInteractive(
2608 self.tti_window.borrow().get_start(),
2609 ));
2610 }
2611 }
2612
2613 fn fire_focus_event(
2615 &self,
2616 focus_event_type: FocusEventType,
2617 event_target: &EventTarget,
2618 related_target: Option<&EventTarget>,
2619 can_gc: CanGc,
2620 ) {
2621 let (event_name, does_bubble) = match focus_event_type {
2622 FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble),
2623 FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble),
2624 };
2625 let event = FocusEvent::new(
2626 &self.window,
2627 event_name,
2628 does_bubble,
2629 EventCancelable::NotCancelable,
2630 Some(&self.window),
2631 0i32,
2632 related_target,
2633 can_gc,
2634 );
2635 let event = event.upcast::<Event>();
2636 event.set_trusted(true);
2637 event.fire(event_target, can_gc);
2638 }
2639
2640 pub(crate) fn is_cookie_averse(&self) -> bool {
2642 !self.has_browsing_context || !url_has_network_scheme(&self.url())
2643 }
2644
2645 pub(crate) fn lookup_custom_element_definition(
2647 &self,
2648 namespace: &Namespace,
2649 local_name: &LocalName,
2650 is: Option<&LocalName>,
2651 ) -> Option<Rc<CustomElementDefinition>> {
2652 if *namespace != ns!(html) {
2654 return None;
2655 }
2656
2657 if !self.has_browsing_context {
2659 return None;
2660 }
2661
2662 let registry = self.window.CustomElements();
2664
2665 registry.lookup_definition(local_name, is)
2666 }
2667
2668 pub(crate) fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
2669 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2670 self.throw_on_dynamic_markup_insertion_counter
2671 .set(counter + 1);
2672 }
2673
2674 pub(crate) fn decrement_throw_on_dynamic_markup_insertion_counter(&self) {
2675 let counter = self.throw_on_dynamic_markup_insertion_counter.get();
2676 self.throw_on_dynamic_markup_insertion_counter
2677 .set(counter - 1);
2678 }
2679
2680 pub(crate) fn react_to_environment_changes(&self) {
2681 for image in self.responsive_images.borrow().iter() {
2682 image.react_to_environment_changes();
2683 }
2684 }
2685
2686 pub(crate) fn register_responsive_image(&self, img: &HTMLImageElement) {
2687 self.responsive_images.borrow_mut().push(Dom::from_ref(img));
2688 }
2689
2690 pub(crate) fn unregister_responsive_image(&self, img: &HTMLImageElement) {
2691 let index = self
2692 .responsive_images
2693 .borrow()
2694 .iter()
2695 .position(|x| **x == *img);
2696 if let Some(i) = index {
2697 self.responsive_images.borrow_mut().remove(i);
2698 }
2699 }
2700
2701 pub(crate) fn register_media_controls(&self, id: &str, controls: &ShadowRoot) {
2702 let did_have_these_media_controls = self
2703 .media_controls
2704 .borrow_mut()
2705 .insert(id.to_string(), Dom::from_ref(controls))
2706 .is_some();
2707 debug_assert!(
2708 !did_have_these_media_controls,
2709 "Trying to register known media controls"
2710 );
2711 }
2712
2713 pub(crate) fn unregister_media_controls(&self, id: &str) {
2714 let did_have_these_media_controls = self.media_controls.borrow_mut().remove(id).is_some();
2715 debug_assert!(
2716 did_have_these_media_controls,
2717 "Trying to unregister unknown media controls"
2718 );
2719 }
2720
2721 pub(crate) fn mark_canvas_as_dirty(&self, canvas: &Dom<HTMLCanvasElement>) {
2722 let mut dirty_canvases = self.dirty_canvases.borrow_mut();
2723 if dirty_canvases
2724 .iter()
2725 .any(|dirty_canvas| dirty_canvas == canvas)
2726 {
2727 return;
2728 }
2729 dirty_canvases.push(canvas.clone());
2730 }
2731
2732 pub(crate) fn needs_rendering_update(&self) -> bool {
2736 if !self.is_fully_active() {
2737 return false;
2738 }
2739 if !self.window().layout_blocked() &&
2740 (!self.restyle_reason().is_empty() ||
2741 self.window().layout().needs_new_display_list())
2742 {
2743 return true;
2744 }
2745 if !self.rendering_update_reasons.get().is_empty() {
2746 return true;
2747 }
2748 if self.event_handler.has_pending_input_events() {
2749 return true;
2750 }
2751 if self.has_pending_scroll_events() {
2752 return true;
2753 }
2754 if self.window().has_unhandled_resize_event() {
2755 return true;
2756 }
2757 if self.has_pending_animated_image_update.get() || !self.dirty_canvases.borrow().is_empty()
2758 {
2759 return true;
2760 }
2761
2762 false
2763 }
2764
2765 pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun {
2773 if self.render_blocking_element_count() > 0 {
2774 return Default::default();
2775 }
2776
2777 let mut results = ReflowPhasesRun::empty();
2778 if self.has_pending_animated_image_update.get() {
2779 self.image_animation_manager
2780 .borrow()
2781 .update_active_frames(&self.window, self.current_animation_timeline_value());
2782 self.has_pending_animated_image_update.set(false);
2783 results.insert(ReflowPhasesRun::UpdatedImageData);
2784 }
2785
2786 self.current_rendering_epoch
2787 .set(self.current_rendering_epoch.get().next());
2788 let current_rendering_epoch = self.current_rendering_epoch.get();
2789
2790 let image_keys: Vec<_> = self
2792 .dirty_canvases
2793 .borrow_mut()
2794 .drain(..)
2795 .filter_map(|canvas| canvas.update_rendering(current_rendering_epoch))
2796 .collect();
2797
2798 let pipeline_id = self.window().pipeline_id();
2801 if !image_keys.is_empty() {
2802 results.insert(ReflowPhasesRun::UpdatedImageData);
2803 self.waiting_on_canvas_image_updates.set(true);
2804 self.window().compositor_api().delay_new_frame_for_canvas(
2805 self.webview_id(),
2806 self.window().pipeline_id(),
2807 current_rendering_epoch,
2808 image_keys,
2809 );
2810 }
2811
2812 let results = results.union(self.window().reflow(ReflowGoal::UpdateTheRendering));
2813
2814 self.window().compositor_api().update_epoch(
2815 self.webview_id(),
2816 pipeline_id,
2817 current_rendering_epoch,
2818 );
2819
2820 results
2821 }
2822
2823 pub(crate) fn handle_no_longer_waiting_on_asynchronous_image_updates(&self) {
2824 self.waiting_on_canvas_image_updates.set(false);
2825 }
2826
2827 pub(crate) fn waiting_on_canvas_image_updates(&self) -> bool {
2828 self.waiting_on_canvas_image_updates.get()
2829 }
2830
2831 pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool {
2841 if !self.is_fully_active() {
2842 return false;
2843 }
2844
2845 let fonts = self.Fonts(can_gc);
2846 if !fonts.waiting_to_fullfill_promise() {
2847 return false;
2848 }
2849 if self.window().font_context().web_fonts_still_loading() != 0 {
2850 return false;
2851 }
2852 if self.ReadyState() != DocumentReadyState::Complete {
2853 return false;
2854 }
2855 if !self.restyle_reason().is_empty() {
2856 return false;
2857 }
2858 if !self.rendering_update_reasons.get().is_empty() {
2859 return false;
2860 }
2861
2862 let result = fonts.fulfill_ready_promise_if_needed(can_gc);
2863
2864 if result {
2868 self.add_rendering_update_reason(RenderingUpdateReason::FontReadyPromiseFulfilled);
2869 }
2870
2871 result
2872 }
2873
2874 pub(crate) fn id_map(
2875 &self,
2876 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2877 self.id_map.borrow()
2878 }
2879
2880 pub(crate) fn name_map(
2881 &self,
2882 ) -> Ref<'_, HashMapTracedValues<Atom, Vec<Dom<Element>>, FxBuildHasher>> {
2883 self.name_map.borrow()
2884 }
2885
2886 pub(crate) fn add_resize_observer(&self, resize_observer: &ResizeObserver) {
2888 self.resize_observers
2889 .borrow_mut()
2890 .push(Dom::from_ref(resize_observer));
2891 }
2892
2893 pub(crate) fn has_resize_observers(&self) -> bool {
2895 !self.resize_observers.borrow().is_empty()
2896 }
2897
2898 pub(crate) fn gather_active_resize_observations_at_depth(
2901 &self,
2902 depth: &ResizeObservationDepth,
2903 ) -> bool {
2904 let mut has_active_resize_observations = false;
2905 for observer in self.resize_observers.borrow_mut().iter_mut() {
2906 observer.gather_active_resize_observations_at_depth(
2907 depth,
2908 &mut has_active_resize_observations,
2909 );
2910 }
2911 has_active_resize_observations
2912 }
2913
2914 pub(crate) fn broadcast_active_resize_observations(
2916 &self,
2917 can_gc: CanGc,
2918 ) -> ResizeObservationDepth {
2919 let mut shallowest = ResizeObservationDepth::max();
2920 let iterator: Vec<DomRoot<ResizeObserver>> = self
2924 .resize_observers
2925 .borrow()
2926 .iter()
2927 .cloned()
2928 .map(|obs| DomRoot::from_ref(&*obs))
2929 .collect();
2930 for observer in iterator {
2931 observer.broadcast_active_resize_observations(&mut shallowest, can_gc);
2932 }
2933 shallowest
2934 }
2935
2936 pub(crate) fn has_skipped_resize_observations(&self) -> bool {
2938 self.resize_observers
2939 .borrow()
2940 .iter()
2941 .any(|observer| observer.has_skipped_resize_observations())
2942 }
2943
2944 pub(crate) fn deliver_resize_loop_error_notification(&self, can_gc: CanGc) {
2946 let error_info: ErrorInfo = crate::dom::bindings::error::ErrorInfo {
2947 message: "ResizeObserver loop completed with undelivered notifications.".to_string(),
2948 ..Default::default()
2949 };
2950 self.window
2951 .as_global_scope()
2952 .report_an_error(error_info, HandleValue::null(), can_gc);
2953 }
2954
2955 pub(crate) fn status_code(&self) -> Option<u16> {
2956 self.status_code
2957 }
2958
2959 pub(crate) fn encoding_parse_a_url(&self, url: &str) -> Result<ServoUrl, url::ParseError> {
2961 let encoding = self.encoding.get();
2967
2968 let base_url = self.base_url();
2974
2975 url::Url::options()
2977 .base_url(Some(base_url.as_url()))
2978 .encoding_override(Some(&|input| {
2979 servo_url::encoding::encode_as_url_query_string(input, encoding)
2980 }))
2981 .parse(url)
2982 .map(ServoUrl::from)
2983 }
2984
2985 pub(crate) fn allowed_to_use_feature(&self, _feature: PermissionName) -> bool {
2987 if !self.has_browsing_context {
2989 return false;
2990 }
2991
2992 if !self.is_fully_active() {
2994 return false;
2995 }
2996
2997 true
3003 }
3004
3005 pub(crate) fn add_intersection_observer(&self, intersection_observer: &IntersectionObserver) {
3008 self.intersection_observers
3009 .borrow_mut()
3010 .push(Dom::from_ref(intersection_observer));
3011 }
3012
3013 pub(crate) fn remove_intersection_observer(
3017 &self,
3018 intersection_observer: &IntersectionObserver,
3019 ) {
3020 self.intersection_observers
3021 .borrow_mut()
3022 .retain(|observer| *observer != intersection_observer)
3023 }
3024
3025 pub(crate) fn update_intersection_observer_steps(
3027 &self,
3028 time: CrossProcessInstant,
3029 can_gc: CanGc,
3030 ) {
3031 for intersection_observer in &*self.intersection_observers.borrow() {
3033 self.update_single_intersection_observer_steps(intersection_observer, time, can_gc);
3034 }
3035 }
3036
3037 fn update_single_intersection_observer_steps(
3039 &self,
3040 intersection_observer: &IntersectionObserver,
3041 time: CrossProcessInstant,
3042 can_gc: CanGc,
3043 ) {
3044 let root_bounds = intersection_observer.root_intersection_rectangle(self);
3047
3048 intersection_observer.update_intersection_observations_steps(
3052 self,
3053 time,
3054 root_bounds,
3055 can_gc,
3056 );
3057 }
3058
3059 pub(crate) fn notify_intersection_observers(&self, can_gc: CanGc) {
3061 self.intersection_observer_task_queued.set(false);
3064
3065 rooted_vec!(let notify_list <- self.intersection_observers.clone().take().into_iter());
3070
3071 for intersection_observer in notify_list.iter() {
3074 intersection_observer.invoke_callback_if_necessary(can_gc);
3076 }
3077 }
3078
3079 pub(crate) fn queue_an_intersection_observer_task(&self) {
3081 if self.intersection_observer_task_queued.get() {
3084 return;
3085 }
3086
3087 self.intersection_observer_task_queued.set(true);
3090
3091 let document = Trusted::new(self);
3095 self.owner_global()
3096 .task_manager()
3097 .intersection_observer_task_source()
3098 .queue(task!(notify_intersection_observers: move || {
3099 document.root().notify_intersection_observers(CanGc::note());
3100 }));
3101 }
3102
3103 pub(crate) fn handle_paint_metric(
3104 &self,
3105 metric_type: ProgressiveWebMetricType,
3106 metric_value: CrossProcessInstant,
3107 first_reflow: bool,
3108 can_gc: CanGc,
3109 ) {
3110 let metrics = self.interactive_time.borrow();
3111 match metric_type {
3112 ProgressiveWebMetricType::FirstPaint |
3113 ProgressiveWebMetricType::FirstContentfulPaint => {
3114 let binding = PerformancePaintTiming::new(
3115 self.window.as_global_scope(),
3116 metric_type,
3117 metric_value,
3118 can_gc,
3119 );
3120 metrics.set_performance_paint_metric(metric_value, first_reflow, metric_type);
3121 let entry = binding.upcast::<PerformanceEntry>();
3122 self.window.Performance().queue_entry(entry);
3123 },
3124 ProgressiveWebMetricType::LargestContentfulPaint { area, lcp_type } => {
3125 let binding = LargestContentfulPaint::new(
3126 self.window.as_global_scope(),
3127 metric_type,
3128 metric_value,
3129 can_gc,
3130 );
3131 metrics.set_largest_contentful_paint(metric_value, area, lcp_type);
3132 let entry = binding.upcast::<PerformanceEntry>();
3133 self.window.Performance().queue_entry(entry);
3134 },
3135 ProgressiveWebMetricType::TimeToInteractive => {
3136 unreachable!("Unexpected non-paint metric.")
3137 },
3138 }
3139 }
3140
3141 fn write(
3143 &self,
3144 text: Vec<TrustedHTMLOrString>,
3145 line_feed: bool,
3146 containing_class: &str,
3147 field: &str,
3148 can_gc: CanGc,
3149 ) -> ErrorResult {
3150 let mut strings: Vec<String> = Vec::with_capacity(text.len());
3152 let mut is_trusted = true;
3154 for value in text {
3156 match value {
3157 TrustedHTMLOrString::TrustedHTML(trusted_html) => {
3159 strings.push(trusted_html.to_string().to_owned());
3160 },
3161 TrustedHTMLOrString::String(str_) => {
3162 is_trusted = false;
3164 strings.push(str_.into());
3166 },
3167 };
3168 }
3169 let mut string = itertools::join(strings, "");
3170 if !is_trusted {
3174 string = TrustedHTML::get_trusted_script_compliant_string(
3175 &self.global(),
3176 TrustedHTMLOrString::String(string.into()),
3177 &format!("{} {}", containing_class, field),
3178 can_gc,
3179 )?
3180 .str()
3181 .to_owned();
3182 }
3183 if line_feed {
3185 string.push('\n');
3186 }
3187 if !self.is_html_document() {
3189 return Err(Error::InvalidState(None));
3190 }
3191
3192 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
3195 return Err(Error::InvalidState(None));
3196 }
3197
3198 if !self.is_active() || self.active_parser_was_aborted.get() {
3200 return Ok(());
3201 }
3202
3203 let parser = match self.get_current_parser() {
3204 Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
3205 _ => {
3207 if self.is_prompting_or_unloading() ||
3210 self.ignore_destructive_writes_counter.get() > 0
3211 {
3212 return Ok(());
3213 }
3214 self.Open(None, None, can_gc)?;
3216 self.get_current_parser().unwrap()
3217 },
3218 };
3219
3220 parser.write(string.into(), can_gc);
3222
3223 Ok(())
3224 }
3225
3226 pub(crate) fn details_name_groups(&self) -> RefMut<'_, DetailsNameGroups> {
3227 RefMut::map(
3228 self.details_name_groups.borrow_mut(),
3229 |details_name_groups| details_name_groups.get_or_insert_default(),
3230 )
3231 }
3232}
3233
3234#[derive(MallocSizeOf, PartialEq)]
3235pub(crate) enum DocumentSource {
3236 FromParser,
3237 NotFromParser,
3238}
3239
3240pub(crate) trait LayoutDocumentHelpers<'dom> {
3241 fn is_html_document_for_layout(&self) -> bool;
3242 fn quirks_mode(self) -> QuirksMode;
3243 fn style_shared_lock(self) -> &'dom StyleSharedRwLock;
3244 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>>;
3245 fn shadow_roots_styles_changed(self) -> bool;
3246 fn flush_shadow_roots_stylesheets(self);
3247}
3248
3249#[expect(unsafe_code)]
3250impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
3251 #[inline]
3252 fn is_html_document_for_layout(&self) -> bool {
3253 self.unsafe_get().is_html_document
3254 }
3255
3256 #[inline]
3257 fn quirks_mode(self) -> QuirksMode {
3258 self.unsafe_get().quirks_mode.get()
3259 }
3260
3261 #[inline]
3262 fn style_shared_lock(self) -> &'dom StyleSharedRwLock {
3263 self.unsafe_get().style_shared_lock()
3264 }
3265
3266 #[inline]
3267 fn shadow_roots(self) -> Vec<LayoutDom<'dom, ShadowRoot>> {
3268 unsafe {
3273 self.unsafe_get()
3274 .shadow_roots
3275 .borrow_for_layout()
3276 .iter()
3277 .map(|sr| sr.to_layout())
3278 .collect()
3279 }
3280 }
3281
3282 #[inline]
3283 fn shadow_roots_styles_changed(self) -> bool {
3284 self.unsafe_get().shadow_roots_styles_changed.get()
3285 }
3286
3287 #[inline]
3288 fn flush_shadow_roots_stylesheets(self) {
3289 (*self.unsafe_get()).flush_shadow_roots_stylesheets()
3290 }
3291}
3292
3293fn get_registrable_domain_suffix_of_or_is_equal_to(
3297 host_suffix_string: &DOMString,
3298 original_host: Host,
3299) -> Option<Host> {
3300 if host_suffix_string.is_empty() {
3302 return None;
3303 }
3304
3305 let host = match Host::parse(&host_suffix_string.str()) {
3307 Ok(host) => host,
3308 Err(_) => return None,
3309 };
3310
3311 if host != original_host {
3313 let host = match host {
3315 Host::Domain(ref host) => host,
3316 _ => return None,
3317 };
3318 let original_host = match original_host {
3319 Host::Domain(ref original_host) => original_host,
3320 _ => return None,
3321 };
3322
3323 let index = original_host.len().checked_sub(host.len())?;
3325 let (prefix, suffix) = original_host.split_at(index);
3326
3327 if !prefix.ends_with('.') {
3328 return None;
3329 }
3330 if suffix != host {
3331 return None;
3332 }
3333
3334 if is_pub_domain(host) {
3336 return None;
3337 }
3338 }
3339
3340 Some(host)
3342}
3343
3344fn url_has_network_scheme(url: &ServoUrl) -> bool {
3346 matches!(url.scheme(), "ftp" | "http" | "https")
3347}
3348
3349#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
3350pub(crate) enum HasBrowsingContext {
3351 No,
3352 Yes,
3353}
3354
3355impl Document {
3356 #[allow(clippy::too_many_arguments)]
3357 pub(crate) fn new_inherited(
3358 window: &Window,
3359 has_browsing_context: HasBrowsingContext,
3360 url: Option<ServoUrl>,
3361 origin: MutableOrigin,
3362 is_html_document: IsHTMLDocument,
3363 content_type: Option<Mime>,
3364 last_modified: Option<String>,
3365 activity: DocumentActivity,
3366 source: DocumentSource,
3367 doc_loader: DocumentLoader,
3368 referrer: Option<String>,
3369 status_code: Option<u16>,
3370 canceller: FetchCanceller,
3371 is_initial_about_blank: bool,
3372 allow_declarative_shadow_roots: bool,
3373 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3374 has_trustworthy_ancestor_origin: bool,
3375 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3376 creation_sandboxing_flag_set: SandboxingFlagSet,
3377 ) -> Document {
3378 let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
3379
3380 let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser {
3381 (DocumentReadyState::Loading, false)
3382 } else {
3383 (DocumentReadyState::Complete, true)
3384 };
3385
3386 let frame_type = match window.is_top_level() {
3387 true => TimerMetadataFrameType::RootWindow,
3388 false => TimerMetadataFrameType::IFrame,
3389 };
3390 let interactive_time = ProgressiveWebMetrics::new(
3391 window.time_profiler_chan().clone(),
3392 url.clone(),
3393 frame_type,
3394 );
3395
3396 let content_type = content_type.unwrap_or_else(|| {
3397 match is_html_document {
3398 IsHTMLDocument::HTMLDocument => "text/html",
3400 IsHTMLDocument::NonHTMLDocument => "application/xml",
3402 }
3403 .parse()
3404 .unwrap()
3405 });
3406
3407 let encoding = content_type
3408 .get_parameter(CHARSET)
3409 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
3410 .unwrap_or(UTF_8);
3411
3412 let has_focus = window.parent_info().is_none();
3413
3414 let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
3415
3416 Document {
3417 node: Node::new_document_node(),
3418 document_or_shadow_root: DocumentOrShadowRoot::new(window),
3419 window: Dom::from_ref(window),
3420 has_browsing_context,
3421 implementation: Default::default(),
3422 content_type,
3423 last_modified,
3424 url: DomRefCell::new(url),
3425 quirks_mode: Cell::new(QuirksMode::NoQuirks),
3427 event_handler: DocumentEventHandler::new(window),
3428 embedder_controls: DocumentEmbedderControls::new(window),
3429 id_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3430 name_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3431 encoding: Cell::new(encoding),
3433 is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
3434 activity: Cell::new(activity),
3435 tag_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3436 tagns_map: DomRefCell::new(HashMapTracedValues::new_fx()),
3437 classes_map: DomRefCell::new(HashMapTracedValues::new()),
3438 images: Default::default(),
3439 embeds: Default::default(),
3440 links: Default::default(),
3441 forms: Default::default(),
3442 scripts: Default::default(),
3443 anchors: Default::default(),
3444 applets: Default::default(),
3445 iframes: RefCell::new(IFrameCollection::new()),
3446 style_shared_lock: {
3447 static PER_PROCESS_AUTHOR_SHARED_LOCK: LazyLock<StyleSharedRwLock> =
3454 LazyLock::new(StyleSharedRwLock::new);
3455
3456 PER_PROCESS_AUTHOR_SHARED_LOCK.clone()
3457 },
3459 stylesheets: DomRefCell::new(DocumentStylesheetSet::new()),
3460 stylesheet_list: MutNullableDom::new(None),
3461 ready_state: Cell::new(ready_state),
3462 domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
3463 focus_transaction: DomRefCell::new(None),
3464 focused: Default::default(),
3465 focus_sequence: Cell::new(FocusSequenceNumber::default()),
3466 has_focus: Cell::new(has_focus),
3467 current_script: Default::default(),
3468 pending_parsing_blocking_script: Default::default(),
3469 script_blocking_stylesheets_count: Default::default(),
3470 render_blocking_element_count: Default::default(),
3471 deferred_scripts: Default::default(),
3472 asap_in_order_scripts_list: Default::default(),
3473 asap_scripts_set: Default::default(),
3474 animation_frame_ident: Cell::new(0),
3475 animation_frame_list: DomRefCell::new(VecDeque::new()),
3476 running_animation_callbacks: Cell::new(false),
3477 loader: DomRefCell::new(doc_loader),
3478 current_parser: Default::default(),
3479 base_element: Default::default(),
3480 appropriate_template_contents_owner_document: Default::default(),
3481 pending_restyles: DomRefCell::new(FxHashMap::default()),
3482 needs_restyle: Cell::new(RestyleReason::DOMChanged),
3483 dom_interactive: Cell::new(Default::default()),
3484 dom_content_loaded_event_start: Cell::new(Default::default()),
3485 dom_content_loaded_event_end: Cell::new(Default::default()),
3486 dom_complete: Cell::new(Default::default()),
3487 top_level_dom_complete: Cell::new(Default::default()),
3488 load_event_start: Cell::new(Default::default()),
3489 load_event_end: Cell::new(Default::default()),
3490 unload_event_start: Cell::new(Default::default()),
3491 unload_event_end: Cell::new(Default::default()),
3492 https_state: Cell::new(HttpsState::None),
3493 origin,
3494 referrer,
3495 target_element: MutNullableDom::new(None),
3496 policy_container: DomRefCell::new(PolicyContainer::default()),
3497 preloaded_resources: Default::default(),
3498 ignore_destructive_writes_counter: Default::default(),
3499 ignore_opens_during_unload_counter: Default::default(),
3500 spurious_animation_frames: Cell::new(0),
3501 dom_count: Cell::new(1),
3502 fullscreen_element: MutNullableDom::new(None),
3503 form_id_listener_map: Default::default(),
3504 interactive_time: DomRefCell::new(interactive_time),
3505 tti_window: DomRefCell::new(InteractiveWindow::default()),
3506 canceller,
3507 throw_on_dynamic_markup_insertion_counter: Cell::new(0),
3508 page_showing: Cell::new(false),
3509 salvageable: Cell::new(true),
3510 active_parser_was_aborted: Cell::new(false),
3511 fired_unload: Cell::new(false),
3512 responsive_images: Default::default(),
3513 redirect_count: Cell::new(0),
3514 completely_loaded: Cell::new(false),
3515 script_and_layout_blockers: Cell::new(0),
3516 delayed_tasks: Default::default(),
3517 shadow_roots: DomRefCell::new(HashSet::new()),
3518 shadow_roots_styles_changed: Cell::new(false),
3519 media_controls: DomRefCell::new(HashMap::new()),
3520 dirty_canvases: DomRefCell::new(Default::default()),
3521 has_pending_animated_image_update: Cell::new(false),
3522 selection: MutNullableDom::new(None),
3523 animation_timeline: if pref!(layout_animations_test_enabled) {
3524 DomRefCell::new(AnimationTimeline::new_for_testing())
3525 } else {
3526 DomRefCell::new(AnimationTimeline::new())
3527 },
3528 animations: Animations::new(),
3529 image_animation_manager: DomRefCell::new(ImageAnimationManager::default()),
3530 dirty_root: Default::default(),
3531 declarative_refresh: Default::default(),
3532 resize_observers: Default::default(),
3533 fonts: Default::default(),
3534 visibility_state: Cell::new(DocumentVisibilityState::Hidden),
3535 status_code,
3536 is_initial_about_blank: Cell::new(is_initial_about_blank),
3537 allow_declarative_shadow_roots: Cell::new(allow_declarative_shadow_roots),
3538 inherited_insecure_requests_policy: Cell::new(inherited_insecure_requests_policy),
3539 has_trustworthy_ancestor_origin: Cell::new(has_trustworthy_ancestor_origin),
3540 intersection_observer_task_queued: Cell::new(false),
3541 intersection_observers: Default::default(),
3542 highlighted_dom_node: Default::default(),
3543 adopted_stylesheets: Default::default(),
3544 adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
3545 pending_scroll_event_targets: Default::default(),
3546 rendering_update_reasons: Default::default(),
3547 waiting_on_canvas_image_updates: Cell::new(false),
3548 current_rendering_epoch: Default::default(),
3549 custom_element_reaction_stack,
3550 active_sandboxing_flag_set: Cell::new(SandboxingFlagSet::empty()),
3551 creation_sandboxing_flag_set: Cell::new(creation_sandboxing_flag_set),
3552 favicon: RefCell::new(None),
3553 websockets: DOMTracker::new(),
3554 details_name_groups: Default::default(),
3555 protocol_handler_automation_mode: Default::default(),
3556 layout_animations_test_enabled: pref!(layout_animations_test_enabled),
3557 }
3558 }
3559
3560 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
3562 if let Some(csp_list) = self.get_csp_list() {
3563 for policy in &csp_list.0 {
3564 if policy.contains_a_directive_whose_name_is("upgrade-insecure-requests") &&
3565 policy.disposition == PolicyDisposition::Enforce
3566 {
3567 return InsecureRequestsPolicy::Upgrade;
3568 }
3569 }
3570 }
3571
3572 self.inherited_insecure_requests_policy
3573 .get()
3574 .unwrap_or(InsecureRequestsPolicy::DoNotUpgrade)
3575 }
3576
3577 pub(crate) fn event_handler(&self) -> &DocumentEventHandler {
3579 &self.event_handler
3580 }
3581
3582 pub(crate) fn embedder_controls(&self) -> &DocumentEmbedderControls {
3584 &self.embedder_controls
3585 }
3586
3587 fn has_pending_scroll_events(&self) -> bool {
3590 !self.pending_scroll_event_targets.borrow().is_empty()
3591 }
3592
3593 pub(crate) fn add_rendering_update_reason(&self, reason: RenderingUpdateReason) {
3596 self.rendering_update_reasons
3597 .set(self.rendering_update_reasons.get().union(reason));
3598 }
3599
3600 pub(crate) fn clear_rendering_update_reasons(&self) {
3602 self.rendering_update_reasons
3603 .set(RenderingUpdateReason::empty())
3604 }
3605
3606 pub(crate) fn add_script_and_layout_blocker(&self) {
3613 self.script_and_layout_blockers
3614 .set(self.script_and_layout_blockers.get() + 1);
3615 }
3616
3617 pub(crate) fn remove_script_and_layout_blocker(&self) {
3621 assert!(self.script_and_layout_blockers.get() > 0);
3622 self.script_and_layout_blockers
3623 .set(self.script_and_layout_blockers.get() - 1);
3624 while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
3625 {
3626 let task = self.delayed_tasks.borrow_mut().remove(0);
3627 task.run_box();
3628 }
3629 }
3630
3631 pub(crate) fn add_delayed_task<T: 'static + NonSendTaskBox>(&self, task: T) {
3633 self.delayed_tasks.borrow_mut().push(Box::new(task));
3634 }
3635
3636 pub(crate) fn ensure_safe_to_run_script_or_layout(&self) {
3639 assert_eq!(
3640 self.script_and_layout_blockers.get(),
3641 0,
3642 "Attempt to use script or layout while DOM not in a stable state"
3643 );
3644 }
3645
3646 #[allow(clippy::too_many_arguments)]
3647 pub(crate) fn new(
3648 window: &Window,
3649 has_browsing_context: HasBrowsingContext,
3650 url: Option<ServoUrl>,
3651 origin: MutableOrigin,
3652 doctype: IsHTMLDocument,
3653 content_type: Option<Mime>,
3654 last_modified: Option<String>,
3655 activity: DocumentActivity,
3656 source: DocumentSource,
3657 doc_loader: DocumentLoader,
3658 referrer: Option<String>,
3659 status_code: Option<u16>,
3660 canceller: FetchCanceller,
3661 is_initial_about_blank: bool,
3662 allow_declarative_shadow_roots: bool,
3663 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3664 has_trustworthy_ancestor_origin: bool,
3665 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3666 creation_sandboxing_flag_set: SandboxingFlagSet,
3667 can_gc: CanGc,
3668 ) -> DomRoot<Document> {
3669 Self::new_with_proto(
3670 window,
3671 None,
3672 has_browsing_context,
3673 url,
3674 origin,
3675 doctype,
3676 content_type,
3677 last_modified,
3678 activity,
3679 source,
3680 doc_loader,
3681 referrer,
3682 status_code,
3683 canceller,
3684 is_initial_about_blank,
3685 allow_declarative_shadow_roots,
3686 inherited_insecure_requests_policy,
3687 has_trustworthy_ancestor_origin,
3688 custom_element_reaction_stack,
3689 creation_sandboxing_flag_set,
3690 can_gc,
3691 )
3692 }
3693
3694 #[allow(clippy::too_many_arguments)]
3695 fn new_with_proto(
3696 window: &Window,
3697 proto: Option<HandleObject>,
3698 has_browsing_context: HasBrowsingContext,
3699 url: Option<ServoUrl>,
3700 origin: MutableOrigin,
3701 doctype: IsHTMLDocument,
3702 content_type: Option<Mime>,
3703 last_modified: Option<String>,
3704 activity: DocumentActivity,
3705 source: DocumentSource,
3706 doc_loader: DocumentLoader,
3707 referrer: Option<String>,
3708 status_code: Option<u16>,
3709 canceller: FetchCanceller,
3710 is_initial_about_blank: bool,
3711 allow_declarative_shadow_roots: bool,
3712 inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
3713 has_trustworthy_ancestor_origin: bool,
3714 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
3715 creation_sandboxing_flag_set: SandboxingFlagSet,
3716 can_gc: CanGc,
3717 ) -> DomRoot<Document> {
3718 let document = reflect_dom_object_with_proto(
3719 Box::new(Document::new_inherited(
3720 window,
3721 has_browsing_context,
3722 url,
3723 origin,
3724 doctype,
3725 content_type,
3726 last_modified,
3727 activity,
3728 source,
3729 doc_loader,
3730 referrer,
3731 status_code,
3732 canceller,
3733 is_initial_about_blank,
3734 allow_declarative_shadow_roots,
3735 inherited_insecure_requests_policy,
3736 has_trustworthy_ancestor_origin,
3737 custom_element_reaction_stack,
3738 creation_sandboxing_flag_set,
3739 )),
3740 window,
3741 proto,
3742 can_gc,
3743 );
3744 {
3745 let node = document.upcast::<Node>();
3746 node.set_owner_doc(&document);
3747 }
3748 document
3749 }
3750
3751 pub(crate) fn get_redirect_count(&self) -> u16 {
3752 self.redirect_count.get()
3753 }
3754
3755 pub(crate) fn set_redirect_count(&self, count: u16) {
3756 self.redirect_count.set(count)
3757 }
3758
3759 pub(crate) fn elements_by_name_count(&self, name: &DOMString) -> u32 {
3760 if name.is_empty() {
3761 return 0;
3762 }
3763 self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
3764 }
3765
3766 pub(crate) fn nth_element_by_name(
3767 &self,
3768 index: u32,
3769 name: &DOMString,
3770 ) -> Option<DomRoot<Node>> {
3771 if name.is_empty() {
3772 return None;
3773 }
3774 self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
3775 }
3776
3777 fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
3780 let element = match node.downcast::<Element>() {
3781 Some(element) => element,
3782 None => return false,
3783 };
3784 if element.namespace() != &ns!(html) {
3785 return false;
3786 }
3787 element.get_name().is_some_and(|n| &*n == name)
3788 }
3789
3790 fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
3791 let doc = self.GetDocumentElement();
3792 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3793 maybe_node
3794 .iter()
3795 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3796 .filter(|node| callback(node))
3797 .count() as u32
3798 }
3799
3800 fn nth_in_node_list<F: Fn(&Node) -> bool>(
3801 &self,
3802 index: u32,
3803 callback: F,
3804 ) -> Option<DomRoot<Node>> {
3805 let doc = self.GetDocumentElement();
3806 let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
3807 maybe_node
3808 .iter()
3809 .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
3810 .filter(|node| callback(node))
3811 .nth(index as usize)
3812 .map(|n| DomRoot::from_ref(&*n))
3813 }
3814
3815 fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
3816 self.GetDocumentElement().and_then(DomRoot::downcast)
3817 }
3818
3819 pub(crate) fn style_shared_lock(&self) -> &StyleSharedRwLock {
3821 &self.style_shared_lock
3822 }
3823
3824 pub(crate) fn flush_stylesheets_for_reflow(&self) -> bool {
3826 let mut stylesheets = self.stylesheets.borrow_mut();
3833 let have_changed = stylesheets.has_changed();
3834 stylesheets.flush_without_invalidation();
3835 have_changed
3836 }
3837
3838 pub(crate) fn salvageable(&self) -> bool {
3839 self.salvageable.get()
3840 }
3841
3842 pub(crate) fn appropriate_template_contents_owner_document(
3844 &self,
3845 can_gc: CanGc,
3846 ) -> DomRoot<Document> {
3847 self.appropriate_template_contents_owner_document
3848 .or_init(|| {
3849 let doctype = if self.is_html_document {
3850 IsHTMLDocument::HTMLDocument
3851 } else {
3852 IsHTMLDocument::NonHTMLDocument
3853 };
3854 let new_doc = Document::new(
3855 self.window(),
3856 HasBrowsingContext::No,
3857 None,
3858 MutableOrigin::new(ImmutableOrigin::new_opaque()),
3860 doctype,
3861 None,
3862 None,
3863 DocumentActivity::Inactive,
3864 DocumentSource::NotFromParser,
3865 DocumentLoader::new(&self.loader()),
3866 None,
3867 None,
3868 Default::default(),
3869 false,
3870 self.allow_declarative_shadow_roots(),
3871 Some(self.insecure_requests_policy()),
3872 self.has_trustworthy_ancestor_or_current_origin(),
3873 self.custom_element_reaction_stack.clone(),
3874 self.creation_sandboxing_flag_set(),
3875 can_gc,
3876 );
3877 new_doc
3878 .appropriate_template_contents_owner_document
3879 .set(Some(&new_doc));
3880 new_doc
3881 })
3882 }
3883
3884 pub(crate) fn get_element_by_id(&self, id: &Atom) -> Option<DomRoot<Element>> {
3885 self.id_map
3886 .borrow()
3887 .get(id)
3888 .map(|elements| DomRoot::from_ref(&*elements[0]))
3889 }
3890
3891 pub(crate) fn ensure_pending_restyle(&self, el: &Element) -> RefMut<'_, PendingRestyle> {
3892 let map = self.pending_restyles.borrow_mut();
3893 RefMut::map(map, |m| {
3894 &mut m
3895 .entry(Dom::from_ref(el))
3896 .or_insert_with(|| NoTrace(PendingRestyle::default()))
3897 .0
3898 })
3899 }
3900
3901 pub(crate) fn element_attr_will_change(&self, el: &Element, attr: &Attr) {
3902 let mut entry = self.ensure_pending_restyle(el);
3908 if entry.snapshot.is_none() {
3909 entry.snapshot = Some(Snapshot::new());
3910 }
3911 if attr.local_name() == &local_name!("style") {
3912 entry.hint.insert(RestyleHint::RESTYLE_STYLE_ATTRIBUTE);
3913 }
3914
3915 if vtable_for(el.upcast()).attribute_affects_presentational_hints(attr) {
3916 entry.hint.insert(RestyleHint::RESTYLE_SELF);
3917 }
3918
3919 let snapshot = entry.snapshot.as_mut().unwrap();
3920 if attr.local_name() == &local_name!("id") {
3921 if snapshot.id_changed {
3922 return;
3923 }
3924 snapshot.id_changed = true;
3925 } else if attr.local_name() == &local_name!("class") {
3926 if snapshot.class_changed {
3927 return;
3928 }
3929 snapshot.class_changed = true;
3930 } else {
3931 snapshot.other_attributes_changed = true;
3932 }
3933 let local_name = style::LocalName::cast(attr.local_name());
3934 if !snapshot.changed_attrs.contains(local_name) {
3935 snapshot.changed_attrs.push(local_name.clone());
3936 }
3937 if snapshot.attrs.is_none() {
3938 let attrs = el
3939 .attrs()
3940 .iter()
3941 .map(|attr| (attr.identifier().clone(), attr.value().clone()))
3942 .collect();
3943 snapshot.attrs = Some(attrs);
3944 }
3945 }
3946
3947 pub(crate) fn set_referrer_policy(&self, policy: ReferrerPolicy) {
3948 self.policy_container
3949 .borrow_mut()
3950 .set_referrer_policy(policy);
3951 }
3952
3953 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
3954 self.policy_container.borrow().get_referrer_policy()
3955 }
3956
3957 pub(crate) fn set_target_element(&self, node: Option<&Element>) {
3958 if let Some(ref element) = self.target_element.get() {
3959 element.set_target_state(false);
3960 }
3961
3962 self.target_element.set(node);
3963
3964 if let Some(ref element) = self.target_element.get() {
3965 element.set_target_state(true);
3966 }
3967 }
3968
3969 pub(crate) fn incr_ignore_destructive_writes_counter(&self) {
3970 self.ignore_destructive_writes_counter
3971 .set(self.ignore_destructive_writes_counter.get() + 1);
3972 }
3973
3974 pub(crate) fn decr_ignore_destructive_writes_counter(&self) {
3975 self.ignore_destructive_writes_counter
3976 .set(self.ignore_destructive_writes_counter.get() - 1);
3977 }
3978
3979 pub(crate) fn is_prompting_or_unloading(&self) -> bool {
3980 self.ignore_opens_during_unload_counter.get() > 0
3981 }
3982
3983 fn incr_ignore_opens_during_unload_counter(&self) {
3984 self.ignore_opens_during_unload_counter
3985 .set(self.ignore_opens_during_unload_counter.get() + 1);
3986 }
3987
3988 fn decr_ignore_opens_during_unload_counter(&self) {
3989 self.ignore_opens_during_unload_counter
3990 .set(self.ignore_opens_during_unload_counter.get() - 1);
3991 }
3992
3993 pub(crate) fn enter_fullscreen(&self, pending: &Element, can_gc: CanGc) -> Rc<Promise> {
3995 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
3997 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
3998 let mut error = false;
3999
4000 match *pending.namespace() {
4003 ns!(mathml) => {
4004 if pending.local_name().as_ref() != "math" {
4005 error = true;
4006 }
4007 },
4008 ns!(svg) => {
4009 if pending.local_name().as_ref() != "svg" {
4010 error = true;
4011 }
4012 },
4013 ns!(html) => (),
4014 _ => error = true,
4015 }
4016 if !pending.fullscreen_element_ready_check() {
4018 error = true;
4019 }
4020
4021 if pref!(dom_fullscreen_test) {
4022 info!("Tests don't really enter fullscreen.");
4025 } else {
4026 warn!("Fullscreen not supported yet");
4029 }
4030
4031 let window = self.window();
4034 if !error {
4036 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), true);
4037 self.send_to_embedder(event);
4038 }
4039
4040 let pipeline_id = self.window().pipeline_id();
4041
4042 let trusted_pending = Trusted::new(pending);
4044 let trusted_promise = TrustedPromise::new(promise.clone());
4045 let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
4046 let script_msg = CommonScriptMsg::Task(
4049 ScriptThreadEventCategory::EnterFullscreen,
4050 handler,
4051 Some(pipeline_id),
4052 TaskSourceName::DOMManipulation,
4053 );
4054 let msg = MainThreadScriptMsg::Common(script_msg);
4055 window.main_thread_script_chan().send(msg).unwrap();
4056
4057 promise
4058 }
4059
4060 pub(crate) fn exit_fullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
4062 let global = self.global();
4063 let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
4065 let promise = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
4066 if self.fullscreen_element.get().is_none() {
4068 promise.reject_error(Error::Type(String::from("fullscreen is null")), can_gc);
4069 return promise;
4070 }
4071 let element = self.fullscreen_element.get().unwrap();
4073
4074 let window = self.window();
4077 let event = EmbedderMsg::NotifyFullscreenStateChanged(self.webview_id(), false);
4079 self.send_to_embedder(event);
4080
4081 let trusted_element = Trusted::new(&*element);
4083 let trusted_promise = TrustedPromise::new(promise.clone());
4084 let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
4085 let pipeline_id = Some(global.pipeline_id());
4086 let script_msg = CommonScriptMsg::Task(
4089 ScriptThreadEventCategory::ExitFullscreen,
4090 handler,
4091 pipeline_id,
4092 TaskSourceName::DOMManipulation,
4093 );
4094 let msg = MainThreadScriptMsg::Common(script_msg);
4095 window.main_thread_script_chan().send(msg).unwrap();
4096
4097 promise
4098 }
4099
4100 pub(crate) fn set_fullscreen_element(&self, element: Option<&Element>) {
4101 self.fullscreen_element.set(element);
4102 }
4103
4104 pub(crate) fn get_allow_fullscreen(&self) -> bool {
4105 match self.browsing_context() {
4107 None => false,
4109 Some(_) => {
4110 let window = self.window();
4112 if window.is_top_level() {
4113 true
4114 } else {
4115 window
4117 .GetFrameElement()
4118 .is_some_and(|el| el.has_attribute(&local_name!("allowfullscreen")))
4119 }
4120 },
4121 }
4122 }
4123
4124 fn reset_form_owner_for_listeners(&self, id: &Atom, can_gc: CanGc) {
4125 let map = self.form_id_listener_map.borrow();
4126 if let Some(listeners) = map.get(id) {
4127 for listener in listeners {
4128 listener
4129 .as_maybe_form_control()
4130 .expect("Element must be a form control")
4131 .reset_form_owner(can_gc);
4132 }
4133 }
4134 }
4135
4136 pub(crate) fn register_shadow_root(&self, shadow_root: &ShadowRoot) {
4137 self.shadow_roots
4138 .borrow_mut()
4139 .insert(Dom::from_ref(shadow_root));
4140 self.invalidate_shadow_roots_stylesheets();
4141 }
4142
4143 pub(crate) fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) {
4144 let mut shadow_roots = self.shadow_roots.borrow_mut();
4145 shadow_roots.remove(&Dom::from_ref(shadow_root));
4146 }
4147
4148 pub(crate) fn invalidate_shadow_roots_stylesheets(&self) {
4149 self.shadow_roots_styles_changed.set(true);
4150 }
4151
4152 pub(crate) fn shadow_roots_styles_changed(&self) -> bool {
4153 self.shadow_roots_styles_changed.get()
4154 }
4155
4156 pub(crate) fn flush_shadow_roots_stylesheets(&self) {
4157 if !self.shadow_roots_styles_changed.get() {
4158 return;
4159 }
4160 self.shadow_roots_styles_changed.set(false);
4161 }
4162
4163 pub(crate) fn stylesheet_count(&self) -> usize {
4164 self.stylesheets.borrow().len()
4165 }
4166
4167 pub(crate) fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
4168 let stylesheets = self.stylesheets.borrow();
4169
4170 stylesheets
4171 .get(Origin::Author, index)
4172 .and_then(|s| s.owner.get_cssom_object())
4173 }
4174
4175 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
4182 let stylesheets = &mut *self.stylesheets.borrow_mut();
4183
4184 let insertion_point = stylesheets
4186 .iter()
4187 .map(|(sheet, _origin)| sheet)
4188 .find(|sheet_in_doc| {
4189 match &sheet_in_doc.owner {
4190 StylesheetSource::Element(other_node) => {
4191 owner_node.upcast::<Node>().is_before(other_node.upcast())
4192 },
4193 StylesheetSource::Constructed(_) => true,
4196 }
4197 })
4198 .cloned();
4199
4200 if self.has_browsing_context() {
4201 let document_context = self.window.web_font_context();
4202
4203 self.window.layout_mut().add_stylesheet(
4204 sheet.clone(),
4205 insertion_point.as_ref().map(|s| s.sheet.clone()),
4206 &document_context,
4207 );
4208 }
4209
4210 DocumentOrShadowRoot::add_stylesheet(
4211 StylesheetSource::Element(Dom::from_ref(owner_node)),
4212 StylesheetSetRef::Document(stylesheets),
4213 sheet,
4214 insertion_point,
4215 self.style_shared_lock(),
4216 );
4217 }
4218
4219 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4224 pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
4225 debug_assert!(cssom_stylesheet.is_constructed());
4226
4227 let stylesheets = &mut *self.stylesheets.borrow_mut();
4228 let sheet = cssom_stylesheet.style_stylesheet().clone();
4229
4230 let insertion_point = stylesheets
4231 .iter()
4232 .last()
4233 .map(|(sheet, _origin)| sheet)
4234 .cloned();
4235
4236 if self.has_browsing_context() {
4237 self.window.layout_mut().add_stylesheet(
4238 sheet.clone(),
4239 insertion_point.as_ref().map(|s| s.sheet.clone()),
4240 &self.window.web_font_context(),
4241 );
4242 }
4243
4244 DocumentOrShadowRoot::add_stylesheet(
4245 StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
4246 StylesheetSetRef::Document(stylesheets),
4247 sheet,
4248 insertion_point,
4249 self.style_shared_lock(),
4250 );
4251 }
4252
4253 pub(crate) fn load_web_fonts_from_stylesheet(
4255 &self,
4256 stylesheet: &Arc<Stylesheet>,
4257 document_context: &WebFontDocumentContext,
4258 ) {
4259 self.window
4260 .layout()
4261 .load_web_fonts_from_stylesheet(stylesheet, document_context);
4262 }
4263
4264 #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
4267 if self.has_browsing_context() {
4268 self.window
4269 .layout_mut()
4270 .remove_stylesheet(stylesheet.clone());
4271 }
4272
4273 DocumentOrShadowRoot::remove_stylesheet(
4274 owner,
4275 stylesheet,
4276 StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()),
4277 )
4278 }
4279
4280 pub(crate) fn get_elements_with_id(&self, id: &Atom) -> Ref<'_, [Dom<Element>]> {
4281 Ref::map(self.id_map.borrow(), |map| {
4282 map.get(id).map(|vec| &**vec).unwrap_or_default()
4283 })
4284 }
4285
4286 pub(crate) fn get_elements_with_name(&self, name: &Atom) -> Ref<'_, [Dom<Element>]> {
4287 Ref::map(self.name_map.borrow(), |map| {
4288 map.get(name).map(|vec| &**vec).unwrap_or_default()
4289 })
4290 }
4291
4292 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
4293 pub(crate) fn drain_pending_restyles(&self) -> Vec<(TrustedNodeAddress, PendingRestyle)> {
4294 self.pending_restyles
4295 .borrow_mut()
4296 .drain()
4297 .filter_map(|(elem, restyle)| {
4298 let node = elem.upcast::<Node>();
4299 if !node.get_flag(NodeFlags::IS_CONNECTED) {
4300 return None;
4301 }
4302 node.note_dirty_descendants();
4303 Some((node.to_trusted_node_address(), restyle.0))
4304 })
4305 .collect()
4306 }
4307
4308 pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
4309 self.animation_timeline.borrow_mut().advance_specific(delta);
4310 let current_timeline_value = self.current_animation_timeline_value();
4311 self.animations
4312 .update_for_new_timeline_value(&self.window, current_timeline_value);
4313 }
4314
4315 pub(crate) fn maybe_mark_animating_nodes_as_dirty(&self) {
4316 let current_timeline_value = self.current_animation_timeline_value();
4317 self.animations
4318 .mark_animating_nodes_as_dirty(current_timeline_value);
4319 }
4320
4321 pub(crate) fn current_animation_timeline_value(&self) -> f64 {
4322 self.animation_timeline.borrow().current_value()
4323 }
4324
4325 pub(crate) fn animations(&self) -> &Animations {
4326 &self.animations
4327 }
4328
4329 pub(crate) fn update_animations_post_reflow(&self) {
4330 self.animations
4331 .do_post_reflow_update(&self.window, self.current_animation_timeline_value());
4332 self.image_animation_manager
4333 .borrow()
4334 .maybe_schedule_update_after_layout(
4335 &self.window,
4336 self.current_animation_timeline_value(),
4337 );
4338 }
4339
4340 pub(crate) fn cancel_animations_for_node(&self, node: &Node) {
4341 self.animations.cancel_animations_for_node(node);
4342 self.image_animation_manager
4343 .borrow()
4344 .cancel_animations_for_node(node);
4345 }
4346
4347 pub(crate) fn update_animations_and_send_events(&self, can_gc: CanGc) {
4349 if !self.layout_animations_test_enabled {
4351 self.animation_timeline.borrow_mut().update();
4352 }
4353
4354 let current_timeline_value = self.current_animation_timeline_value();
4361 self.animations
4362 .update_for_new_timeline_value(&self.window, current_timeline_value);
4363 self.maybe_mark_animating_nodes_as_dirty();
4364
4365 self.window().perform_a_microtask_checkpoint(can_gc);
4367
4368 let _realm = enter_realm(self);
4370 self.animations().send_pending_events(self.window(), can_gc);
4371 }
4372
4373 pub(crate) fn image_animation_manager(&self) -> Ref<'_, ImageAnimationManager> {
4374 self.image_animation_manager.borrow()
4375 }
4376
4377 pub(crate) fn set_has_pending_animated_image_update(&self) {
4378 self.has_pending_animated_image_update.set(true);
4379 }
4380
4381 pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) {
4383 if self.will_declaratively_refresh() {
4385 return;
4386 }
4387
4388 static REFRESH_REGEX: LazyLock<Regex> = LazyLock::new(|| {
4390 Regex::new(
4394 r#"(?xs)
4395 ^
4396 \s* # 3
4397 ((?<time>[0-9]+)|\.) # 5-6
4398 [0-9.]* # 8
4399 (
4400 (
4401 (\s*;|\s*,|\s) # 10.3
4402 \s* # 10.4
4403 )
4404 (
4405 (
4406 (U|u)(R|r)(L|l) # 11.2-11.4
4407 \s*=\s* # 11.5-11.7
4408 )?
4409 ('(?<url1>[^']*)'(?s-u:.)*|"(?<url2>[^"]*)"(?s-u:.)*|['"]?(?<url3>(?s-u:.)*)) # 11.8 - 11.10
4410 |
4411 (?<url4>(?s-u:.)*)
4412 )
4413 )?
4414 $
4415 "#,
4416 )
4417 .unwrap()
4418 });
4419
4420 let mut url_record = self.url();
4422 let captures = if let Some(captures) = REFRESH_REGEX.captures(content) {
4423 captures
4424 } else {
4425 return;
4426 };
4427 let time = if let Some(time_string) = captures.name("time") {
4428 u64::from_str(&String::from_utf8_lossy(time_string.as_bytes())).unwrap_or(0)
4429 } else {
4430 0
4431 };
4432 let captured_url = captures.name("url1").or(captures
4433 .name("url2")
4434 .or(captures.name("url3").or(captures.name("url4"))));
4435
4436 if let Some(url_match) = captured_url {
4438 url_record = if let Ok(url) = ServoUrl::parse_with_base(
4439 Some(&url_record),
4440 &String::from_utf8_lossy(url_match.as_bytes()),
4441 ) {
4442 info!("Refresh to {}", url.debug_compact());
4443 url
4444 } else {
4445 return;
4447 }
4448 }
4449 if self.completely_loaded() {
4451 self.window.as_global_scope().schedule_callback(
4453 OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
4454 window: DomRoot::from_ref(self.window()),
4455 url: url_record,
4456 }),
4457 Duration::from_secs(time),
4458 );
4459 self.set_declarative_refresh(DeclarativeRefresh::CreatedAfterLoad);
4460 } else {
4461 self.set_declarative_refresh(DeclarativeRefresh::PendingLoad {
4462 url: url_record,
4463 time,
4464 });
4465 }
4466 }
4467
4468 pub(crate) fn will_declaratively_refresh(&self) -> bool {
4469 self.declarative_refresh.borrow().is_some()
4470 }
4471 pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) {
4472 *self.declarative_refresh.borrow_mut() = Some(refresh);
4473 }
4474
4475 fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
4477 if self.visibility_state.get() == visibility_state {
4479 return;
4480 }
4481 self.visibility_state.set(visibility_state);
4483 let entry = VisibilityStateEntry::new(
4486 &self.global(),
4487 visibility_state,
4488 CrossProcessInstant::now(),
4489 can_gc,
4490 );
4491 self.window
4492 .Performance()
4493 .queue_entry(entry.upcast::<PerformanceEntry>());
4494
4495 if visibility_state == DocumentVisibilityState::Hidden {
4506 self.window
4507 .Navigator()
4508 .GetGamepads()
4509 .iter_mut()
4510 .for_each(|gamepad| {
4511 if let Some(g) = gamepad {
4512 g.vibration_actuator().handle_visibility_change();
4513 }
4514 });
4515 }
4516
4517 self.upcast::<EventTarget>()
4519 .fire_bubbling_event(atom!("visibilitychange"), can_gc);
4520 }
4521
4522 pub(crate) fn is_initial_about_blank(&self) -> bool {
4524 self.is_initial_about_blank.get()
4525 }
4526
4527 pub(crate) fn allow_declarative_shadow_roots(&self) -> bool {
4529 self.allow_declarative_shadow_roots.get()
4530 }
4531
4532 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
4533 self.has_trustworthy_ancestor_origin.get()
4534 }
4535
4536 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
4537 self.has_trustworthy_ancestor_origin.get() ||
4538 self.origin().immutable().is_potentially_trustworthy()
4539 }
4540
4541 pub(crate) fn highlight_dom_node(&self, node: Option<&Node>) {
4542 self.highlighted_dom_node.set(node);
4543 self.add_restyle_reason(RestyleReason::HighlightedDOMNodeChanged);
4544 }
4545
4546 pub(crate) fn highlighted_dom_node(&self) -> Option<DomRoot<Node>> {
4547 self.highlighted_dom_node.get()
4548 }
4549
4550 pub(crate) fn custom_element_reaction_stack(&self) -> Rc<CustomElementReactionStack> {
4551 self.custom_element_reaction_stack.clone()
4552 }
4553
4554 pub(crate) fn has_active_sandboxing_flag(&self, flag: SandboxingFlagSet) -> bool {
4555 self.active_sandboxing_flag_set.get().contains(flag)
4556 }
4557
4558 pub(crate) fn set_active_sandboxing_flag_set(&self, flags: SandboxingFlagSet) {
4559 self.active_sandboxing_flag_set.set(flags)
4560 }
4561
4562 pub(crate) fn creation_sandboxing_flag_set(&self) -> SandboxingFlagSet {
4563 self.creation_sandboxing_flag_set.get()
4564 }
4565
4566 pub(crate) fn creation_sandboxing_flag_set_considering_parent_iframe(
4567 &self,
4568 ) -> SandboxingFlagSet {
4569 self.window()
4570 .window_proxy()
4571 .frame_element()
4572 .and_then(|element| element.downcast::<HTMLIFrameElement>())
4573 .map(HTMLIFrameElement::sandboxing_flag_set)
4574 .unwrap_or_else(|| self.creation_sandboxing_flag_set())
4575 }
4576
4577 pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
4578 self.window()
4579 .scrolling_box_query(None, flags)
4580 .expect("We should always have a ScrollingBox for the Viewport")
4581 }
4582
4583 pub(crate) fn notify_embedder_favicon(&self) {
4584 if let Some(ref image) = *self.favicon.borrow() {
4585 self.send_to_embedder(EmbedderMsg::NewFavicon(self.webview_id(), image.clone()));
4586 }
4587 }
4588
4589 pub(crate) fn set_favicon(&self, favicon: Image) {
4590 *self.favicon.borrow_mut() = Some(favicon);
4591 self.notify_embedder_favicon();
4592 }
4593}
4594
4595#[allow(non_snake_case)]
4596impl DocumentMethods<crate::DomTypeHolder> for Document {
4597 fn Constructor(
4599 window: &Window,
4600 proto: Option<HandleObject>,
4601 can_gc: CanGc,
4602 ) -> Fallible<DomRoot<Document>> {
4603 let doc = window.Document();
4604 let docloader = DocumentLoader::new(&doc.loader());
4605 Ok(Document::new_with_proto(
4606 window,
4607 proto,
4608 HasBrowsingContext::No,
4609 None,
4610 doc.origin().clone(),
4611 IsHTMLDocument::NonHTMLDocument,
4612 None,
4613 None,
4614 DocumentActivity::Inactive,
4615 DocumentSource::NotFromParser,
4616 docloader,
4617 None,
4618 None,
4619 Default::default(),
4620 false,
4621 doc.allow_declarative_shadow_roots(),
4622 Some(doc.insecure_requests_policy()),
4623 doc.has_trustworthy_ancestor_or_current_origin(),
4624 doc.custom_element_reaction_stack(),
4625 doc.active_sandboxing_flag_set.get(),
4626 can_gc,
4627 ))
4628 }
4629
4630 fn ParseHTMLUnsafe(
4632 window: &Window,
4633 s: TrustedHTMLOrString,
4634 can_gc: CanGc,
4635 ) -> Fallible<DomRoot<Self>> {
4636 let compliant_html = TrustedHTML::get_trusted_script_compliant_string(
4640 window.as_global_scope(),
4641 s,
4642 "Document parseHTMLUnsafe",
4643 can_gc,
4644 )?;
4645
4646 let url = window.get_url();
4647 let doc = window.Document();
4648 let loader = DocumentLoader::new(&doc.loader());
4649
4650 let content_type = "text/html"
4651 .parse()
4652 .expect("Supported type is not a MIME type");
4653 let document = Document::new(
4656 window,
4657 HasBrowsingContext::No,
4658 Some(ServoUrl::parse("about:blank").unwrap()),
4659 doc.origin().clone(),
4660 IsHTMLDocument::HTMLDocument,
4661 Some(content_type),
4662 None,
4663 DocumentActivity::Inactive,
4664 DocumentSource::FromParser,
4665 loader,
4666 None,
4667 None,
4668 Default::default(),
4669 false,
4670 true,
4671 Some(doc.insecure_requests_policy()),
4672 doc.has_trustworthy_ancestor_or_current_origin(),
4673 doc.custom_element_reaction_stack(),
4674 doc.creation_sandboxing_flag_set(),
4675 can_gc,
4676 );
4677 ServoParser::parse_html_document(&document, Some(compliant_html), url, can_gc);
4679 document.set_ready_state(DocumentReadyState::Complete, can_gc);
4681 Ok(document)
4682 }
4683
4684 fn QueryCommandSupported(&self, _command: DOMString) -> bool {
4686 false
4687 }
4688
4689 fn StyleSheets(&self, can_gc: CanGc) -> DomRoot<StyleSheetList> {
4691 self.stylesheet_list.or_init(|| {
4692 StyleSheetList::new(
4693 &self.window,
4694 StyleSheetListOwner::Document(Dom::from_ref(self)),
4695 can_gc,
4696 )
4697 })
4698 }
4699
4700 fn Implementation(&self, can_gc: CanGc) -> DomRoot<DOMImplementation> {
4702 self.implementation
4703 .or_init(|| DOMImplementation::new(self, can_gc))
4704 }
4705
4706 fn URL(&self) -> USVString {
4708 USVString(String::from(self.url().as_str()))
4709 }
4710
4711 fn GetActiveElement(&self) -> Option<DomRoot<Element>> {
4713 self.document_or_shadow_root.get_active_element(
4714 self.get_focused_element(),
4715 self.GetBody(),
4716 self.GetDocumentElement(),
4717 )
4718 }
4719
4720 fn HasFocus(&self) -> bool {
4722 if self.window().parent_info().is_none() {
4744 self.is_fully_active()
4746 } else {
4747 self.is_fully_active() && self.has_focus.get()
4749 }
4750 }
4751
4752 fn Domain(&self) -> DOMString {
4754 if !self.has_browsing_context {
4756 return DOMString::new();
4757 }
4758
4759 match self.origin.effective_domain() {
4761 None => DOMString::new(),
4763 Some(Host::Domain(domain)) => DOMString::from(domain),
4765 Some(host) => DOMString::from(host.to_string()),
4766 }
4767 }
4768
4769 fn SetDomain(&self, value: DOMString) -> ErrorResult {
4771 if !self.has_browsing_context {
4773 return Err(Error::Security(None));
4774 }
4775
4776 if self.has_active_sandboxing_flag(
4779 SandboxingFlagSet::SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG,
4780 ) {
4781 return Err(Error::Security(None));
4782 }
4783
4784 let effective_domain = match self.origin.effective_domain() {
4786 Some(effective_domain) => effective_domain,
4787 None => return Err(Error::Security(None)),
4788 };
4789
4790 let host = match get_registrable_domain_suffix_of_or_is_equal_to(&value, effective_domain) {
4792 None => return Err(Error::Security(None)),
4793 Some(host) => host,
4794 };
4795
4796 self.origin.set_domain(host);
4798
4799 Ok(())
4800 }
4801
4802 fn Referrer(&self) -> DOMString {
4804 match self.referrer {
4805 Some(ref referrer) => DOMString::from(referrer.to_string()),
4806 None => DOMString::new(),
4807 }
4808 }
4809
4810 fn DocumentURI(&self) -> USVString {
4812 self.URL()
4813 }
4814
4815 fn CompatMode(&self) -> DOMString {
4817 DOMString::from(match self.quirks_mode.get() {
4818 QuirksMode::LimitedQuirks | QuirksMode::NoQuirks => "CSS1Compat",
4819 QuirksMode::Quirks => "BackCompat",
4820 })
4821 }
4822
4823 fn CharacterSet(&self) -> DOMString {
4825 DOMString::from(self.encoding.get().name())
4826 }
4827
4828 fn Charset(&self) -> DOMString {
4830 self.CharacterSet()
4831 }
4832
4833 fn InputEncoding(&self) -> DOMString {
4835 self.CharacterSet()
4836 }
4837
4838 fn ContentType(&self) -> DOMString {
4840 DOMString::from(self.content_type.to_string())
4841 }
4842
4843 fn GetDoctype(&self) -> Option<DomRoot<DocumentType>> {
4845 self.upcast::<Node>().children().find_map(DomRoot::downcast)
4846 }
4847
4848 fn GetDocumentElement(&self) -> Option<DomRoot<Element>> {
4850 self.upcast::<Node>().child_elements().next()
4851 }
4852
4853 fn GetElementsByTagName(
4855 &self,
4856 qualified_name: DOMString,
4857 can_gc: CanGc,
4858 ) -> DomRoot<HTMLCollection> {
4859 let qualified_name = LocalName::from(qualified_name);
4860 if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
4861 return DomRoot::from_ref(entry);
4862 }
4863 let result = HTMLCollection::by_qualified_name(
4864 &self.window,
4865 self.upcast(),
4866 qualified_name.clone(),
4867 can_gc,
4868 );
4869 self.tag_map
4870 .borrow_mut()
4871 .insert(qualified_name, Dom::from_ref(&*result));
4872 result
4873 }
4874
4875 fn GetElementsByTagNameNS(
4877 &self,
4878 maybe_ns: Option<DOMString>,
4879 tag_name: DOMString,
4880 can_gc: CanGc,
4881 ) -> DomRoot<HTMLCollection> {
4882 let ns = namespace_from_domstring(maybe_ns);
4883 let local = LocalName::from(tag_name);
4884 let qname = QualName::new(None, ns, local);
4885 if let Some(collection) = self.tagns_map.borrow().get(&qname) {
4886 return DomRoot::from_ref(collection);
4887 }
4888 let result =
4889 HTMLCollection::by_qual_tag_name(&self.window, self.upcast(), qname.clone(), can_gc);
4890 self.tagns_map
4891 .borrow_mut()
4892 .insert(qname, Dom::from_ref(&*result));
4893 result
4894 }
4895
4896 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
4898 let class_atoms: Vec<Atom> = split_html_space_chars(&classes.str())
4899 .map(Atom::from)
4900 .collect();
4901 if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
4902 return DomRoot::from_ref(collection);
4903 }
4904 let result = HTMLCollection::by_atomic_class_name(
4905 &self.window,
4906 self.upcast(),
4907 class_atoms.clone(),
4908 can_gc,
4909 );
4910 self.classes_map
4911 .borrow_mut()
4912 .insert(class_atoms, Dom::from_ref(&*result));
4913 result
4914 }
4915
4916 fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
4918 self.get_element_by_id(&Atom::from(id))
4919 }
4920
4921 fn CreateElement(
4923 &self,
4924 mut local_name: DOMString,
4925 options: StringOrElementCreationOptions,
4926 can_gc: CanGc,
4927 ) -> Fallible<DomRoot<Element>> {
4928 if !is_valid_element_local_name(&local_name.str()) {
4931 debug!("Not a valid element name");
4932 return Err(Error::InvalidCharacter(None));
4933 }
4934
4935 if self.is_html_document {
4936 local_name.make_ascii_lowercase();
4937 }
4938
4939 let ns = if self.is_html_document || self.is_xhtml_document() {
4940 ns!(html)
4941 } else {
4942 ns!()
4943 };
4944
4945 let name = QualName::new(None, ns, LocalName::from(local_name));
4946 let is = match options {
4947 StringOrElementCreationOptions::String(_) => None,
4948 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4949 options.is.as_ref().map(LocalName::from)
4950 },
4951 };
4952 Ok(Element::create(
4953 name,
4954 is,
4955 self,
4956 ElementCreator::ScriptCreated,
4957 CustomElementCreationMode::Synchronous,
4958 None,
4959 can_gc,
4960 ))
4961 }
4962
4963 fn CreateElementNS(
4965 &self,
4966 namespace: Option<DOMString>,
4967 qualified_name: DOMString,
4968 options: StringOrElementCreationOptions,
4969 can_gc: CanGc,
4970 ) -> Fallible<DomRoot<Element>> {
4971 let context = domname::Context::Element;
4974 let (namespace, prefix, local_name) =
4975 domname::validate_and_extract(namespace, &qualified_name, context)?;
4976
4977 let name = QualName::new(prefix, namespace, local_name);
4980 let is = match options {
4981 StringOrElementCreationOptions::String(_) => None,
4982 StringOrElementCreationOptions::ElementCreationOptions(options) => {
4983 options.is.as_ref().map(LocalName::from)
4984 },
4985 };
4986
4987 Ok(Element::create(
4989 name,
4990 is,
4991 self,
4992 ElementCreator::ScriptCreated,
4993 CustomElementCreationMode::Synchronous,
4994 None,
4995 can_gc,
4996 ))
4997 }
4998
4999 fn CreateAttribute(&self, mut local_name: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
5001 if !is_valid_attribute_local_name(&local_name.str()) {
5004 debug!("Not a valid attribute name");
5005 return Err(Error::InvalidCharacter(None));
5006 }
5007 if self.is_html_document {
5008 local_name.make_ascii_lowercase();
5009 }
5010 let name = LocalName::from(local_name);
5011 let value = AttrValue::String("".to_owned());
5012
5013 Ok(Attr::new(
5014 self,
5015 name.clone(),
5016 value,
5017 name,
5018 ns!(),
5019 None,
5020 None,
5021 can_gc,
5022 ))
5023 }
5024
5025 fn CreateAttributeNS(
5027 &self,
5028 namespace: Option<DOMString>,
5029 qualified_name: DOMString,
5030 can_gc: CanGc,
5031 ) -> Fallible<DomRoot<Attr>> {
5032 let context = domname::Context::Attribute;
5035 let (namespace, prefix, local_name) =
5036 domname::validate_and_extract(namespace, &qualified_name, context)?;
5037 let value = AttrValue::String("".to_owned());
5038 let qualified_name = LocalName::from(qualified_name);
5039 Ok(Attr::new(
5040 self,
5041 local_name,
5042 value,
5043 qualified_name,
5044 namespace,
5045 prefix,
5046 None,
5047 can_gc,
5048 ))
5049 }
5050
5051 fn CreateDocumentFragment(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> {
5053 DocumentFragment::new(self, can_gc)
5054 }
5055
5056 fn CreateTextNode(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Text> {
5058 Text::new(data, self, can_gc)
5059 }
5060
5061 fn CreateCDATASection(
5063 &self,
5064 data: DOMString,
5065 can_gc: CanGc,
5066 ) -> Fallible<DomRoot<CDATASection>> {
5067 if self.is_html_document {
5069 return Err(Error::NotSupported(None));
5070 }
5071
5072 if data.contains("]]>") {
5074 return Err(Error::InvalidCharacter(None));
5075 }
5076
5077 Ok(CDATASection::new(data, self, can_gc))
5079 }
5080
5081 fn CreateComment(&self, data: DOMString, can_gc: CanGc) -> DomRoot<Comment> {
5083 Comment::new(data, self, None, can_gc)
5084 }
5085
5086 fn CreateProcessingInstruction(
5088 &self,
5089 target: DOMString,
5090 data: DOMString,
5091 can_gc: CanGc,
5092 ) -> Fallible<DomRoot<ProcessingInstruction>> {
5093 if !matches_name_production(&target.str()) {
5095 return Err(Error::InvalidCharacter(None));
5096 }
5097
5098 if data.contains("?>") {
5100 return Err(Error::InvalidCharacter(None));
5101 }
5102
5103 Ok(ProcessingInstruction::new(target, data, self, can_gc))
5105 }
5106
5107 fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5109 if node.is::<Document>() || node.is::<ShadowRoot>() {
5111 return Err(Error::NotSupported(None));
5112 }
5113
5114 let clone_children = if deep {
5116 CloneChildrenFlag::CloneChildren
5117 } else {
5118 CloneChildrenFlag::DoNotCloneChildren
5119 };
5120
5121 Ok(Node::clone(node, Some(self), clone_children, can_gc))
5122 }
5123
5124 fn AdoptNode(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
5126 if node.is::<Document>() {
5128 return Err(Error::NotSupported(None));
5129 }
5130
5131 if node.is::<ShadowRoot>() {
5133 return Err(Error::HierarchyRequest(None));
5134 }
5135
5136 Node::adopt(node, self, can_gc);
5138
5139 Ok(DomRoot::from_ref(node))
5141 }
5142
5143 fn CreateEvent(&self, mut interface: DOMString, can_gc: CanGc) -> Fallible<DomRoot<Event>> {
5145 interface.make_ascii_lowercase();
5146 match &*interface.str() {
5147 "beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
5148 &self.window,
5149 can_gc,
5150 ))),
5151 "compositionevent" | "textevent" => Ok(DomRoot::upcast(
5152 CompositionEvent::new_uninitialized(&self.window, can_gc),
5153 )),
5154 "customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
5155 self.window.upcast(),
5156 can_gc,
5157 ))),
5158 "events" | "event" | "htmlevents" | "svgevents" => {
5161 Ok(Event::new_uninitialized(self.window.upcast(), can_gc))
5162 },
5163 "focusevent" => Ok(DomRoot::upcast(FocusEvent::new_uninitialized(
5164 &self.window,
5165 can_gc,
5166 ))),
5167 "hashchangeevent" => Ok(DomRoot::upcast(HashChangeEvent::new_uninitialized(
5168 &self.window,
5169 can_gc,
5170 ))),
5171 "keyboardevent" => Ok(DomRoot::upcast(KeyboardEvent::new_uninitialized(
5172 &self.window,
5173 can_gc,
5174 ))),
5175 "messageevent" => Ok(DomRoot::upcast(MessageEvent::new_uninitialized(
5176 self.window.upcast(),
5177 can_gc,
5178 ))),
5179 "mouseevent" | "mouseevents" => Ok(DomRoot::upcast(MouseEvent::new_uninitialized(
5180 &self.window,
5181 can_gc,
5182 ))),
5183 "storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
5184 &self.window,
5185 "".into(),
5186 can_gc,
5187 ))),
5188 "touchevent" => Ok(DomRoot::upcast(DomTouchEvent::new_uninitialized(
5189 &self.window,
5190 &TouchList::new(&self.window, &[], can_gc),
5191 &TouchList::new(&self.window, &[], can_gc),
5192 &TouchList::new(&self.window, &[], can_gc),
5193 can_gc,
5194 ))),
5195 "uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(
5196 &self.window,
5197 can_gc,
5198 ))),
5199 _ => Err(Error::NotSupported(None)),
5200 }
5201 }
5202
5203 fn LastModified(&self) -> DOMString {
5205 DOMString::from(self.last_modified.as_ref().cloned().unwrap_or_else(|| {
5206 Local::now().format("%m/%d/%Y %H:%M:%S").to_string()
5212 }))
5213 }
5214
5215 fn CreateRange(&self, can_gc: CanGc) -> DomRoot<Range> {
5217 Range::new_with_doc(self, None, can_gc)
5218 }
5219
5220 fn CreateNodeIterator(
5222 &self,
5223 root: &Node,
5224 what_to_show: u32,
5225 filter: Option<Rc<NodeFilter>>,
5226 can_gc: CanGc,
5227 ) -> DomRoot<NodeIterator> {
5228 NodeIterator::new(self, root, what_to_show, filter, can_gc)
5229 }
5230
5231 fn CreateTreeWalker(
5233 &self,
5234 root: &Node,
5235 what_to_show: u32,
5236 filter: Option<Rc<NodeFilter>>,
5237 ) -> DomRoot<TreeWalker> {
5238 TreeWalker::new(self, root, what_to_show, filter)
5239 }
5240
5241 fn Title(&self) -> DOMString {
5243 self.title().unwrap_or_else(|| DOMString::from(""))
5244 }
5245
5246 fn SetTitle(&self, title: DOMString, can_gc: CanGc) {
5248 let root = match self.GetDocumentElement() {
5249 Some(root) => root,
5250 None => return,
5251 };
5252
5253 let node = if root.namespace() == &ns!(svg) && root.local_name() == &local_name!("svg") {
5254 let elem = root.upcast::<Node>().child_elements().find(|node| {
5255 node.namespace() == &ns!(svg) && node.local_name() == &local_name!("title")
5256 });
5257 match elem {
5258 Some(elem) => DomRoot::upcast::<Node>(elem),
5259 None => {
5260 let name = QualName::new(None, ns!(svg), local_name!("title"));
5261 let elem = Element::create(
5262 name,
5263 None,
5264 self,
5265 ElementCreator::ScriptCreated,
5266 CustomElementCreationMode::Synchronous,
5267 None,
5268 can_gc,
5269 );
5270 let parent = root.upcast::<Node>();
5271 let child = elem.upcast::<Node>();
5272 parent
5273 .InsertBefore(child, parent.GetFirstChild().as_deref(), can_gc)
5274 .unwrap()
5275 },
5276 }
5277 } else if root.namespace() == &ns!(html) {
5278 let elem = root
5279 .upcast::<Node>()
5280 .traverse_preorder(ShadowIncluding::No)
5281 .find(|node| node.is::<HTMLTitleElement>());
5282 match elem {
5283 Some(elem) => elem,
5284 None => match self.GetHead() {
5285 Some(head) => {
5286 let name = QualName::new(None, ns!(html), local_name!("title"));
5287 let elem = Element::create(
5288 name,
5289 None,
5290 self,
5291 ElementCreator::ScriptCreated,
5292 CustomElementCreationMode::Synchronous,
5293 None,
5294 can_gc,
5295 );
5296 head.upcast::<Node>()
5297 .AppendChild(elem.upcast(), can_gc)
5298 .unwrap()
5299 },
5300 None => return,
5301 },
5302 }
5303 } else {
5304 return;
5305 };
5306
5307 node.set_text_content_for_element(Some(title), can_gc);
5308 }
5309
5310 fn GetHead(&self) -> Option<DomRoot<HTMLHeadElement>> {
5312 self.get_html_element()
5313 .and_then(|root| root.upcast::<Node>().children().find_map(DomRoot::downcast))
5314 }
5315
5316 fn GetCurrentScript(&self) -> Option<DomRoot<HTMLScriptElement>> {
5318 self.current_script.get()
5319 }
5320
5321 fn GetBody(&self) -> Option<DomRoot<HTMLElement>> {
5323 self.get_html_element().and_then(|root| {
5324 let node = root.upcast::<Node>();
5325 node.children()
5326 .find(|child| {
5327 matches!(
5328 child.type_id(),
5329 NodeTypeId::Element(ElementTypeId::HTMLElement(
5330 HTMLElementTypeId::HTMLBodyElement,
5331 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
5332 HTMLElementTypeId::HTMLFrameSetElement,
5333 ))
5334 )
5335 })
5336 .map(|node| DomRoot::downcast(node).unwrap())
5337 })
5338 }
5339
5340 fn SetBody(&self, new_body: Option<&HTMLElement>, can_gc: CanGc) -> ErrorResult {
5342 let new_body = match new_body {
5344 Some(new_body) => new_body,
5345 None => return Err(Error::HierarchyRequest(None)),
5346 };
5347
5348 let node = new_body.upcast::<Node>();
5349 match node.type_id() {
5350 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) |
5351 NodeTypeId::Element(ElementTypeId::HTMLElement(
5352 HTMLElementTypeId::HTMLFrameSetElement,
5353 )) => {},
5354 _ => return Err(Error::HierarchyRequest(None)),
5355 }
5356
5357 let old_body = self.GetBody();
5359 if old_body.as_deref() == Some(new_body) {
5360 return Ok(());
5361 }
5362
5363 match (self.GetDocumentElement(), &old_body) {
5364 (Some(ref root), Some(child)) => {
5366 let root = root.upcast::<Node>();
5367 root.ReplaceChild(new_body.upcast(), child.upcast(), can_gc)
5368 .unwrap();
5369 },
5370
5371 (None, _) => return Err(Error::HierarchyRequest(None)),
5373
5374 (Some(ref root), &None) => {
5376 let root = root.upcast::<Node>();
5377 root.AppendChild(new_body.upcast(), can_gc).unwrap();
5378 },
5379 }
5380 Ok(())
5381 }
5382
5383 fn GetElementsByName(&self, name: DOMString, can_gc: CanGc) -> DomRoot<NodeList> {
5385 NodeList::new_elements_by_name_list(self.window(), self, name, can_gc)
5386 }
5387
5388 fn Images(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5390 self.images.or_init(|| {
5391 HTMLCollection::new_with_filter_fn(
5392 &self.window,
5393 self.upcast(),
5394 |element, _| element.is::<HTMLImageElement>(),
5395 can_gc,
5396 )
5397 })
5398 }
5399
5400 fn Embeds(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5402 self.embeds.or_init(|| {
5403 HTMLCollection::new_with_filter_fn(
5404 &self.window,
5405 self.upcast(),
5406 |element, _| element.is::<HTMLEmbedElement>(),
5407 can_gc,
5408 )
5409 })
5410 }
5411
5412 fn Plugins(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5414 self.Embeds(can_gc)
5415 }
5416
5417 fn Links(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5419 self.links.or_init(|| {
5420 HTMLCollection::new_with_filter_fn(
5421 &self.window,
5422 self.upcast(),
5423 |element, _| {
5424 (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) &&
5425 element.has_attribute(&local_name!("href"))
5426 },
5427 can_gc,
5428 )
5429 })
5430 }
5431
5432 fn Forms(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5434 self.forms.or_init(|| {
5435 HTMLCollection::new_with_filter_fn(
5436 &self.window,
5437 self.upcast(),
5438 |element, _| element.is::<HTMLFormElement>(),
5439 can_gc,
5440 )
5441 })
5442 }
5443
5444 fn Scripts(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5446 self.scripts.or_init(|| {
5447 HTMLCollection::new_with_filter_fn(
5448 &self.window,
5449 self.upcast(),
5450 |element, _| element.is::<HTMLScriptElement>(),
5451 can_gc,
5452 )
5453 })
5454 }
5455
5456 fn Anchors(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5458 self.anchors.or_init(|| {
5459 HTMLCollection::new_with_filter_fn(
5460 &self.window,
5461 self.upcast(),
5462 |element, _| {
5463 element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href"))
5464 },
5465 can_gc,
5466 )
5467 })
5468 }
5469
5470 fn Applets(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5472 self.applets
5473 .or_init(|| HTMLCollection::always_empty(&self.window, self.upcast(), can_gc))
5474 }
5475
5476 fn GetLocation(&self) -> Option<DomRoot<Location>> {
5478 if self.is_fully_active() {
5479 Some(self.window.Location())
5480 } else {
5481 None
5482 }
5483 }
5484
5485 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
5487 HTMLCollection::children(&self.window, self.upcast(), can_gc)
5488 }
5489
5490 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
5492 self.upcast::<Node>().child_elements().next()
5493 }
5494
5495 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
5497 self.upcast::<Node>()
5498 .rev_children()
5499 .find_map(DomRoot::downcast)
5500 }
5501
5502 fn ChildElementCount(&self) -> u32 {
5504 self.upcast::<Node>().child_elements().count() as u32
5505 }
5506
5507 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5509 self.upcast::<Node>().prepend(nodes, can_gc)
5510 }
5511
5512 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5514 self.upcast::<Node>().append(nodes, can_gc)
5515 }
5516
5517 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
5519 self.upcast::<Node>().replace_children(nodes, can_gc)
5520 }
5521
5522 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
5524 let root = self.upcast::<Node>();
5525 root.query_selector(selectors)
5526 }
5527
5528 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
5530 let root = self.upcast::<Node>();
5531 root.query_selector_all(selectors)
5532 }
5533
5534 fn ReadyState(&self) -> DocumentReadyState {
5536 self.ready_state.get()
5537 }
5538
5539 fn GetDefaultView(&self) -> Option<DomRoot<Window>> {
5541 if self.has_browsing_context {
5542 Some(DomRoot::from_ref(&*self.window))
5543 } else {
5544 None
5545 }
5546 }
5547
5548 fn GetCookie(&self) -> Fallible<DOMString> {
5550 if self.is_cookie_averse() {
5551 return Ok(DOMString::new());
5552 }
5553
5554 if !self.origin.is_tuple() {
5555 return Err(Error::Security(None));
5556 }
5557
5558 let url = self.url();
5559 let (tx, rx) = profile_ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
5560 let _ = self
5561 .window
5562 .as_global_scope()
5563 .resource_threads()
5564 .send(GetCookiesForUrl(url, tx, NonHTTP));
5565 let cookies = rx.recv().unwrap();
5566 Ok(cookies.map_or(DOMString::new(), DOMString::from))
5567 }
5568
5569 fn SetCookie(&self, cookie: DOMString) -> ErrorResult {
5571 if self.is_cookie_averse() {
5572 return Ok(());
5573 }
5574
5575 if !self.origin.is_tuple() {
5576 return Err(Error::Security(None));
5577 }
5578
5579 if !cookie.is_valid_for_cookie() {
5580 return Ok(());
5581 }
5582
5583 let cookies = if let Some(cookie) = Cookie::parse(cookie.to_string()).ok().map(Serde) {
5584 vec![cookie]
5585 } else {
5586 vec![]
5587 };
5588
5589 let _ = self
5590 .window
5591 .as_global_scope()
5592 .resource_threads()
5593 .send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
5594 Ok(())
5595 }
5596
5597 fn BgColor(&self) -> DOMString {
5599 self.get_body_attribute(&local_name!("bgcolor"))
5600 }
5601
5602 fn SetBgColor(&self, value: DOMString, can_gc: CanGc) {
5604 self.set_body_attribute(&local_name!("bgcolor"), value, can_gc)
5605 }
5606
5607 fn FgColor(&self) -> DOMString {
5609 self.get_body_attribute(&local_name!("text"))
5610 }
5611
5612 fn SetFgColor(&self, value: DOMString, can_gc: CanGc) {
5614 self.set_body_attribute(&local_name!("text"), value, can_gc)
5615 }
5616
5617 fn NamedGetter(&self, name: DOMString, can_gc: CanGc) -> Option<NamedPropertyValue> {
5619 if name.is_empty() {
5620 return None;
5621 }
5622 let name = Atom::from(name);
5623
5624 let elements_with_name = self.get_elements_with_name(&name);
5627 let name_iter = elements_with_name
5628 .iter()
5629 .filter(|elem| is_named_element_with_name_attribute(elem));
5630 let elements_with_id = self.get_elements_with_id(&name);
5631 let id_iter = elements_with_id
5632 .iter()
5633 .filter(|elem| is_named_element_with_id_attribute(elem));
5634 let mut elements = name_iter.chain(id_iter);
5635
5636 let first = elements.next()?;
5643 if elements.all(|other| first == other) {
5644 if let Some(nested_window_proxy) = first
5645 .downcast::<HTMLIFrameElement>()
5646 .and_then(|iframe| iframe.GetContentWindow())
5647 {
5648 return Some(NamedPropertyValue::WindowProxy(nested_window_proxy));
5649 }
5650
5651 return Some(NamedPropertyValue::Element(DomRoot::from_ref(first)));
5653 }
5654
5655 #[derive(JSTraceable, MallocSizeOf)]
5658 struct DocumentNamedGetter {
5659 #[no_trace]
5660 name: Atom,
5661 }
5662 impl CollectionFilter for DocumentNamedGetter {
5663 fn filter(&self, elem: &Element, _root: &Node) -> bool {
5664 let type_ = match elem.upcast::<Node>().type_id() {
5665 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
5666 _ => return false,
5667 };
5668 match type_ {
5669 HTMLElementTypeId::HTMLFormElement | HTMLElementTypeId::HTMLIFrameElement => {
5670 elem.get_name().as_ref() == Some(&self.name)
5671 },
5672 HTMLElementTypeId::HTMLImageElement => elem.get_name().is_some_and(|name| {
5673 name == *self.name ||
5674 !name.is_empty() && elem.get_id().as_ref() == Some(&self.name)
5675 }),
5676 _ => false,
5680 }
5681 }
5682 }
5683 let collection = HTMLCollection::create(
5684 self.window(),
5685 self.upcast(),
5686 Box::new(DocumentNamedGetter { name }),
5687 can_gc,
5688 );
5689 Some(NamedPropertyValue::HTMLCollection(collection))
5690 }
5691
5692 fn SupportedPropertyNames(&self) -> Vec<DOMString> {
5694 let mut names_with_first_named_element_map: HashMap<&Atom, &Element> = HashMap::new();
5695
5696 let name_map = self.name_map.borrow();
5697 for (name, elements) in &(name_map).0 {
5698 if name.is_empty() {
5699 continue;
5700 }
5701 let mut name_iter = elements
5702 .iter()
5703 .filter(|elem| is_named_element_with_name_attribute(elem));
5704 if let Some(first) = name_iter.next() {
5705 names_with_first_named_element_map.insert(name, first);
5706 }
5707 }
5708 let id_map = self.id_map.borrow();
5709 for (id, elements) in &(id_map).0 {
5710 if id.is_empty() {
5711 continue;
5712 }
5713 let mut id_iter = elements
5714 .iter()
5715 .filter(|elem| is_named_element_with_id_attribute(elem));
5716 if let Some(first) = id_iter.next() {
5717 match names_with_first_named_element_map.entry(id) {
5718 Vacant(entry) => drop(entry.insert(first)),
5719 Occupied(mut entry) => {
5720 if first.upcast::<Node>().is_before(entry.get().upcast()) {
5721 *entry.get_mut() = first;
5722 }
5723 },
5724 }
5725 }
5726 }
5727
5728 let mut names_with_first_named_element_vec: Vec<(&Atom, &Element)> =
5729 names_with_first_named_element_map
5730 .iter()
5731 .map(|(k, v)| (*k, *v))
5732 .collect();
5733 names_with_first_named_element_vec.sort_unstable_by(|a, b| {
5734 if a.1 == b.1 {
5735 a.0.cmp(b.0)
5738 } else if a.1.upcast::<Node>().is_before(b.1.upcast::<Node>()) {
5739 Ordering::Less
5740 } else {
5741 Ordering::Greater
5742 }
5743 });
5744
5745 names_with_first_named_element_vec
5746 .iter()
5747 .map(|(k, _v)| DOMString::from(&***k))
5748 .collect()
5749 }
5750
5751 fn Clear(&self) {
5753 }
5755
5756 fn CaptureEvents(&self) {
5758 }
5760
5761 fn ReleaseEvents(&self) {
5763 }
5765
5766 global_event_handlers!();
5768
5769 event_handler!(
5771 readystatechange,
5772 GetOnreadystatechange,
5773 SetOnreadystatechange
5774 );
5775
5776 fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> {
5778 self.document_or_shadow_root.element_from_point(
5779 x,
5780 y,
5781 self.GetDocumentElement(),
5782 self.has_browsing_context,
5783 )
5784 }
5785
5786 fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> {
5788 self.document_or_shadow_root.elements_from_point(
5789 x,
5790 y,
5791 self.GetDocumentElement(),
5792 self.has_browsing_context,
5793 )
5794 }
5795
5796 fn GetScrollingElement(&self) -> Option<DomRoot<Element>> {
5798 if self.quirks_mode() == QuirksMode::Quirks {
5800 if let Some(ref body) = self.GetBody() {
5802 let e = body.upcast::<Element>();
5803 if !e.is_potentially_scrollable_body_for_scrolling_element() {
5807 return Some(DomRoot::from_ref(e));
5808 }
5809 }
5810
5811 return None;
5813 }
5814
5815 self.GetDocumentElement()
5818 }
5819
5820 fn Open(
5822 &self,
5823 _unused1: Option<DOMString>,
5824 _unused2: Option<DOMString>,
5825 can_gc: CanGc,
5826 ) -> Fallible<DomRoot<Document>> {
5827 if !self.is_html_document() {
5829 return Err(Error::InvalidState(None));
5830 }
5831
5832 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5834 return Err(Error::InvalidState(None));
5835 }
5836
5837 let entry_responsible_document = GlobalScope::entry().as_window().Document();
5839
5840 if !self.origin.same_origin(&entry_responsible_document.origin) {
5842 return Err(Error::Security(None));
5843 }
5844
5845 if self
5847 .get_current_parser()
5848 .is_some_and(|parser| parser.is_active())
5849 {
5850 return Ok(DomRoot::from_ref(self));
5851 }
5852
5853 if self.is_prompting_or_unloading() {
5855 return Ok(DomRoot::from_ref(self));
5856 }
5857
5858 if self.active_parser_was_aborted.get() {
5860 return Ok(DomRoot::from_ref(self));
5861 }
5862
5863 self.window().set_navigation_start();
5867
5868 if self.has_browsing_context() {
5871 self.abort(can_gc);
5874 }
5875
5876 for node in self
5878 .upcast::<Node>()
5879 .traverse_preorder(ShadowIncluding::Yes)
5880 {
5881 node.upcast::<EventTarget>().remove_all_listeners();
5882 }
5883
5884 if self.window.Document() == DomRoot::from_ref(self) {
5886 self.window.upcast::<EventTarget>().remove_all_listeners();
5887 }
5888
5889 Node::replace_all(None, self.upcast::<Node>(), can_gc);
5891
5892 if self.is_fully_active() {
5899 let mut new_url = entry_responsible_document.url();
5901
5902 if entry_responsible_document != DomRoot::from_ref(self) {
5904 new_url.set_fragment(None);
5905 }
5906
5907 self.set_url(new_url);
5910 }
5911
5912 self.is_initial_about_blank.set(false);
5914
5915 self.set_quirks_mode(QuirksMode::NoQuirks);
5921
5922 let resource_threads = self.window.as_global_scope().resource_threads().clone();
5928 *self.loader.borrow_mut() =
5929 DocumentLoader::new_with_threads(resource_threads, Some(self.url()));
5930 ServoParser::parse_html_script_input(self, self.url());
5931
5932 self.ready_state.set(DocumentReadyState::Loading);
5938
5939 Ok(DomRoot::from_ref(self))
5941 }
5942
5943 fn Open_(
5945 &self,
5946 url: USVString,
5947 target: DOMString,
5948 features: DOMString,
5949 can_gc: CanGc,
5950 ) -> Fallible<Option<DomRoot<WindowProxy>>> {
5951 self.browsing_context()
5952 .ok_or(Error::InvalidAccess(None))?
5953 .open(url, target, features, can_gc)
5954 }
5955
5956 fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5958 self.write(text, false, "Document", "write", can_gc)
5961 }
5962
5963 fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
5965 self.write(text, true, "Document", "writeln", can_gc)
5968 }
5969
5970 fn Close(&self, can_gc: CanGc) -> ErrorResult {
5972 if !self.is_html_document() {
5973 return Err(Error::InvalidState(None));
5975 }
5976
5977 if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
5979 return Err(Error::InvalidState(None));
5980 }
5981
5982 let parser = match self.get_current_parser() {
5983 Some(ref parser) if parser.is_script_created() => DomRoot::from_ref(&**parser),
5984 _ => {
5985 return Ok(());
5987 },
5988 };
5989
5990 parser.close(can_gc);
5992
5993 Ok(())
5994 }
5995
5996 event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
5998
5999 event_handler!(
6001 fullscreenchange,
6002 GetOnfullscreenchange,
6003 SetOnfullscreenchange
6004 );
6005
6006 fn FullscreenEnabled(&self) -> bool {
6008 self.get_allow_fullscreen()
6009 }
6010
6011 fn Fullscreen(&self) -> bool {
6013 self.fullscreen_element.get().is_some()
6014 }
6015
6016 fn GetFullscreenElement(&self) -> Option<DomRoot<Element>> {
6018 self.fullscreen_element.get()
6020 }
6021
6022 fn ExitFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
6024 self.exit_fullscreen(can_gc)
6025 }
6026
6027 fn ServoGetMediaControls(&self, id: DOMString) -> Fallible<DomRoot<ShadowRoot>> {
6031 match self.media_controls.borrow().get(&*id.str()) {
6032 Some(m) => Ok(DomRoot::from_ref(m)),
6033 None => Err(Error::InvalidAccess(None)),
6034 }
6035 }
6036
6037 fn GetSelection(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
6039 if self.has_browsing_context {
6040 Some(self.selection.or_init(|| Selection::new(self, can_gc)))
6041 } else {
6042 None
6043 }
6044 }
6045
6046 fn Fonts(&self, can_gc: CanGc) -> DomRoot<FontFaceSet> {
6048 self.fonts
6049 .or_init(|| FontFaceSet::new(&self.global(), None, can_gc))
6050 }
6051
6052 fn Hidden(&self) -> bool {
6054 self.visibility_state.get() == DocumentVisibilityState::Hidden
6055 }
6056
6057 fn VisibilityState(&self) -> DocumentVisibilityState {
6059 self.visibility_state.get()
6060 }
6061
6062 fn CreateExpression(
6063 &self,
6064 expression: DOMString,
6065 resolver: Option<Rc<XPathNSResolver>>,
6066 can_gc: CanGc,
6067 ) -> Fallible<DomRoot<super::types::XPathExpression>> {
6068 let parsed_expression =
6069 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6070 Ok(XPathExpression::new(
6071 &self.window,
6072 None,
6073 can_gc,
6074 parsed_expression,
6075 ))
6076 }
6077
6078 fn CreateNSResolver(&self, node_resolver: &Node, can_gc: CanGc) -> DomRoot<Node> {
6079 let global = self.global();
6080 let window = global.as_window();
6081 let evaluator = XPathEvaluator::new(window, None, can_gc);
6082 XPathEvaluatorMethods::<crate::DomTypeHolder>::CreateNSResolver(&*evaluator, node_resolver)
6083 }
6084
6085 fn Evaluate(
6086 &self,
6087 expression: DOMString,
6088 context_node: &Node,
6089 resolver: Option<Rc<XPathNSResolver>>,
6090 result_type: u16,
6091 result: Option<&super::types::XPathResult>,
6092 can_gc: CanGc,
6093 ) -> Fallible<DomRoot<super::types::XPathResult>> {
6094 let parsed_expression =
6095 parse_expression(&expression.str(), resolver, self.is_html_document())?;
6096 XPathExpression::new(&self.window, None, can_gc, parsed_expression).evaluate_internal(
6097 context_node,
6098 result_type,
6099 result,
6100 can_gc,
6101 )
6102 }
6103
6104 fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
6106 self.adopted_stylesheets_frozen_types.get_or_init(
6107 || {
6108 self.adopted_stylesheets
6109 .borrow()
6110 .clone()
6111 .iter()
6112 .map(|sheet| sheet.as_rooted())
6113 .collect()
6114 },
6115 context,
6116 retval,
6117 can_gc,
6118 );
6119 }
6120
6121 fn SetAdoptedStyleSheets(
6123 &self,
6124 context: JSContext,
6125 val: HandleValue,
6126 can_gc: CanGc,
6127 ) -> ErrorResult {
6128 let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
6129 context,
6130 self.adopted_stylesheets.borrow_mut().as_mut(),
6131 val,
6132 &StyleSheetListOwner::Document(Dom::from_ref(self)),
6133 can_gc,
6134 );
6135
6136 if result.is_ok() {
6138 self.adopted_stylesheets_frozen_types.clear()
6139 }
6140
6141 result
6142 }
6143}
6144
6145fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
6146 if marker.get().is_none() {
6147 marker.set(Some(CrossProcessInstant::now()))
6148 }
6149}
6150
6151#[derive(Clone, Copy, PartialEq)]
6153pub(crate) enum FocusType {
6154 Element, Parent, }
6157
6158#[derive(Clone, Copy, PartialEq)]
6160pub enum FocusInitiator {
6161 Local,
6164 Remote,
6167}
6168
6169pub(crate) enum FocusEventType {
6171 Focus, Blur, }
6174
6175#[derive(JSTraceable, MallocSizeOf)]
6176pub(crate) enum AnimationFrameCallback {
6177 DevtoolsFramerateTick {
6178 actor_name: String,
6179 },
6180 FrameRequestCallback {
6181 #[conditional_malloc_size_of]
6182 callback: Rc<FrameRequestCallback>,
6183 },
6184}
6185
6186impl AnimationFrameCallback {
6187 fn call(&self, document: &Document, now: f64, can_gc: CanGc) {
6188 match *self {
6189 AnimationFrameCallback::DevtoolsFramerateTick { ref actor_name } => {
6190 let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name.clone(), now);
6191 let devtools_sender = document.window().as_global_scope().devtools_chan().unwrap();
6192 devtools_sender.send(msg).unwrap();
6193 },
6194 AnimationFrameCallback::FrameRequestCallback { ref callback } => {
6195 let _ = callback.Call__(Finite::wrap(now), ExceptionHandling::Report, can_gc);
6198 },
6199 }
6200 }
6201}
6202
6203#[derive(Default, JSTraceable, MallocSizeOf)]
6204#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6205struct PendingInOrderScriptVec {
6206 scripts: DomRefCell<VecDeque<PendingScript>>,
6207}
6208
6209impl PendingInOrderScriptVec {
6210 fn is_empty(&self) -> bool {
6211 self.scripts.borrow().is_empty()
6212 }
6213
6214 fn push(&self, element: &HTMLScriptElement) {
6215 self.scripts
6216 .borrow_mut()
6217 .push_back(PendingScript::new(element));
6218 }
6219
6220 fn loaded(&self, element: &HTMLScriptElement, result: ScriptResult) {
6221 let mut scripts = self.scripts.borrow_mut();
6222 let entry = scripts
6223 .iter_mut()
6224 .find(|entry| &*entry.element == element)
6225 .unwrap();
6226 entry.loaded(result);
6227 }
6228
6229 fn take_next_ready_to_be_executed(&self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6230 let mut scripts = self.scripts.borrow_mut();
6231 let pair = scripts.front_mut()?.take_result()?;
6232 scripts.pop_front();
6233 Some(pair)
6234 }
6235
6236 fn clear(&self) {
6237 *self.scripts.borrow_mut() = Default::default();
6238 }
6239}
6240
6241#[derive(JSTraceable, MallocSizeOf)]
6242#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
6243struct PendingScript {
6244 element: Dom<HTMLScriptElement>,
6245 load: Option<ScriptResult>,
6247}
6248
6249impl PendingScript {
6250 fn new(element: &HTMLScriptElement) -> Self {
6251 Self {
6252 element: Dom::from_ref(element),
6253 load: None,
6254 }
6255 }
6256
6257 fn new_with_load(element: &HTMLScriptElement, load: Option<ScriptResult>) -> Self {
6258 Self {
6259 element: Dom::from_ref(element),
6260 load,
6261 }
6262 }
6263
6264 fn loaded(&mut self, result: ScriptResult) {
6265 assert!(self.load.is_none());
6266 self.load = Some(result);
6267 }
6268
6269 fn take_result(&mut self) -> Option<(DomRoot<HTMLScriptElement>, ScriptResult)> {
6270 self.load
6271 .take()
6272 .map(|result| (DomRoot::from_ref(&*self.element), result))
6273 }
6274}
6275
6276fn is_named_element_with_name_attribute(elem: &Element) -> bool {
6277 let type_ = match elem.upcast::<Node>().type_id() {
6278 NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
6279 _ => return false,
6280 };
6281 match type_ {
6282 HTMLElementTypeId::HTMLFormElement |
6283 HTMLElementTypeId::HTMLIFrameElement |
6284 HTMLElementTypeId::HTMLImageElement => true,
6285 _ => false,
6289 }
6290}
6291
6292fn is_named_element_with_id_attribute(elem: &Element) -> bool {
6293 elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
6297}
6298
6299impl DocumentHelpers for Document {
6300 fn ensure_safe_to_run_script_or_layout(&self) {
6301 Document::ensure_safe_to_run_script_or_layout(self)
6302 }
6303}