Invalidate and flush shadow tree stylesheets where needed

This commit is contained in:
Fernando Jiménez Moreno 2019-02-13 17:01:30 +01:00
parent 18c1b8f690
commit 519cc2c317
8 changed files with 115 additions and 25 deletions

View file

@ -83,6 +83,7 @@ use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode};
use style::dom::{TDocument, TElement, TNode, TShadowRoot}; use style::dom::{TDocument, TElement, TNode, TShadowRoot};
use style::element_state::*; use style::element_state::*;
use style::font_metrics::ServoMetricsProvider; use style::font_metrics::ServoMetricsProvider;
use style::media_queries::Device;
use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::properties::{ComputedValues, PropertyDeclarationBlock};
use style::selector_parser::{extended_filtering, PseudoElement, SelectorImpl}; use style::selector_parser::{extended_filtering, PseudoElement, SelectorImpl};
use style::selector_parser::{AttrValue as SelectorAttrValue, Lang, NonTSPseudoClass}; 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 { unsafe {
&self &self
.shadow_root .shadow_root
.flush_stylesheets::<ServoLayoutElement>(guard) .flush_stylesheets::<ServoLayoutElement>(device, quirks_mode, guard)
}; };
} }
} }
@ -425,6 +431,16 @@ impl<'ld> ServoLayoutDocument<'ld> {
unsafe { self.document.style_shared_lock() } unsafe { self.document.style_shared_lock() }
} }
pub fn shadow_roots(&self) -> Vec<ServoShadowRoot> {
unsafe {
self.document
.shadow_roots()
.iter()
.map(|sr| ServoShadowRoot::from_layout_js(*sr))
.collect()
}
}
pub fn from_layout_js(doc: LayoutDom<Document>) -> ServoLayoutDocument<'ld> { pub fn from_layout_js(doc: LayoutDom<Document>) -> ServoLayoutDocument<'ld> {
ServoLayoutDocument { ServoLayoutDocument {
document: doc, document: doc,

View file

@ -103,7 +103,7 @@ use std::time::Duration;
use style::animation::Animation; use style::animation::Animation;
use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters}; use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo}; 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::driver;
use style::error_reporting::RustLogReporter; use style::error_reporting::RustLogReporter;
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; 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(); let restyles = document.drain_pending_restyles();
debug!("Draining restyles: {}", restyles.len()); debug!("Draining restyles: {}", restyles.len());

View file

@ -13,7 +13,7 @@ use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::cssrule::CSSRule; use crate::dom::cssrule::CSSRule;
use crate::dom::element::Element; 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 crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use servo_arc::Arc; use servo_arc::Arc;
@ -115,10 +115,16 @@ impl CSSStyleOwner {
if changed { if changed {
// If this is changed, see also // If this is changed, see also
// CSSStyleRule::SetSelectorText, which does the same thing. // CSSStyleRule::SetSelectorText, which does the same thing.
rule.global() if let Some(shadow_root) =
.as_window() shadow_root_from_node(rule.parent_stylesheet().owner().upcast::<Node>())
.Document() {
.invalidate_stylesheets(); shadow_root.invalidate_stylesheets();
} else {
rule.global()
.as_window()
.Document()
.invalidate_stylesheets();
}
} }
result result
}, },

View file

@ -11,6 +11,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::cssrule::{CSSRule, SpecificCSSRule}; use crate::dom::cssrule::{CSSRule, SpecificCSSRule};
use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::node::{shadow_root_from_node, Node};
use crate::dom::window::Window; use crate::dom::window::Window;
use cssparser::ToCss; use cssparser::ToCss;
use cssparser::{Parser as CssParser, ParserInput as CssParserInput}; 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 mut guard = self.cssrule.shared_lock().write();
let stylerule = self.stylerule.write_with(&mut guard); let stylerule = self.stylerule.write_with(&mut guard);
mem::swap(&mut stylerule.selectors, &mut s); mem::swap(&mut stylerule.selectors, &mut s);
// It seems like we will want to avoid having to invalidate all if let Some(shadow_root) =
// stylesheets eventually! shadow_root_from_node(self.cssrule.parent_stylesheet().owner().upcast::<Node>())
self.global() {
.as_window() shadow_root.invalidate_stylesheets();
.Document() } else {
.invalidate_stylesheets(); // It seems like we will want to avoid having to invalidate all
// stylesheets eventually!
self.global()
.as_window()
.Document()
.invalidate_stylesheets();
}
} }
} }
} }

View file

