diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-08-22 17:03:46 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-08-23 11:06:42 +0200 |
commit | bf45a207602d368874035bc929e55f2df0c72036 (patch) | |
tree | 2e87597bd5efc706fc22c1490aa301326f2792c4 /components/style/stylesheet_set.rs | |
parent | 1c67a7dc14b8b046d1b5c05e21cd7dc63a3aba32 (diff) | |
download | servo-bf45a207602d368874035bc929e55f2df0c72036.tar.gz servo-bf45a207602d368874035bc929e55f2df0c72036.zip |
style: Implement finer-grained stylist rebuilds.
MozReview-Commit-ID: ALsH9kSqHb0
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
Diffstat (limited to 'components/style/stylesheet_set.rs')
-rw-r--r-- | components/style/stylesheet_set.rs | 116 |
1 files changed, 106 insertions, 10 deletions
diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 104ada57783..98abfbbb1c7 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -9,7 +9,7 @@ use invalidation::stylesheets::StylesheetInvalidationSet; use media_queries::Device; use shared_lock::SharedRwLockReadGuard; use std::slice; -use stylesheets::{Origin, OriginSet, StylesheetInDocument}; +use stylesheets::{Origin, OriginSet, PerOrigin, StylesheetInDocument}; /// Entry for a StylesheetSet. We don't bother creating a constructor, because /// there's no sensible defaults for the member variables. @@ -19,6 +19,7 @@ where S: StylesheetInDocument + PartialEq + 'static, { sheet: S, + dirty: bool, } impl<S> StylesheetSetEntry<S> @@ -26,7 +27,7 @@ where S: StylesheetInDocument + PartialEq + 'static, { fn new(sheet: S) -> Self { - Self { sheet } + Self { sheet, dirty: true } } } @@ -47,6 +48,28 @@ where } } +/// The validity of the data in a given cascade origin. +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum OriginValidity { + /// The origin is clean, all the data already there is valid, though we may + /// have new sheets at the end. + Valid = 0, + + /// The cascade data is invalid, but not the invalidation data (which is + /// order-independent), and thus only the cascade data should be inserted. + CascadeInvalid = 1, + + /// Everything needs to be rebuilt. + FullyInvalid = 2, +} + +impl Default for OriginValidity { + fn default() -> Self { + OriginValidity::Valid + } +} + /// A struct to iterate over the different stylesheets to be flushed. pub struct StylesheetFlusher<'a, 'b, S> where @@ -56,15 +79,24 @@ where iter: slice::IterMut<'a, StylesheetSetEntry<S>>, guard: &'a SharedRwLockReadGuard<'b>, origins_dirty: OriginSet, + origin_data_validity: PerOrigin<OriginValidity>, 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. + /// A full rebuild, of both cascade data and invalidation data. Full, + /// A partial rebuild, of only the cascade data. + CascadeOnly, +} + +impl SheetRebuildKind { + /// Whether the stylesheet invalidation data should be rebuilt. + pub fn rebuild_invalidation(&self) -> bool { + matches!(*self, SheetRebuildKind::Full) + } } impl<'a, 'b, S> StylesheetFlusher<'a, 'b, S> @@ -72,10 +104,9 @@ 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 + /// The data validity for a given origin. + pub fn origin_validity(&self, origin: Origin) -> OriginValidity { + *self.origin_data_validity.borrow_for_origin(&origin) } /// Returns whether running the whole flushing process would be a no-op. @@ -99,7 +130,7 @@ where fn drop(&mut self) { debug_assert!( self.iter.next().is_none(), - "You're supposed to fully consume the flusher", + "You're supposed to fully consume the flusher" ); } } @@ -112,12 +143,21 @@ where type Item = (&'a S, SheetRebuildKind); fn next(&mut self) -> Option<Self::Item> { + use std::mem; + loop { let potential_sheet = match self.iter.next() { None => return None, Some(s) => s, }; + let dirty = mem::replace(&mut potential_sheet.dirty, false); + + if dirty { + // If the sheet was dirty, we need to do a full rebuild anyway. + return Some((&potential_sheet.sheet, SheetRebuildKind::Full)) + } + let origin = potential_sheet.sheet.contents(self.guard).origin; if !self.origins_dirty.contains(origin.into()) { continue; @@ -127,7 +167,13 @@ where continue; } - return Some((&potential_sheet.sheet, SheetRebuildKind::Full)) + let rebuild_kind = match self.origin_validity(origin) { + OriginValidity::Valid => continue, + OriginValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly, + OriginValidity::FullyInvalid => SheetRebuildKind::Full, + }; + + return Some((&potential_sheet.sheet, rebuild_kind)); } } } @@ -151,6 +197,14 @@ where /// The origins whose stylesheets have changed so far. origins_dirty: OriginSet, + /// The validity of the data that was already there for a given origin. + /// + /// Note that an origin may appear on `origins_dirty`, but still have + /// `OriginValidity::Valid`, if only sheets have been appended into it (in + /// which case the existing data is valid, but the origin needs to be + /// rebuilt). + origin_data_validity: PerOrigin<OriginValidity>, + /// Has author style been disabled? author_style_disabled: bool, } @@ -165,6 +219,7 @@ where entries: vec![], invalidations: StylesheetInvalidationSet::new(), origins_dirty: OriginSet::empty(), + origin_data_validity: Default::default(), author_style_disabled: false, } } @@ -201,6 +256,24 @@ where self.origins_dirty |= sheet.contents(guard).origin; } + fn set_data_validity_at_least( + &mut self, + origin: Origin, + validity: OriginValidity, + ) { + use std::cmp; + + debug_assert!( + self.origins_dirty.contains(origin.into()), + "data_validity should be a subset of origins_dirty" + ); + + let existing_validity = + self.origin_data_validity.borrow_mut_for_origin(&origin); + + *existing_validity = cmp::max(*existing_validity, validity); + } + /// Appends a new stylesheet to the current set. /// /// No device implies not computing invalidations. @@ -213,6 +286,8 @@ where debug!("StylesheetSet::append_stylesheet"); self.remove_stylesheet_if_present(&sheet); self.collect_invalidations_for(device, &sheet, guard); + // Appending sheets doesn't alter the validity of the existing data, so + // we don't need to change `origin_data_validity` here. self.entries.push(StylesheetSetEntry::new(sheet)); } @@ -226,6 +301,11 @@ where debug!("StylesheetSet::prepend_stylesheet"); self.remove_stylesheet_if_present(&sheet); self.collect_invalidations_for(device, &sheet, guard); + + // Inserting stylesheets somewhere but at the end changes the validity + // of the cascade data, but not the invalidation data. + self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid); + self.entries.insert(0, StylesheetSetEntry::new(sheet)); } @@ -243,6 +323,10 @@ where entry.sheet == before_sheet }).expect("`before_sheet` stylesheet not found"); self.collect_invalidations_for(device, &sheet, guard); + + // Inserting stylesheets somewhere but at the end changes the validity + // of the cascade data, but not the invalidation data. + self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid); self.entries.insert(index, StylesheetSetEntry::new(sheet)); } @@ -255,7 +339,12 @@ where ) { debug!("StylesheetSet::remove_stylesheet"); self.remove_stylesheet_if_present(&sheet); + self.collect_invalidations_for(device, &sheet, guard); + + // Removing sheets makes us tear down the whole cascade and invalidation + // data. + self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::FullyInvalid); } /// Notes that the author style has been disabled for this document. @@ -290,12 +379,15 @@ where let had_invalidations = self.invalidations.flush(document_element); let origins_dirty = mem::replace(&mut self.origins_dirty, OriginSet::empty()); + let origin_data_validity = + mem::replace(&mut self.origin_data_validity, Default::default()); StylesheetFlusher { iter: self.entries.iter_mut(), author_style_disabled: self.author_style_disabled, had_invalidations, origins_dirty, + origin_data_validity, guard, } } @@ -321,5 +413,9 @@ where pub fn force_dirty(&mut self, origins: OriginSet) { self.invalidations.invalidate_fully(); self.origins_dirty |= origins; + for origin in origins.iter() { + // We don't know what happened, assume the worse. + self.set_data_validity_at_least(origin, OriginValidity::FullyInvalid); + } } } |