diff options
Diffstat (limited to 'components/script/dom/documentorshadowroot.rs')
-rw-r--r-- | components/script/dom/documentorshadowroot.rs | 183 |
1 files changed, 151 insertions, 32 deletions
diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 5e413c5cc89..b1ea9ee1549 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -2,65 +2,86 @@ * 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::NodeBinding::NodeBinding::NodeMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::cssstylesheet::CSSStyleSheet; -use crate::dom::document::Document; use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node; -use crate::dom::shadowroot::ShadowRoot; +use crate::dom::htmlmetaelement::HTMLMetaElement; +use crate::dom::node::{self, Node}; use crate::dom::window::Window; use euclid::Point2D; use js::jsapi::JS_GetRuntime; -use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; +use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg}; use script_traits::UntrustedNodeAddress; +use servo_arc::Arc; +use std::fmt; +use style::context::QuirksMode; +use style::media_queries::MediaList; +use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; +use style::stylesheet_set::DocumentStylesheetSet; +use style::stylesheets::{CssRule, Origin, OriginSet, Stylesheet}; -macro_rules! proxy_call( - ($fn_name:ident, $return_type:ty) => ( - pub fn $fn_name(&self) -> $return_type { - match self { - DocumentOrShadowRoot::Document(doc) => doc.$fn_name(), - DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name(), - } - } - ); +#[derive(Clone, JSTraceable, MallocSizeOf)] +#[must_root] +pub struct StyleSheetInDocument { + #[ignore_malloc_size_of = "Arc"] + sheet: Arc<Stylesheet>, + owner: Dom<Element>, +} - ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( - pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { - match self { - DocumentOrShadowRoot::Document(doc) => doc.$fn_name($arg1), - DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name($arg1), - } - } - ); -); +impl fmt::Debug for StyleSheetInDocument { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.sheet.fmt(formatter) + } +} -#[must_root] -#[derive(JSTraceable, MallocSizeOf)] -pub enum DocumentOrShadowRoot { - Document(Dom<Document>), - ShadowRoot(Dom<ShadowRoot>), +impl PartialEq for StyleSheetInDocument { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.sheet, &other.sheet) + } } -impl DocumentOrShadowRoot { - proxy_call!(stylesheet_count, usize); - proxy_call!(stylesheet_at, index, usize, Option<DomRoot<CSSStyleSheet>>); +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://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin #[must_root] #[derive(JSTraceable, MallocSizeOf)] -pub struct DocumentOrShadowRootImpl { +pub struct DocumentOrShadowRoot { window: Dom<Window>, + /// List of stylesheets associated with nodes in this document or shadow root. + /// |None| if the list needs to be refreshed. + stylesheets: DomRefCell<DocumentStylesheetSet<StyleSheetInDocument>>, } -impl DocumentOrShadowRootImpl { +impl DocumentOrShadowRoot { pub fn new(window: &Window) -> Self { Self { window: Dom::from_ref(window), + stylesheets: DomRefCell::new(DocumentStylesheetSet::new()), } } @@ -185,4 +206,102 @@ impl DocumentOrShadowRootImpl { }, } } + + 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()) + } + + pub fn stylesheets_have_changed(&self) -> bool { + self.stylesheets.borrow().has_changed() + } + + pub fn invalidate_stylesheets(&self) { + self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); + } + + pub fn flush_stylesheets_without_invalidation(&self) { + self.stylesheets.borrow_mut().flush_without_invalidation(); + } + + /// 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>, + style_shared_lock: &StyleSharedRwLock, + ) { + // 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 guard = style_shared_lock.read(); + + match insertion_point { + Some(ip) => { + stylesheets.insert_stylesheet_before(None, sheet, ip, &guard); + }, + None => { + stylesheets.append_stylesheet(None, sheet, &guard); + }, + } + } } |