@ -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::CSSStyleSheetBinding::CSSStyleSheetMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; 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::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::cssrulelist::{CSSRuleList, RulesSource}; use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
use crate::dom::element::Element; use crate::dom::element::Element;
use crate::dom::node::{shadow_root_from_node, Node};
use crate::dom::stylesheet::StyleSheet; use crate::dom::stylesheet::StyleSheet;
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
@ -64,6 +66,10 @@ impl CSSStyleSheet {
) )
} }
pub fn owner(&self) -> DomRoot<Element> {
DomRoot::from_ref(&*self.owner)
}
fn rulelist(&self) -> DomRoot<CSSRuleList> { fn rulelist(&self) -> DomRoot<CSSRuleList> {
self.rulelist.or_init(|| { self.rulelist.or_init(|| {
let rules = self.style_stylesheet.contents.rules.clone(); let rules = self.style_stylesheet.contents.rules.clone();
@ -81,10 +87,14 @@ impl CSSStyleSheet {
pub fn set_disabled(&self, disabled: bool) { pub fn set_disabled(&self, disabled: bool) {
if self.style_stylesheet.set_disabled(disabled) { if self.style_stylesheet.set_disabled(disabled) {
self.global() if let Some(shadow_root) = shadow_root_from_node(self.owner.upcast::<Node>()) {
.as_window() shadow_root.invalidate_stylesheets();
.Document() } else {
.invalidate_stylesheets(); self.global()
.as_window()
.Document()
.invalidate_stylesheets();
}
} }
} }

View file

@ -2430,6 +2430,7 @@ pub trait LayoutDocumentHelpers {
unsafe fn will_paint(&self); unsafe fn will_paint(&self);
unsafe fn quirks_mode(&self) -> QuirksMode; unsafe fn quirks_mode(&self) -> QuirksMode;
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock;
unsafe fn shadow_roots(&self) -> Vec<LayoutDom<ShadowRoot>>;
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -2474,6 +2475,16 @@ impl LayoutDocumentHelpers for LayoutDom<Document> {
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock { unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock {
(*self.unsafe_get()).style_shared_lock() (*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()
}
} }
// https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to

View file

@ -14,13 +14,15 @@ use crate::dom::document::Document;
use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument};
use crate::dom::element::Element; 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::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use selectors::context::QuirksMode;
use servo_arc::Arc; use servo_arc::Arc;
use style::author_styles::AuthorStyles; use style::author_styles::AuthorStyles;
use style::dom::TElement; use style::dom::TElement;
use style::media_queries::Device;
use style::shared_lock::SharedRwLockReadGuard; use style::shared_lock::SharedRwLockReadGuard;
use style::stylesheets::Stylesheet; use style::stylesheets::Stylesheet;
@ -67,6 +69,14 @@ impl ShadowRoot {
//XXX get retargeted focused element //XXX get retargeted focused element
None 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::<Node>()
.dirty(NodeDamage::NodeStyleDamaged);
}
} }
impl ShadowRootMethods for ShadowRoot { impl ShadowRootMethods for ShadowRoot {
@ -123,7 +133,12 @@ pub trait LayoutShadowRootHelpers {
unsafe fn get_style_data_for_layout<'a, E: TElement>( unsafe fn get_style_data_for_layout<'a, E: TElement>(
&self, &self,
) -> &'a AuthorStyles<StyleSheetInDocument>; ) -> &'a AuthorStyles<StyleSheetInDocument>;
unsafe fn flush_stylesheets<E: TElement>(&self, guard: &SharedRwLockReadGuard); unsafe fn flush_stylesheets<E: TElement>(
&self,
device: &Device,
quirks_mode: QuirksMode,
guard: &SharedRwLockReadGuard,
);
} }
impl LayoutShadowRootHelpers for LayoutDom<ShadowRoot> { impl LayoutShadowRootHelpers for LayoutDom<ShadowRoot> {
@ -143,10 +158,16 @@ impl LayoutShadowRootHelpers for LayoutDom<ShadowRoot> {
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn flush_stylesheets<E: TElement>(&self, guard: &SharedRwLockReadGuard) { unsafe fn flush_stylesheets<E: TElement>(
let document = &(*self.unsafe_get()).document; &self,
device: &Device,
quirks_mode: QuirksMode,
guard: &SharedRwLockReadGuard,
) {
let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout();
author_styles.flush::<E>(&document.device(), document.quirks_mode(), guard); if author_styles.stylesheets.dirty() {
author_styles.flush::<E>(device, quirks_mode, guard);
}
} }
} }

View file

@ -13,8 +13,9 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId}; 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::performanceresourcetiming::InitiatorType;
use crate::dom::shadowroot::ShadowRoot;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use cssparser::SourceLocation; use cssparser::SourceLocation;
use encoding_rs::UTF_8; use encoding_rs::UTF_8;
@ -81,6 +82,7 @@ pub struct StylesheetContext {
data: Vec<u8>, data: Vec<u8>,
/// The node document for elem when the load was initiated. /// The node document for elem when the load was initiated.
document: Trusted<Document>, document: Trusted<Document>,
shadow_root: Option<Trusted<ShadowRoot>>,
origin_clean: bool, origin_clean: bool,
/// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet. /// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet.
/// This is ignored for `HTMLStyleElement` and imports. /// 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: // FIXME: Revisit once consensus is reached at:
// https://github.com/whatwg/html/issues/1142 // https://github.com/whatwg/html/issues/1142
@ -264,6 +270,7 @@ impl<'a> StylesheetLoader<'a> {
integrity_metadata: String, integrity_metadata: String,
) { ) {
let document = document_from_node(self.elem); let document = document_from_node(self.elem);
let shadow_root = shadow_root_from_node(self.elem).map(|sr| Trusted::new(&*sr));
let gen = self let gen = self
.elem .elem
.downcast::<HTMLLinkElement>() .downcast::<HTMLLinkElement>()
@ -275,6 +282,7 @@ impl<'a> StylesheetLoader<'a> {
metadata: None, metadata: None,
data: vec![], data: vec![],
document: Trusted::new(&*document), document: Trusted::new(&*document),
shadow_root,
origin_clean: true, origin_clean: true,
request_generation_id: gen, request_generation_id: gen,
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),