aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/stylesheet_set.rs
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2017-08-22 17:03:46 +0200
committerEmilio Cobos Álvarez <emilio@crisal.io>2017-08-23 11:06:42 +0200
commitbf45a207602d368874035bc929e55f2df0c72036 (patch)
tree2e87597bd5efc706fc22c1490aa301326f2792c4 /components/style/stylesheet_set.rs
parent1c67a7dc14b8b046d1b5c05e21cd7dc63a3aba32 (diff)
downloadservo-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.rs116
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);
+ }
}
}