mirror of
https://github.com/servo/servo.git
synced 2025-08-01 19:50:30 +01:00
style: Move more stuff to the place it belongs to.
In particular, `rebuild` is now done entirely by CascadeData, which simplifies more stuff. The eventual final state for this is that the data structure we use to store the XBL / Shadow DOM stuff will be something like: struct AuthorStyles { CascadeData, AuthorSheetCollection } MozReview-Commit-ID: 8TExtP58L4X
This commit is contained in:
parent
7edd25890d
commit
88cc2798c4
2 changed files with 139 additions and 148 deletions
|
@ -9,7 +9,7 @@ use invalidation::stylesheets::StylesheetInvalidationSet;
|
|||
use media_queries::Device;
|
||||
use selector_parser::SnapshotMap;
|
||||
use shared_lock::SharedRwLockReadGuard;
|
||||
use std::slice;
|
||||
use std::{mem, slice};
|
||||
use stylesheets::{Origin, OriginSet, OriginSetIterator, PerOrigin, StylesheetInDocument};
|
||||
|
||||
/// Entry for a StylesheetSet.
|
||||
|
@ -125,13 +125,11 @@ impl Default for DataValidity {
|
|||
}
|
||||
|
||||
/// A struct to iterate over the different stylesheets to be flushed.
|
||||
pub struct StylesheetFlusher<'a, S>
|
||||
pub struct DocumentStylesheetFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
origins_dirty: OriginSet,
|
||||
collections: &'a mut PerOrigin<SheetCollection<S>>,
|
||||
origin_data_validity: PerOrigin<DataValidity>,
|
||||
had_invalidations: bool,
|
||||
}
|
||||
|
||||
|
@ -151,82 +149,59 @@ impl SheetRebuildKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, S> StylesheetFlusher<'a, S>
|
||||
impl<'a, S> DocumentStylesheetFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
/// The data validity for a given origin.
|
||||
pub fn data_validity(&self, origin: Origin) -> DataValidity {
|
||||
*self.origin_data_validity.borrow_for_origin(&origin)
|
||||
/// Returns a flusher for `origin`.
|
||||
pub fn flush_origin(&mut self, origin: Origin) -> SheetCollectionFlusher<S> {
|
||||
self.collections.borrow_mut_for_origin(&origin).flush()
|
||||
}
|
||||
|
||||
/// Whether the origin data is dirty in any way.
|
||||
pub fn origin_dirty(&self, origin: Origin) -> bool {
|
||||
self.origins_dirty.contains(origin.into())
|
||||
}
|
||||
|
||||
/// Returns an iterator over the stylesheets of a given origin, assuming all
|
||||
/// of them will be flushed.
|
||||
pub fn manual_origin_sheets<'b>(&'b mut self, origin: Origin) -> StylesheetCollectionIterator<'b, S>
|
||||
where
|
||||
'a: 'b
|
||||
{
|
||||
debug_assert_eq!(origin, Origin::UserAgent);
|
||||
|
||||
// We could iterate over `origin_sheets(origin)` to ensure state is
|
||||
// consistent (that the `committed` member of the Entry is reset to
|
||||
// `true`).
|
||||
//
|
||||
// In practice it doesn't matter for correctness given our use of it
|
||||
// (that this is UA only).
|
||||
//
|
||||
// FIXME(emilio): I think it does matter and that we effectively don't
|
||||
// support removing UA sheets since #19927...
|
||||
self.collections.borrow_for_origin(&origin).iter()
|
||||
}
|
||||
|
||||
/// Returns a flusher for the dirty origin `origin`.
|
||||
pub fn origin_sheets<'b>(&'b mut self, origin: Origin) -> PerOriginFlusher<'b, S>
|
||||
where
|
||||
'a: 'b
|
||||
{
|
||||
let validity = self.data_validity(origin);
|
||||
let origin_dirty = self.origins_dirty.contains(origin.into());
|
||||
|
||||
debug_assert!(
|
||||
origin_dirty || validity == DataValidity::Valid,
|
||||
"origin_data_validity should be a subset of origins_dirty!"
|
||||
);
|
||||
|
||||
PerOriginFlusher {
|
||||
iter: self.collections.borrow_mut_for_origin(&origin).entries.iter_mut(),
|
||||
validity,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 the list of stylesheets for `origin`.
|
||||
///
|
||||
/// Only used for UA sheets.
|
||||
pub fn origin_sheets(&mut self, origin: Origin) -> StylesheetCollectionIterator<S> {
|
||||
self.collections.borrow_mut_for_origin(&origin).iter()
|
||||
}
|
||||
|
||||
/// Returns whether any DOM invalidations were processed as a result of the
|
||||
/// stylesheet flush.
|
||||
#[inline]
|
||||
pub fn had_invalidations(&self) -> bool {
|
||||
self.had_invalidations
|
||||
}
|
||||
}
|
||||
|
||||
/// A flusher struct for a given origin, that takes care of returning the
|
||||
/// A flusher struct for a given collection, that takes care of returning the
|
||||
/// appropriate stylesheets that need work.
|
||||
pub struct PerOriginFlusher<'a, S>
|
||||
pub struct SheetCollectionFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static
|
||||
{
|
||||
iter: slice::IterMut<'a, StylesheetSetEntry<S>>,
|
||||
validity: DataValidity,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl<'a, S> Iterator for PerOriginFlusher<'a, S>
|
||||
impl<'a, S> SheetCollectionFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
/// Whether the collection was originally dirty.
|
||||
#[inline]
|
||||
pub fn dirty(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
|
||||
/// What the state of the sheet data is.
|
||||
#[inline]
|
||||
pub fn data_validity(&self) -> DataValidity {
|
||||
self.validity
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Iterator for SheetCollectionFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
|
@ -379,6 +354,17 @@ where
|
|||
fn iter(&self) -> StylesheetCollectionIterator<S> {
|
||||
StylesheetCollectionIterator(self.entries.iter())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> SheetCollectionFlusher<S> {
|
||||
let dirty = mem::replace(&mut self.dirty, false);
|
||||
let validity = mem::replace(&mut self.data_validity, DataValidity::Valid);
|
||||
|
||||
SheetCollectionFlusher {
|
||||
iter: self.entries.iter_mut(),
|
||||
dirty,
|
||||
validity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The set of stylesheets effective for a given document.
|
||||
|
@ -420,7 +406,7 @@ macro_rules! sheet_set_methods {
|
|||
&mut self,
|
||||
device: Option<&Device>,
|
||||
sheet: S,
|
||||
guard: &SharedRwLockReadGuard
|
||||
guard: &SharedRwLockReadGuard,
|
||||
) {
|
||||
debug!(concat!($set_name, "::append_stylesheet"));
|
||||
self.collect_invalidations_for(device, &sheet, guard);
|
||||
|
@ -433,7 +419,7 @@ macro_rules! sheet_set_methods {
|
|||
&mut self,
|
||||
device: Option<&Device>,
|
||||
sheet: S,
|
||||
guard: &SharedRwLockReadGuard
|
||||
guard: &SharedRwLockReadGuard,
|
||||
) {
|
||||
debug!(concat!($set_name, "::prepend_stylesheet"));
|
||||
self.collect_invalidations_for(device, &sheet, guard);
|
||||
|
@ -477,7 +463,7 @@ impl<S> DocumentStylesheetSet<S>
|
|||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
/// Create a new empty StylesheetSet.
|
||||
/// Create a new empty DocumentStylesheetSet.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
collections: Default::default(),
|
||||
|
@ -512,60 +498,43 @@ where
|
|||
}
|
||||
|
||||
/// Flush the current set, unmarking it as dirty, and returns a
|
||||
/// `StylesheetFlusher` in order to rebuild the stylist.
|
||||
pub fn flush<'a, E>(
|
||||
&'a mut self,
|
||||
/// `DocumentStylesheetFlusher` in order to rebuild the stylist.
|
||||
pub fn flush<E>(
|
||||
&mut self,
|
||||
document_element: Option<E>,
|
||||
snapshots: Option<&SnapshotMap>,
|
||||
) -> StylesheetFlusher<'a, S>
|
||||
) -> DocumentStylesheetFlusher<S>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
use std::mem;
|
||||
|
||||
debug!("DocumentStylesheetSet::flush");
|
||||
|
||||
let had_invalidations =
|
||||
self.invalidations.flush(document_element, snapshots);
|
||||
|
||||
let mut origins_dirty = OriginSet::empty();
|
||||
let mut origin_data_validity = PerOrigin::<DataValidity>::default();
|
||||
for (collection, origin) in self.collections.iter_mut_origins() {
|
||||
let was_dirty = mem::replace(&mut collection.dirty, false);
|
||||
if !was_dirty {
|
||||
debug_assert_eq!(collection.data_validity, DataValidity::Valid);
|
||||
continue;
|
||||
}
|
||||
|
||||
origins_dirty |= origin;
|
||||
*origin_data_validity.borrow_mut_for_origin(&origin) =
|
||||
mem::replace(&mut collection.data_validity, DataValidity::Valid);
|
||||
}
|
||||
|
||||
StylesheetFlusher {
|
||||
DocumentStylesheetFlusher {
|
||||
collections: &mut self.collections,
|
||||
had_invalidations,
|
||||
origins_dirty,
|
||||
origin_data_validity,
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush stylesheets, but without running any of the invalidation passes.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn flush_without_invalidation(&mut self) -> OriginSet {
|
||||
use std::mem;
|
||||
|
||||
debug!("DocumentStylesheetSet::flush_without_invalidation");
|
||||
|
||||
let mut origins = OriginSet::empty();
|
||||
self.invalidations.clear();
|
||||
|
||||
for (collection, origin) in self.collections.iter_mut_origins() {
|
||||
collection.dirty = false;
|
||||
// NOTE(emilio): I think this should also poke at the data validity
|
||||
// and such, but it doesn't really matter given we don't use that
|
||||
// collection for style resolution anyway.
|
||||
if collection.flush().dirty() {
|
||||
origins |= origin;
|
||||
}
|
||||
}
|
||||
|
||||
origins
|
||||
}
|
||||
|
||||
/// Return an iterator over the flattened view of all the stylesheets.
|
||||
pub fn iter(&self) -> StylesheetIterator<S> {
|
||||
StylesheetIterator {
|
||||
|
@ -599,6 +568,17 @@ where
|
|||
invalidations: StylesheetInvalidationSet,
|
||||
}
|
||||
|
||||
/// A struct to flush an author style sheet collection.
|
||||
pub struct AuthorStylesheetFlusher<'a, S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
{
|
||||
/// The actual flusher for the collection.
|
||||
pub sheets: SheetCollectionFlusher<'a, S>,
|
||||
/// Whether any sheet invalidation matched.
|
||||
pub had_invalidations: bool,
|
||||
}
|
||||
|
||||
impl<S> AuthorStylesheetSet<S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
|
@ -612,4 +592,23 @@ where
|
|||
}
|
||||
|
||||
sheet_set_methods!("AuthorStylesheetSet");
|
||||
|
||||
/// Flush the stylesheets for this author set.
|
||||
///
|
||||
/// `host` is the root of the affected subtree, like the shadow host, for
|
||||
/// example.
|
||||
pub fn flush<E>(
|
||||
&mut self,
|
||||
host: Option<E>,
|
||||
snapshots: Option<&SnapshotMap>,
|
||||
) -> AuthorStylesheetFlusher<S>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
let had_invalidations = self.invalidations.flush(host, snapshots);
|
||||
AuthorStylesheetFlusher {
|
||||
sheets: self.collection.flush(),
|
||||
had_invalidations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ use smallvec::SmallVec;
|
|||
use std::ops;
|
||||
use std::sync::Mutex;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use stylesheet_set::{DataValidity, SheetRebuildKind, DocumentStylesheetSet, StylesheetFlusher};
|
||||
use stylesheet_set::{DataValidity, SheetRebuildKind, DocumentStylesheetSet};
|
||||
use stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
|
||||
#[cfg(feature = "gecko")]
|
||||
use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule};
|
||||
use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter};
|
||||
|
@ -227,46 +228,6 @@ impl DocumentCascadeData {
|
|||
}
|
||||
}
|
||||
|
||||
fn rebuild_origin<'a, S>(
|
||||
device: &Device,
|
||||
quirks_mode: QuirksMode,
|
||||
flusher: &mut StylesheetFlusher<'a, S>,
|
||||
guards: &StylesheetGuards,
|
||||
origin: Origin,
|
||||
cascade_data: &mut CascadeData,
|
||||
) -> Result<(), FailedAllocationError>
|
||||
where
|
||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
||||
{
|
||||
debug_assert_ne!(origin, Origin::UserAgent);
|
||||
|
||||
if !flusher.origin_dirty(origin) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let validity = flusher.data_validity(origin);
|
||||
|
||||
match validity {
|
||||
DataValidity::Valid => {},
|
||||
DataValidity::CascadeInvalid => cascade_data.clear_cascade_data(),
|
||||
DataValidity::FullyInvalid => cascade_data.clear(),
|
||||
}
|
||||
|
||||
let guard = guards.for_origin(origin);
|
||||
for (stylesheet, rebuild_kind) in flusher.origin_sheets(origin) {
|
||||
cascade_data.add_stylesheet(
|
||||
device,
|
||||
quirks_mode,
|
||||
stylesheet,
|
||||
guard,
|
||||
rebuild_kind,
|
||||
/* precomputed_pseudo_element_decls = */ None,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Rebuild the cascade data for the given document stylesheets, and
|
||||
/// optionally with a set of user agent stylesheets. Returns Err(..)
|
||||
/// to signify OOM.
|
||||
|
@ -274,21 +235,17 @@ impl DocumentCascadeData {
|
|||
&mut self,
|
||||
device: &Device,
|
||||
quirks_mode: QuirksMode,
|
||||
mut flusher: StylesheetFlusher<'a, S>,
|
||||
mut flusher: DocumentStylesheetFlusher<'a, S>,
|
||||
guards: &StylesheetGuards,
|
||||
) -> Result<(), FailedAllocationError>
|
||||
where
|
||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
||||
{
|
||||
debug_assert!(!flusher.nothing_to_do());
|
||||
|
||||
// First do UA sheets.
|
||||
{
|
||||
if flusher.origin_dirty(Origin::UserAgent) {
|
||||
if flusher.flush_origin(Origin::UserAgent).dirty() {
|
||||
let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
|
||||
let origin_sheets =
|
||||
flusher.manual_origin_sheets(Origin::UserAgent);
|
||||
|
||||
let origin_sheets = flusher.origin_sheets(Origin::UserAgent);
|
||||
let ua_cascade_data = ua_cache.lookup(
|
||||
origin_sheets,
|
||||
device,
|
||||
|
@ -302,23 +259,19 @@ impl DocumentCascadeData {
|
|||
}
|
||||
|
||||
// Now do the user sheets.
|
||||
Self::rebuild_origin(
|
||||
self.user.rebuild(
|
||||
device,
|
||||
quirks_mode,
|
||||
&mut flusher,
|
||||
guards,
|
||||
Origin::User,
|
||||
&mut self.user,
|
||||
flusher.flush_origin(Origin::User),
|
||||
guards.ua_or_user,
|
||||
)?;
|
||||
|
||||
// And now the author sheets.
|
||||
Self::rebuild_origin(
|
||||
self.author.rebuild(
|
||||
device,
|
||||
quirks_mode,
|
||||
&mut flusher,
|
||||
guards,
|
||||
Origin::Author,
|
||||
&mut self.author,
|
||||
flusher.flush_origin(Origin::Author),
|
||||
guards.author,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -2048,6 +2001,45 @@ impl CascadeData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Rebuild the cascade data from a given SheetCollection, incrementally if
|
||||
/// possible.
|
||||
fn rebuild<'a, S>(
|
||||
&mut self,
|
||||
device: &Device,
|
||||
quirks_mode: QuirksMode,
|
||||
collection: SheetCollectionFlusher<S>,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
) -> Result<(), FailedAllocationError>
|
||||
where
|
||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
||||
{
|
||||
if !collection.dirty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let validity = collection.data_validity();
|
||||
|
||||
match validity {
|
||||
DataValidity::Valid => {},
|
||||
DataValidity::CascadeInvalid => self.clear_cascade_data(),
|
||||
DataValidity::FullyInvalid => self.clear(),
|
||||
}
|
||||
|
||||
for (stylesheet, rebuild_kind) in collection {
|
||||
self.add_stylesheet(
|
||||
device,
|
||||
quirks_mode,
|
||||
stylesheet,
|
||||
guard,
|
||||
rebuild_kind,
|
||||
/* precomputed_pseudo_element_decls = */ None,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Returns the invalidation map.
|
||||
pub fn invalidation_map(&self) -> &InvalidationMap {
|
||||
&self.invalidation_map
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue