/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{self, ShadowRootMode}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::element::Element; use crate::dom::node::{Node, NodeFlags}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; use style::author_styles::AuthorStyles; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot #[dom_struct] pub struct ShadowRoot { document_fragment: DocumentFragment, document_or_shadow_root: DocumentOrShadowRoot, document: Dom, host: Dom, /// List of stylesheets associated with nodes in this shadow tree. /// |None| if the list needs to be refreshed. author_styles: DomRefCell>, stylesheet_list: MutNullableDom, window: Dom, } impl ShadowRoot { #[allow(unrooted_must_root)] fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { let document_fragment = DocumentFragment::new_inherited(document); document_fragment .upcast::() .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); ShadowRoot { document_fragment, document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), document: Dom::from_ref(document), host: Dom::from_ref(host), author_styles: DomRefCell::new(AuthorStyles::new()), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), } } pub fn new(host: &Element, document: &Document) -> DomRoot { reflect_dom_object( Box::new(ShadowRoot::new_inherited(host, document)), document.window(), ShadowRootBinding::Wrap, ) } pub fn get_focused_element(&self) -> Option> { //XXX get retargeted focused element None } } impl ShadowRootMethods for ShadowRoot { // https://html.spec.whatwg.org/multipage/#dom-document-activeelement fn GetActiveElement(&self) -> Option> { self.document_or_shadow_root .get_active_element(self.get_focused_element(), None, None) } // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { // XXX return the result of running the retargeting algorithm with context object // and the original result as input self.document_or_shadow_root.element_from_point( x, y, None, self.document.has_browsing_context(), ) } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { // XXX return the result of running the retargeting algorithm with context object // and the original result as input self.document_or_shadow_root.elements_from_point( x, y, None, self.document.has_browsing_context(), ) } /// https://dom.spec.whatwg.org/#dom-shadowroot-mode fn Mode(&self) -> ShadowRootMode { ShadowRootMode::Closed } /// https://dom.spec.whatwg.org/#dom-shadowroot-host fn Host(&self) -> DomRoot { DomRoot::from_ref(&self.host) } // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { self.stylesheet_list .or_init(|| StyleSheetList::new(&self.window, Box::new(Dom::from_ref(self)))) } } #[allow(unsafe_code)] pub trait LayoutShadowRootHelpers { unsafe fn get_host_for_layout(&self) -> LayoutDom; } impl LayoutShadowRootHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn get_host_for_layout(&self) -> LayoutDom { (*self.unsafe_get()).host.to_layout() } } impl StyleSheetListOwner for Dom { fn stylesheet_count(&self) -> usize { self.author_styles.borrow().stylesheets.len() } fn stylesheet_at(&self, index: usize) -> Option> { let stylesheets = &self.author_styles.borrow().stylesheets; stylesheets .get(index) .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) } /// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the /// correct tree position. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn add_stylesheet(&self, owner: &Element, sheet: Arc) { let stylesheets = &mut self.author_styles.borrow_mut().stylesheets; let insertion_point = stylesheets .iter() .find(|sheet_in_shadow| { owner .upcast::() .is_before(sheet_in_shadow.owner.upcast()) }) .cloned(); self.document_or_shadow_root.add_stylesheet( owner, stylesheets, sheet, insertion_point, self.document.style_shared_lock(), ); } /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn remove_stylesheet(&self, owner: &Element, s: &Arc) { self.document_or_shadow_root.remove_stylesheet( owner, s, &mut self.author_styles.borrow_mut().stylesheets, ) } }