From 519cc2c31754d75c1b6cab7db0cfb0c1aaabbdf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 13 Feb 2019 17:01:30 +0100 Subject: [PATCH] Invalidate and flush shadow tree stylesheets where needed --- components/layout_thread/dom_wrapper.rs | 20 +++++++++++-- components/layout_thread/lib.rs | 13 +++++++- components/script/dom/cssstyledeclaration.rs | 16 ++++++---- components/script/dom/cssstylerule.rs | 19 ++++++++---- components/script/dom/cssstylesheet.rs | 18 +++++++++--- components/script/dom/document.rs | 11 +++++++ components/script/dom/shadowroot.rs | 31 ++++++++++++++++---- components/script/stylesheet_loader.rs | 12 ++++++-- 8 files changed, 115 insertions(+), 25 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index bbc023cf958..1aa9488c327 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -83,6 +83,7 @@ use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode}; use style::dom::{TDocument, TElement, TNode, TShadowRoot}; use style::element_state::*; use style::font_metrics::ServoMetricsProvider; +use style::media_queries::Device; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{extended_filtering, PseudoElement, SelectorImpl}; use style::selector_parser::{AttrValue as SelectorAttrValue, Lang, NonTSPseudoClass}; @@ -219,11 +220,16 @@ impl<'sr> ServoShadowRoot<'sr> { } } - pub fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { + pub fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ) { unsafe { &self .shadow_root - .flush_stylesheets::(guard) + .flush_stylesheets::(device, quirks_mode, guard) }; } } @@ -425,6 +431,16 @@ impl<'ld> ServoLayoutDocument<'ld> { unsafe { self.document.style_shared_lock() } } + pub fn shadow_roots(&self) -> Vec { + unsafe { + self.document + .shadow_roots() + .iter() + .map(|sr| ServoShadowRoot::from_layout_js(*sr)) + .collect() + } + } + pub fn from_layout_js(doc: LayoutDom) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 839fac79006..8c46fb90720 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -103,7 +103,7 @@ use std::time::Duration; use style::animation::Animation; use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters}; use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo}; -use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode}; +use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; @@ -1346,6 +1346,17 @@ impl LayoutThread { } } + debug!( + "Shadow roots in document {:?}", + document.shadow_roots().len() + ); + + let device = Device::new(MediaType::screen(), initial_viewport, device_pixel_ratio); + // Flush shadow roots stylesheets if dirty. + for shadow_root in document.shadow_roots() { + shadow_root.flush_stylesheets(&device, document.quirks_mode(), guards.author.clone()); + } + let restyles = document.drain_pending_restyles(); debug!("Draining restyles: {}", restyles.len()); diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 5cc2f64af11..bbb788cceeb 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -13,7 +13,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::CSSRule; use crate::dom::element::Element; -use crate::dom::node::{document_from_node, window_from_node, Node}; +use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node, Node}; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; @@ -115,10 +115,16 @@ impl CSSStyleOwner { if changed { // If this is changed, see also // CSSStyleRule::SetSelectorText, which does the same thing. - rule.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = + shadow_root_from_node(rule.parent_stylesheet().owner().upcast::()) + { + shadow_root.invalidate_stylesheets(); + } else { + rule.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } result }, diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index c76e3bdd938..173661eb30a 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::{CSSRule, SpecificCSSRule}; use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; use crate::dom::cssstylesheet::CSSStyleSheet; +use crate::dom::node::{shadow_root_from_node, Node}; use crate::dom::window::Window; use cssparser::ToCss; use cssparser::{Parser as CssParser, ParserInput as CssParserInput}; @@ -118,12 +119,18 @@ impl CSSStyleRuleMethods for CSSStyleRule { let mut guard = self.cssrule.shared_lock().write(); let stylerule = self.stylerule.write_with(&mut guard); mem::swap(&mut stylerule.selectors, &mut s); - // It seems like we will want to avoid having to invalidate all - // stylesheets eventually! - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = + shadow_root_from_node(self.cssrule.parent_stylesheet().owner().upcast::()) + { + shadow_root.invalidate_stylesheets(); + } else { + // It seems like we will want to avoid having to invalidate all + // stylesheets eventually! + self.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } } } diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index 2def47d7aaa..9863dede5cb 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -6,11 +6,13 @@ use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding; use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; +use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrulelist::{CSSRuleList, RulesSource}; use crate::dom::element::Element; +use crate::dom::node::{shadow_root_from_node, Node}; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -64,6 +66,10 @@ impl CSSStyleSheet { ) } + pub fn owner(&self) -> DomRoot { + DomRoot::from_ref(&*self.owner) + } + fn rulelist(&self) -> DomRoot { self.rulelist.or_init(|| { let rules = self.style_stylesheet.contents.rules.clone(); @@ -81,10 +87,14 @@ impl CSSStyleSheet { pub fn set_disabled(&self, disabled: bool) { if self.style_stylesheet.set_disabled(disabled) { - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = shadow_root_from_node(self.owner.upcast::()) { + shadow_root.invalidate_stylesheets(); + } else { + self.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3f1bf1c450a..f1ddfc9f378 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -2430,6 +2430,7 @@ 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>; } #[allow(unsafe_code)] @@ -2474,6 +2475,16 @@ impl LayoutDocumentHelpers for LayoutDom { unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock { (*self.unsafe_get()).style_shared_lock() } + + #[inline] + unsafe fn shadow_roots(&self) -> Vec> { + (*self.unsafe_get()) + .shadow_roots + .borrow_for_layout() + .iter() + .map(|sr| sr.to_layout()) + .collect() + } } // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7f06b486b1d..aad85d4d087 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -14,13 +14,15 @@ 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::node::{Node, NodeDamage, NodeFlags}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; +use selectors::context::QuirksMode; use servo_arc::Arc; use style::author_styles::AuthorStyles; use style::dom::TElement; +use style::media_queries::Device; use style::shared_lock::SharedRwLockReadGuard; use style::stylesheets::Stylesheet; @@ -67,6 +69,14 @@ impl ShadowRoot { //XXX get retargeted focused element None } + + pub fn invalidate_stylesheets(&self) { + self.author_styles.borrow_mut().stylesheets.force_dirty(); + // Mark the host element dirty so a reflow will be performed. + self.host + .upcast::() + .dirty(NodeDamage::NodeStyleDamaged); + } } impl ShadowRootMethods for ShadowRoot { @@ -123,7 +133,12 @@ pub trait LayoutShadowRootHelpers { unsafe fn get_style_data_for_layout<'a, E: TElement>( &self, ) -> &'a AuthorStyles; - unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard); + unsafe fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ); } impl LayoutShadowRootHelpers for LayoutDom { @@ -143,10 +158,16 @@ impl LayoutShadowRootHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] - unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { - let document = &(*self.unsafe_get()).document; + unsafe fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ) { let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); - author_styles.flush::(&document.device(), document.quirks_mode(), guard); + if author_styles.stylesheets.dirty() { + author_styles.flush::(device, quirks_mode, guard); + } } } diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 61c89b35f80..3c75bfef520 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -13,8 +13,9 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId}; -use crate::dom::node::{document_from_node, window_from_node}; +use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node}; use crate::dom::performanceresourcetiming::InitiatorType; +use crate::dom::shadowroot::ShadowRoot; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use cssparser::SourceLocation; use encoding_rs::UTF_8; @@ -81,6 +82,7 @@ pub struct StylesheetContext { data: Vec, /// The node document for elem when the load was initiated. document: Trusted, + shadow_root: Option>, origin_clean: bool, /// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet. /// This is ignored for `HTMLStyleElement` and imports. @@ -187,7 +189,11 @@ impl FetchResponseListener for StylesheetContext { }, } - document.invalidate_stylesheets(); + if let Some(ref shadow_root) = self.shadow_root { + shadow_root.root().invalidate_stylesheets(); + } else { + document.invalidate_stylesheets(); + } // FIXME: Revisit once consensus is reached at: // https://github.com/whatwg/html/issues/1142 @@ -264,6 +270,7 @@ impl<'a> StylesheetLoader<'a> { integrity_metadata: String, ) { let document = document_from_node(self.elem); + let shadow_root = shadow_root_from_node(self.elem).map(|sr| Trusted::new(&*sr)); let gen = self .elem .downcast::() @@ -275,6 +282,7 @@ impl<'a> StylesheetLoader<'a> { metadata: None, data: vec![], document: Trusted::new(&*document), + shadow_root, origin_clean: true, request_generation_id: gen, resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),