diff options
Diffstat (limited to 'components/script/dom/document.rs')
-rw-r--r-- | components/script/dom/document.rs | 482 |
1 files changed, 188 insertions, 294 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ed011c8029d..1a6714f5927 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -43,6 +43,7 @@ use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::customelementregistry::CustomElementDefinition; use crate::dom::customevent::CustomEvent; use crate::dom::documentfragment::DocumentFragment; +use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::documenttype::DocumentType; use crate::dom::domimplementation::DOMImplementation; use crate::dom::element::CustomElementCreationMode; @@ -67,16 +68,14 @@ use crate::dom::htmlheadelement::HTMLHeadElement; use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlimageelement::HTMLImageElement; -use crate::dom::htmlmetaelement::HTMLMetaElement; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult}; use crate::dom::htmltitleelement::HTMLTitleElement; use crate::dom::keyboardevent::KeyboardEvent; use crate::dom::location::Location; use crate::dom::messageevent::MessageEvent; use crate::dom::mouseevent::MouseEvent; -use crate::dom::node::VecPreOrderInsertionHelper; use crate::dom::node::{self, document_from_node, window_from_node, CloneChildrenFlag}; -use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags}; +use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags, ShadowIncluding}; use crate::dom::nodeiterator::NodeIterator; use crate::dom::nodelist::NodeList; use crate::dom::pagetransitionevent::PageTransitionEvent; @@ -86,8 +85,9 @@ use crate::dom::progressevent::ProgressEvent; use crate::dom::promise::Promise; use crate::dom::range::Range; use crate::dom::servoparser::ServoParser; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::storageevent::StorageEvent; -use crate::dom::stylesheetlist::StyleSheetList; +use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::text::Text; use crate::dom::touch::Touch; use crate::dom::touchevent::TouchEvent; @@ -101,6 +101,7 @@ use crate::dom::windowproxy::WindowProxy; use crate::fetch::FetchCanceller; use crate::script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; use crate::script_thread::{MainThreadScriptMsg, ScriptThread}; +use crate::stylesheet_set::StylesheetSetRef; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::OneshotTimerCallback; @@ -113,7 +114,6 @@ use euclid::Point2D; use html5ever::{LocalName, Namespace, QualName}; use hyper_serde::Serde; use ipc_channel::ipc::{self, IpcSender}; -use js::jsapi::JS_GetRuntime; use js::jsapi::{JSContext, JSObject, JSRuntime}; use keyboard_types::{Key, KeyState, Modifiers}; use metrics::{ @@ -132,7 +132,7 @@ use num_traits::ToPrimitive; use profile_traits::ipc as profile_ipc; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use ref_slice::ref_slice; -use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg, ReflowGoal}; +use script_layout_interface::message::{Msg, ReflowGoal}; use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType}; use script_traits::{MsDuration, ScriptMsg, TouchEventType, TouchId, UntrustedNodeAddress}; use servo_arc::Arc; @@ -144,7 +144,6 @@ use std::cell::{Cell, Ref, RefMut}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet, VecDeque}; use std::default::Default; -use std::fmt; use std::mem; use std::ptr::NonNull; use std::rc::Rc; @@ -152,12 +151,12 @@ use std::time::{Duration, Instant}; use style::attr::AttrValue; use style::context::QuirksMode; use style::invalidation::element::restyle_hints::RestyleHint; -use style::media_queries::{Device, MediaList, MediaType}; +use style::media_queries::{Device, MediaType}; use style::selector_parser::{RestyleDamage, Snapshot}; -use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; +use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; use style::stylesheet_set::DocumentStylesheetSet; -use style::stylesheets::{CssRule, Origin, OriginSet, Stylesheet}; +use style::stylesheets::{Origin, OriginSet, Stylesheet}; use url::percent_encoding::percent_decode; use url::Host; @@ -220,52 +219,11 @@ impl PendingRestyle { } } -#[derive(Clone, JSTraceable, MallocSizeOf)] -#[must_root] -struct StyleSheetInDocument { - #[ignore_malloc_size_of = "Arc"] - sheet: Arc<Stylesheet>, - owner: Dom<Element>, -} - -impl fmt::Debug for StyleSheetInDocument { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.sheet.fmt(formatter) - } -} - -impl PartialEq for StyleSheetInDocument { - fn eq(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.sheet, &other.sheet) - } -} - -impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { - fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { - self.sheet.origin(guard) - } - - fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { - self.sheet.quirks_mode(guard) - } - - fn enabled(&self) -> bool { - self.sheet.enabled() - } - - fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { - self.sheet.media(guard) - } - - fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { - self.sheet.rules(guard) - } -} - /// <https://dom.spec.whatwg.org/#document> #[dom_struct] pub struct Document { node: Node, + document_or_shadow_root: DocumentOrShadowRoot, window: Dom<Window>, implementation: MutNullableDom<DOMImplementation>, #[ignore_malloc_size_of = "type from external crate"] @@ -419,6 +377,10 @@ pub struct Document { delayed_tasks: DomRefCell<Vec<Box<dyn TaskBox>>>, /// https://html.spec.whatwg.org/multipage/#completely-loaded completely_loaded: Cell<bool>, + /// Set of shadow roots connected to the document tree. + shadow_roots: DomRefCell<HashSet<Dom<ShadowRoot>>>, + /// Whether any of the shadow roots need the stylesheets flushed. + shadow_roots_styles_changed: Cell<bool>, } #[derive(JSTraceable, MallocSizeOf)] @@ -634,7 +596,7 @@ impl Document { pub fn refresh_base_element(&self) { let base = self .upcast::<Node>() - .traverse_preorder() + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::<HTMLBaseElement>) .find(|element| { element @@ -684,7 +646,7 @@ impl Document { } pub fn content_and_heritage_changed(&self, node: &Node) { - if node.is_in_doc() { + if node.is_connected() { node.note_dirty_descendants(); } @@ -720,55 +682,23 @@ impl Document { /// Remove any existing association between the provided id and any elements in this document. pub fn unregister_named_element(&self, to_unregister: &Element, id: Atom) { - debug!( - "Removing named element from document {:p}: {:p} id={}", - self, to_unregister, id - ); - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = self.id_map.borrow_mut(); - let is_empty = match id_map.get_mut(&id) { - None => false, - Some(elements) => { - let position = elements - .iter() - .position(|element| &**element == to_unregister) - .expect("This element should be in registered."); - elements.remove(position); - elements.is_empty() - }, - }; - if is_empty { - id_map.remove(&id); - } - } + self.document_or_shadow_root + .unregister_named_element(&self.id_map, to_unregister, &id); self.reset_form_owner_for_listeners(&id); } /// Associate an element present in this document with the provided id. pub fn register_named_element(&self, element: &Element, id: Atom) { - debug!( - "Adding named element to document {:p}: {:p} id={}", - self, element, id - ); - assert!(element.upcast::<Node>().is_in_doc()); - assert!(!id.is_empty()); - let root = self.GetDocumentElement().expect( "The element is in the document, so there must be a document \ element.", ); - - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = self.id_map.borrow_mut(); - let elements = id_map.entry(id.clone()).or_insert(Vec::new()); - elements.insert_pre_order(element, root.upcast::<Node>()); - } + self.document_or_shadow_root.register_named_element( + &self.id_map, + element, + &id, + DomRoot::from_ref(root.upcast::<Node>()), + ); self.reset_form_owner_for_listeners(&id); } @@ -872,7 +802,7 @@ impl Document { }; let doc_node = self.upcast::<Node>(); doc_node - .traverse_preorder() + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast) .find(|node| check_anchor(&node)) .map(DomRoot::upcast) @@ -981,7 +911,7 @@ impl Document { pub fn dirty_all_nodes(&self) { let root = self.upcast::<Node>(); - for node in root.traverse_preorder() { + for node in root.traverse_preorder(ShadowIncluding::Yes) { node.dirty(NodeDamage::OtherNodeDamage) } } @@ -1005,7 +935,7 @@ impl Document { let el = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::<Element>) .next() }); @@ -1189,7 +1119,7 @@ impl Document { let maybe_new_target = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::<Element>) .next() }); @@ -1225,7 +1155,7 @@ impl Document { if !old_target_is_ancestor_of_new_target { for element in old_target .upcast::<Node>() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::<Element>) { element.set_hover_state(false); @@ -1243,7 +1173,7 @@ impl Document { if let Some(ref new_target) = maybe_new_target { for element in new_target .upcast::<Node>() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::<Element>) { if element.hover_state() { @@ -1285,7 +1215,7 @@ impl Document { let el = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::<Element>) .next() }); @@ -2276,7 +2206,7 @@ impl Document { /// Iterate over all iframes in the document. pub fn iter_iframes(&self) -> impl Iterator<Item = DomRoot<HTMLIFrameElement>> { self.upcast::<Node>() - .traverse_preorder() + .traverse_preorder(ShadowIncluding::Yes) .filter_map(DomRoot::downcast::<HTMLIFrameElement>) } @@ -2395,21 +2325,6 @@ impl Document { !self.has_browsing_context || !url_has_network_scheme(&self.url()) } - pub fn nodes_from_point( - &self, - client_point: &Point2D<f32>, - reflow_goal: NodesFromPointQueryType, - ) -> Vec<UntrustedNodeAddress> { - if !self - .window - .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) - { - return vec![]; - }; - - self.window.layout().nodes_from_point_response() - } - /// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition> pub fn lookup_custom_element_definition( &self, @@ -2485,6 +2400,9 @@ pub trait LayoutDocumentHelpers { unsafe fn will_paint(&self); unsafe fn quirks_mode(&self) -> QuirksMode; unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; + unsafe fn shadow_roots(&self) -> Vec<LayoutDom<ShadowRoot>>; + unsafe fn shadow_roots_styles_changed(&self) -> bool; + unsafe fn flush_shadow_roots_stylesheets(&self); } #[allow(unsafe_code)] @@ -2500,12 +2418,12 @@ impl LayoutDocumentHelpers for LayoutDom<Document> { let mut elements = (*self.unsafe_get()) .pending_restyles .borrow_mut_for_layout(); - // Elements were in a document when they were adding to this list, but that + // Elements were in a document when they were added to this list, but that // may no longer be true when the next layout occurs. let result = elements .drain() .map(|(k, v)| (k.to_layout(), v)) - .filter(|&(ref k, _)| k.upcast::<Node>().get_flag(NodeFlags::IS_IN_DOC)) + .filter(|&(ref k, _)| k.upcast::<Node>().get_flag(NodeFlags::IS_CONNECTED)) .collect(); result } @@ -2529,6 +2447,26 @@ impl LayoutDocumentHelpers for LayoutDom<Document> { unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock { (*self.unsafe_get()).style_shared_lock() } + + #[inline] + unsafe fn shadow_roots(&self) -> Vec<LayoutDom<ShadowRoot>> { + (*self.unsafe_get()) + .shadow_roots + .borrow_for_layout() + .iter() + .map(|sr| sr.to_layout()) + .collect() + } + + #[inline] + unsafe fn shadow_roots_styles_changed(&self) -> bool { + (*self.unsafe_get()).shadow_roots_styles_changed() + } + + #[inline] + unsafe fn flush_shadow_roots_stylesheets(&self) { + (*self.unsafe_get()).flush_shadow_roots_stylesheets() + } } // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to @@ -2637,21 +2575,23 @@ impl Document { .and_then(|charset| Encoding::for_label(charset.as_str().as_bytes())) .unwrap_or(UTF_8); + let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes; Document { node: Node::new_document_node(), + document_or_shadow_root: DocumentOrShadowRoot::new(window), window: Dom::from_ref(window), - has_browsing_context: has_browsing_context == HasBrowsingContext::Yes, + has_browsing_context, implementation: Default::default(), content_type, last_modified: last_modified, url: DomRefCell::new(url), // https://dom.spec.whatwg.org/#concept-document-quirks quirks_mode: Cell::new(QuirksMode::NoQuirks), + id_map: DomRefCell::new(HashMap::new()), // https://dom.spec.whatwg.org/#concept-document-encoding encoding: Cell::new(encoding), is_html_document: is_html_document == IsHTMLDocument::HTMLDocument, activity: Cell::new(activity), - id_map: DomRefCell::new(HashMap::new()), tag_map: DomRefCell::new(HashMap::new()), tagns_map: DomRefCell::new(HashMap::new()), classes_map: DomRefCell::new(HashMap::new()), @@ -2689,7 +2629,7 @@ impl Document { deferred_scripts: Default::default(), asap_in_order_scripts_list: Default::default(), asap_scripts_set: Default::default(), - scripting_enabled: has_browsing_context == HasBrowsingContext::Yes, + scripting_enabled: has_browsing_context, animation_frame_ident: Cell::new(0), animation_frame_list: DomRefCell::new(vec![]), running_animation_callbacks: Cell::new(false), @@ -2735,6 +2675,8 @@ impl Document { completely_loaded: Cell::new(false), script_and_layout_blockers: Cell::new(0), delayed_tasks: Default::default(), + shadow_roots: DomRefCell::new(HashSet::new()), + shadow_roots_styles_changed: Cell::new(false), } } @@ -2853,7 +2795,7 @@ impl Document { let maybe_node = doc.deref().map(Castable::upcast::<Node>); let iter = maybe_node .iter() - .flat_map(|node| node.traverse_preorder()) + .flat_map(|node| node.traverse_preorder(ShadowIncluding::No)) .filter(|node| callback(&node)); NodeList::new_simple_list(&self.window, iter) } @@ -2893,93 +2835,10 @@ impl Document { Device::new(MediaType::screen(), viewport_size, device_pixel_ratio) } - /// Remove a stylesheet owned by `owner` from the list of document sheets. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - pub fn remove_stylesheet(&self, owner: &Element, s: &Arc<Stylesheet>) { - self.window() - .layout_chan() - .send(Msg::RemoveStylesheet(s.clone())) - .unwrap(); - - let guard = s.shared_lock.read(); - - // FIXME(emilio): Would be nice to remove the clone, etc. - self.stylesheets.borrow_mut().remove_stylesheet( - None, - StyleSheetInDocument { - sheet: s.clone(), - owner: Dom::from_ref(owner), - }, - &guard, - ); - } - - /// Add a stylesheet owned by `owner` to the list of document sheets, in the - /// correct tree position. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - pub fn add_stylesheet(&self, owner: &Element, sheet: Arc<Stylesheet>) { - // FIXME(emilio): It'd be nice to unify more code between the elements - // that own stylesheets, but StylesheetOwner is more about loading - // them... - debug_assert!( - owner.as_stylesheet_owner().is_some() || owner.is::<HTMLMetaElement>(), - "Wat" - ); - - let mut stylesheets = self.stylesheets.borrow_mut(); - let insertion_point = stylesheets - .iter() - .map(|(sheet, _origin)| sheet) - .find(|sheet_in_doc| { - owner - .upcast::<Node>() - .is_before(sheet_in_doc.owner.upcast()) - }) - .cloned(); - - self.window() - .layout_chan() - .send(Msg::AddStylesheet( - sheet.clone(), - insertion_point.as_ref().map(|s| s.sheet.clone()), - )) - .unwrap(); - - let sheet = StyleSheetInDocument { - sheet, - owner: Dom::from_ref(owner), - }; - - let lock = self.style_shared_lock(); - let guard = lock.read(); - - match insertion_point { - Some(ip) => { - stylesheets.insert_stylesheet_before(None, sheet, ip, &guard); - }, - None => { - stylesheets.append_stylesheet(None, sheet, &guard); - }, - } - } - - /// Returns the number of document stylesheets. - pub fn stylesheet_count(&self) -> usize { - self.stylesheets.borrow().len() - } - pub fn salvageable(&self) -> bool { self.salvageable.get() } - pub fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> { - let stylesheets = self.stylesheets.borrow(); - - stylesheets - .get(Origin::Author, index) - .and_then(|s| s.owner.upcast::<Node>().get_cssom_stylesheet()) - } - /// <https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document> pub fn appropriate_template_contents_owner_document(&self) -> DomRoot<Document> { self.appropriate_template_contents_owner_document @@ -3270,6 +3129,92 @@ impl Document { } } } + + pub fn register_shadow_root(&self, shadow_root: &ShadowRoot) { + self.shadow_roots + .borrow_mut() + .insert(Dom::from_ref(shadow_root)); + self.invalidate_shadow_roots_stylesheets(); + } + + pub fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) { + let mut shadow_roots = self.shadow_roots.borrow_mut(); + shadow_roots.remove(&Dom::from_ref(shadow_root)); + } + + pub fn invalidate_shadow_roots_stylesheets(&self) { + self.shadow_roots_styles_changed.set(true); + } + + pub fn shadow_roots_styles_changed(&self) -> bool { + self.shadow_roots_styles_changed.get() + } + + pub fn flush_shadow_roots_stylesheets(&self) { + if !self.shadow_roots_styles_changed.get() { + return; + } + self.shadow_roots_styles_changed.set(false); + } + + pub fn stylesheet_count(&self) -> usize { + self.stylesheets.borrow().len() + } + + pub fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> { + let stylesheets = self.stylesheets.borrow(); + + stylesheets + .get(Origin::Author, index) + .and_then(|s| s.owner.upcast::<Node>().get_cssom_stylesheet()) + } + + /// Add a stylesheet owned by `owner` to the list of document sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn add_stylesheet(&self, owner: &Element, sheet: Arc<Stylesheet>) { + let stylesheets = &mut *self.stylesheets.borrow_mut(); + let insertion_point = stylesheets + .iter() + .map(|(sheet, _origin)| sheet) + .find(|sheet_in_doc| { + owner + .upcast::<Node>() + .is_before(sheet_in_doc.owner.upcast()) + }) + .cloned(); + + self.window + .layout_chan() + .send(Msg::AddStylesheet( + sheet.clone(), + insertion_point.as_ref().map(|s| s.sheet.clone()), + )) + .unwrap(); + + DocumentOrShadowRoot::add_stylesheet( + owner, + StylesheetSetRef::Document(stylesheets), + sheet, + insertion_point, + self.style_shared_lock(), + ); + } + + /// Remove a stylesheet owned by `owner` from the list of document sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn remove_stylesheet(&self, owner: &Element, s: &Arc<Stylesheet>) { + self.window + .layout_chan() + .send(Msg::RemoveStylesheet(s.clone())) + .unwrap(); + + DocumentOrShadowRoot::remove_stylesheet( + owner, + s, + StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()), + ) + } } impl Element { @@ -3301,8 +3246,12 @@ impl ProfilerMetadataFactory for Document { impl DocumentMethods for Document { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot<StyleSheetList> { - self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, Dom::from_ref(&self))) + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + StyleSheetListOwner::Document(Dom::from_ref(self)), + ) + }) } // https://dom.spec.whatwg.org/#dom-document-implementation @@ -3317,16 +3266,11 @@ impl DocumentMethods for Document { // https://html.spec.whatwg.org/multipage/#dom-document-activeelement fn GetActiveElement(&self) -> Option<DomRoot<Element>> { - // TODO: Step 2. - - match self.get_focused_element() { - Some(element) => Some(element), // Step 3. and 4. - None => match self.GetBody() { - // Step 5. - Some(body) => Some(DomRoot::upcast(body)), - None => self.GetDocumentElement(), - }, - } + self.document_or_shadow_root.get_active_element( + self.get_focused_element(), + self.GetBody(), + self.GetDocumentElement(), + ) } // https://html.spec.whatwg.org/multipage/#dom-document-hasfocus @@ -3643,7 +3587,7 @@ impl DocumentMethods for Document { // https://dom.spec.whatwg.org/#dom-document-importnode fn ImportNode(&self, node: &Node, deep: bool) -> Fallible<DomRoot<Node>> { // Step 1. - if node.is::<Document>() { + if node.is::<Document>() || node.is::<ShadowRoot>() { return Err(Error::NotSupported); } @@ -3665,9 +3609,14 @@ impl DocumentMethods for Document { } // Step 2. - Node::adopt(node, self); + if node.is::<ShadowRoot>() { + return Err(Error::HierarchyRequest); + } // Step 3. + Node::adopt(node, self); + + // Step 4. Ok(DomRoot::from_ref(node)) } @@ -3805,7 +3754,7 @@ impl DocumentMethods for Document { } else { // Step 2. root.upcast::<Node>() - .traverse_preorder() + .traverse_preorder(ShadowIncluding::No) .find(|node| node.is::<HTMLTitleElement>()) } }); @@ -3852,7 +3801,7 @@ impl DocumentMethods for Document { } else if root.namespace() == &ns!(html) { let elem = root .upcast::<Node>() - .traverse_preorder() + .traverse_preorder(ShadowIncluding::No) .find(|node| node.is::<HTMLTitleElement>()); match elem { Some(elem) => elem, @@ -4219,7 +4168,7 @@ impl DocumentMethods for Document { { // Step 1. let mut elements = root - .traverse_preorder() + .traverse_preorder(ShadowIncluding::No) .filter(|node| filter_by_name(&name, &node)) .peekable(); if let Some(first) = elements.next() { @@ -4273,82 +4222,24 @@ impl DocumentMethods for Document { SetOnreadystatechange ); - #[allow(unsafe_code)] // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> { - let x = *x as f32; - let y = *y as f32; - let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = window.window_size().initial_viewport; - - if self.browsing_context().is_none() { - return None; - } - - if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height { - return None; - } - - match self - .nodes_from_point(point, NodesFromPointQueryType::Topmost) - .first() - { - Some(address) => { - let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; - let node = unsafe { node::from_untrusted_node_address(js_runtime, *address) }; - let parent_node = node.GetParentNode().unwrap(); - let element_ref = node - .downcast::<Element>() - .unwrap_or_else(|| parent_node.downcast::<Element>().unwrap()); - - Some(DomRoot::from_ref(element_ref)) - }, - None => self.GetDocumentElement(), - } + self.document_or_shadow_root.element_from_point( + x, + y, + self.GetDocumentElement(), + self.has_browsing_context, + ) } - #[allow(unsafe_code)] // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> { - let x = *x as f32; - let y = *y as f32; - let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = window.window_size().initial_viewport; - - if self.browsing_context().is_none() { - return vec![]; - } - - // Step 2 - if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height { - return vec![]; - } - - let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; - - // Step 1 and Step 3 - let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); - let mut elements: Vec<DomRoot<Element>> = nodes - .iter() - .flat_map(|&untrusted_node_address| { - let node = unsafe { - node::from_untrusted_node_address(js_runtime, untrusted_node_address) - }; - DomRoot::downcast::<Element>(node) - }) - .collect(); - - // Step 4 - if let Some(root_element) = self.GetDocumentElement() { - if elements.last() != Some(&root_element) { - elements.push(root_element); - } - } - - // Step 5 - elements + self.document_or_shadow_root.elements_from_point( + x, + y, + self.GetDocumentElement(), + self.has_browsing_context, + ) } // https://html.spec.whatwg.org/multipage/#dom-document-open @@ -4403,7 +4294,10 @@ impl DocumentMethods for Document { } // Step 8 - for node in self.upcast::<Node>().traverse_preorder() { + for node in self + .upcast::<Node>() + .traverse_preorder(ShadowIncluding::Yes) + { node.upcast::<EventTarget>().remove_all_listeners(); } |