diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 82872d4473f..386cc31c99f 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -47,6 +47,77 @@ where } } +/// A struct to iterate over the different stylesheets to be flushed. +pub struct StylesheetFlusher<'a, 'b, S> +where + 'b: 'a, + S: StylesheetInDocument + PartialEq + 'static, +{ + iter: slice::IterMut<'a, StylesheetSetEntry>, + guard: &'a SharedRwLockReadGuard<'b>, + origins_dirty: OriginSet, + author_style_disabled: bool, + had_invalidations: bool, +} + +/// The type of rebuild that we need to do for a given stylesheet. +pub enum SheetRebuildKind { + /// For now we only support full rebuilds, in the future we'll implement + /// partial rebuilds. + Full, +} + +impl<'a, 'b, S> StylesheetFlusher<'a, 'b, S> +where + 'b: 'a, + S: StylesheetInDocument + PartialEq + 'static, +{ + /// The set of origins to fully rebuild, which need to be cleared + /// beforehand. + pub fn origins_to_fully_rebuild(&self) -> OriginSet { + self.origins_dirty + } + + /// Returns whether running the whole flushing process would be a no-op. + pub fn nothing_to_do(&self) -> bool { + self.origins_dirty.is_empty() + } + + /// Returns whether any DOM invalidations were processed as a result of the + /// stylesheet flush. + pub fn had_invalidations(&self) -> bool { + self.had_invalidations + } +} + +impl<'a, 'b, S> Iterator for StylesheetFlusher<'a, 'b, S> +where + 'b: 'a, + S: StylesheetInDocument + PartialEq + 'static, +{ + type Item = (&'a S, SheetRebuildKind); + + fn next(&mut self) -> Option { + loop { + let potential_sheet = match self.iter.next() { + None => return None, + Some(s) => s, + }; + + let origin = potential_sheet.sheet.contents(self.guard).origin; + if !self.origins_dirty.contains(origin.into()) { + continue; + } + + if self.author_style_disabled && matches!(origin, Origin::Author) { + continue; + } + + return Some((&potential_sheet.sheet, SheetRebuildKind::Full)) + } + } +} + /// The set of stylesheets effective for a given document. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct StylesheetSet @@ -189,12 +260,13 @@ where !self.origins_dirty.is_empty() } - /// Flush the current set, unmarking it as dirty, and returns the damaged - /// origins, and whether any elements were invalidated. - pub fn flush( - &mut self, + /// Flush the current set, unmarking it as dirty, and returns a + /// `StylesheetFlusher` in order to rebuild the stylist. + pub fn flush<'a, 'b, E>( + &'a mut self, document_element: Option, - ) -> (OriginSet, bool) + guard: &'a SharedRwLockReadGuard<'b>, + ) -> StylesheetFlusher<'a, 'b, S> where E: TElement, { @@ -202,10 +274,16 @@ where debug!("StylesheetSet::flush"); - let have_invalidations = self.invalidations.flush(document_element); - let origins = mem::replace(&mut self.origins_dirty, OriginSet::empty()); + let had_invalidations = self.invalidations.flush(document_element); + let origins_dirty = mem::replace(&mut self.origins_dirty, OriginSet::empty()); - (origins, have_invalidations) + StylesheetFlusher { + iter: self.entries.iter_mut(), + author_style_disabled: self.author_style_disabled, + had_invalidations, + origins_dirty, + guard, + } } /// Flush stylesheets, but without running any of the invalidation passes. diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 38b0861c047..5205958b9b8 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -38,7 +38,7 @@ use smallvec::VecLike; use std::fmt::Debug; use std::ops; use style_traits::viewport::ViewportConstraints; -use stylesheet_set::{StylesheetSet, StylesheetIterator}; +use stylesheet_set::{StylesheetSet, StylesheetIterator, StylesheetFlusher}; #[cfg(feature = "gecko")] use stylesheets::{CounterStyleRule, FontFaceRule}; use stylesheets::{CssRule, StyleRule}; @@ -83,22 +83,22 @@ impl DocumentCascadeData { /// Rebuild the cascade data for the given document stylesheets, and /// optionally with a set of user agent stylesheets. - fn rebuild<'a, I, S>( + fn rebuild<'a, 'b, S>( &mut self, device: &Device, quirks_mode: QuirksMode, - doc_stylesheets: I, + flusher: StylesheetFlusher<'a, 'b, S>, guards: &StylesheetGuards, ua_stylesheets: Option<&UserAgentStylesheets>, - author_style_disabled: bool, extra_data: &mut PerOrigin, - origins_to_rebuild: OriginSet, ) where - I: Iterator + Clone, - S: StylesheetInDocument + ToMediaListKey + 'static, + 'b: 'a, + S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static, { - debug_assert!(!origins_to_rebuild.is_empty()); + debug_assert!(!flusher.nothing_to_do()); + + let origins_to_rebuild = flusher.origins_to_fully_rebuild(); for origin in origins_to_rebuild.iter() { extra_data.borrow_mut_for_origin(&origin).clear(); @@ -146,22 +146,13 @@ impl DocumentCascadeData { quirks_mode, &ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user, - extra_data + extra_data, ); } } } - // Only add stylesheets for origins we are updating, and only add - // Author level sheets if author style is not disabled. - let sheets_to_add = doc_stylesheets.filter(|s| { - let sheet_origin = s.contents(guards.author).origin; - - origins_to_rebuild.contains(sheet_origin.into()) && - (!matches!(sheet_origin, Origin::Author) || !author_style_disabled) - }); - - for stylesheet in sheets_to_add { + for (stylesheet, _rebuild_kind) in flusher { self.add_stylesheet( device, quirks_mode, @@ -489,16 +480,6 @@ impl Stylist { return false; } - let author_style_disabled = self.stylesheets.author_style_disabled(); - let (origins_to_rebuild, have_invalidations) = - self.stylesheets.flush(document_element); - - if origins_to_rebuild.is_empty() { - return have_invalidations; - } - - let doc_stylesheets = self.stylesheets.iter(); - self.num_rebuilds += 1; // Update viewport_constraints regardless of which origins' @@ -517,7 +498,9 @@ impl Stylist { // queries defined?) let cascaded_rule = ViewportRule { declarations: viewport_rule::Cascade::from_stylesheets( - doc_stylesheets.clone(), guards.author, &self.device + self.stylesheets.iter(), + guards.author, + &self.device, ).finish() }; @@ -533,18 +516,20 @@ impl Stylist { } } + let flusher = self.stylesheets.flush(document_element, &guards.author); + + let had_invalidations = flusher.had_invalidations(); + self.cascade_data.rebuild( &self.device, self.quirks_mode, - doc_stylesheets, + flusher, guards, ua_sheets, - author_style_disabled, extra_data, - origins_to_rebuild, ); - have_invalidations + had_invalidations } /// Insert a given stylesheet before another stylesheet in the document.