diff options
author | Delan Azabani <dazabani@igalia.com> | 2024-02-27 23:39:06 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-27 15:39:06 +0000 |
commit | faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch) | |
tree | 4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/stylesheet_set.rs | |
parent | b07505417e629bbb081be9683630f2d7a5f50544 (diff) | |
download | servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.tar.gz servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.zip |
Move Stylo to its own repo (#31350)
* Remove packages that were moved to external repo
* Add workspace dependencies pointing to 2023-06-14 branch
* Fix servo-tidy.toml errors
* Update commit to include #31346
* Update commit to include servo/stylo#2
* Move css-properties.json lookup to target/doc/stylo
* Remove dependency on vendored mako in favour of pypi dependency
This also removes etc/ci/generate_workflow.py, which has been unused
since at least 9e71bd6a7010d6e5723831696ae0ebe26b47682f.
* Add temporary code to debug Windows test failures
* Fix failures on Windows due to custom target dir
* Update commit to include servo/stylo#3
* Fix license in tests/unit/style/build.rs
* Document how to build with local Stylo in Cargo.toml
Diffstat (limited to 'components/style/stylesheet_set.rs')
-rw-r--r-- | components/style/stylesheet_set.rs | 705 |
1 files changed, 0 insertions, 705 deletions
diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs deleted file mode 100644 index e2937e06e75..00000000000 --- a/components/style/stylesheet_set.rs +++ /dev/null @@ -1,705 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -//! A centralized set of stylesheets for a document. - -use crate::dom::TElement; -use crate::invalidation::stylesheets::{RuleChangeKind, StylesheetInvalidationSet}; -use crate::media_queries::Device; -use crate::selector_parser::SnapshotMap; -use crate::shared_lock::SharedRwLockReadGuard; -use crate::stylesheets::{ - CssRule, Origin, OriginSet, OriginSetIterator, PerOrigin, StylesheetInDocument, -}; -use std::{mem, slice}; - -/// Entry for a StylesheetSet. -#[derive(MallocSizeOf)] -struct StylesheetSetEntry<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// The sheet. - sheet: S, - - /// Whether this sheet has been part of at least one flush. - committed: bool, -} - -impl<S> StylesheetSetEntry<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - fn new(sheet: S) -> Self { - Self { - sheet, - committed: false, - } - } -} - -/// A iterator over the stylesheets of a list of entries in the StylesheetSet. -pub struct StylesheetCollectionIterator<'a, S>(slice::Iter<'a, StylesheetSetEntry<S>>) -where - S: StylesheetInDocument + PartialEq + 'static; - -impl<'a, S> Clone for StylesheetCollectionIterator<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - fn clone(&self) -> Self { - StylesheetCollectionIterator(self.0.clone()) - } -} - -impl<'a, S> Iterator for StylesheetCollectionIterator<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - type Item = &'a S; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().map(|entry| &entry.sheet) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - self.0.size_hint() - } -} - -/// An iterator over the flattened view of the stylesheet collections. -#[derive(Clone)] -pub struct StylesheetIterator<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - origins: OriginSetIterator, - collections: &'a PerOrigin<SheetCollection<S>>, - current: Option<(Origin, StylesheetCollectionIterator<'a, S>)>, -} - -impl<'a, S> Iterator for StylesheetIterator<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - type Item = (&'a S, Origin); - - fn next(&mut self) -> Option<Self::Item> { - loop { - if self.current.is_none() { - let next_origin = self.origins.next()?; - - self.current = Some(( - next_origin, - self.collections.borrow_for_origin(&next_origin).iter(), - )); - } - - { - let (origin, ref mut iter) = *self.current.as_mut().unwrap(); - if let Some(s) = iter.next() { - return Some((s, origin)); - } - } - - self.current = None; - } - } -} - -/// The validity of the data in a given cascade origin. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd)] -pub enum DataValidity { - /// 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 DataValidity { - fn default() -> Self { - DataValidity::Valid - } -} - -/// A struct to iterate over the different stylesheets to be flushed. -pub struct DocumentStylesheetFlusher<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - collections: &'a mut PerOrigin<SheetCollection<S>>, - had_invalidations: bool, -} - -/// The type of rebuild that we need to do for a given stylesheet. -#[derive(Clone, Copy, Debug)] -pub enum SheetRebuildKind { - /// 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 should_rebuild_invalidation(&self) -> bool { - matches!(*self, SheetRebuildKind::Full) - } -} - -impl<'a, S> DocumentStylesheetFlusher<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Returns a flusher for `origin`. - pub fn flush_origin(&mut self, origin: Origin) -> SheetCollectionFlusher<S> { - self.collections.borrow_mut_for_origin(&origin).flush() - } - - /// 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 collection, that takes care of returning the -/// appropriate stylesheets that need work. -pub struct SheetCollectionFlusher<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - // TODO: This can be made an iterator again once - // https://github.com/rust-lang/rust/pull/82771 lands on stable. - entries: &'a mut [StylesheetSetEntry<S>], - validity: DataValidity, - dirty: bool, -} - -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 - } - - /// Returns an iterator over the remaining list of sheets to consume. - pub fn sheets<'b>(&'b self) -> impl Iterator<Item = &'b S> { - self.entries.iter().map(|entry| &entry.sheet) - } -} - -impl<'a, S> SheetCollectionFlusher<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Iterates over all sheets and values that we have to invalidate. - /// - /// TODO(emilio): This would be nicer as an iterator but we can't do that - /// until https://github.com/rust-lang/rust/pull/82771 stabilizes. - /// - /// Since we don't have a good use-case for partial iteration, this does the - /// trick for now. - pub fn each(self, mut callback: impl FnMut(&S, SheetRebuildKind) -> bool) { - for potential_sheet in self.entries.iter_mut() { - let committed = mem::replace(&mut potential_sheet.committed, true); - let rebuild_kind = if !committed { - // If the sheet was uncommitted, we need to do a full rebuild - // anyway. - SheetRebuildKind::Full - } else { - match self.validity { - DataValidity::Valid => continue, - DataValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly, - DataValidity::FullyInvalid => SheetRebuildKind::Full, - } - }; - - if !callback(&potential_sheet.sheet, rebuild_kind) { - return; - } - } - } -} - -#[derive(MallocSizeOf)] -struct SheetCollection<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// The actual list of stylesheets. - /// - /// This is only a list of top-level stylesheets, and as such it doesn't - /// include recursive `@import` rules. - entries: Vec<StylesheetSetEntry<S>>, - - /// 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 - /// `DataValidity::Valid`, if only sheets have been appended into it (in - /// which case the existing data is valid, but the origin needs to be - /// rebuilt). - data_validity: DataValidity, - - /// Whether anything in the collection has changed. Note that this is - /// different from `data_validity`, in the sense that after a sheet append, - /// the data validity is still `Valid`, but we need to be marked as dirty. - dirty: bool, -} - -impl<S> Default for SheetCollection<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - fn default() -> Self { - Self { - entries: vec![], - data_validity: DataValidity::Valid, - dirty: false, - } - } -} - -impl<S> SheetCollection<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Returns the number of stylesheets in the set. - fn len(&self) -> usize { - self.entries.len() - } - - /// Returns the `index`th stylesheet in the set if present. - fn get(&self, index: usize) -> Option<&S> { - self.entries.get(index).map(|e| &e.sheet) - } - - fn remove(&mut self, sheet: &S) { - let index = self.entries.iter().position(|entry| entry.sheet == *sheet); - if cfg!(feature = "gecko") && index.is_none() { - // FIXME(emilio): Make Gecko's PresShell::AddUserSheet not suck. - return; - } - let sheet = self.entries.remove(index.unwrap()); - // Removing sheets makes us tear down the whole cascade and invalidation - // data, but only if the sheet has been involved in at least one flush. - // Checking whether the sheet has been committed allows us to avoid - // rebuilding the world when sites quickly append and remove a - // stylesheet. - // - // See bug 1434756. - if sheet.committed { - self.set_data_validity_at_least(DataValidity::FullyInvalid); - } else { - self.dirty = true; - } - } - - fn contains(&self, sheet: &S) -> bool { - self.entries.iter().any(|e| e.sheet == *sheet) - } - - /// Appends a given sheet into the collection. - fn append(&mut self, sheet: S) { - debug_assert!(!self.contains(&sheet)); - self.entries.push(StylesheetSetEntry::new(sheet)); - // Appending sheets doesn't alter the validity of the existing data, so - // we don't need to change `data_validity` here. - // - // But we need to be marked as dirty, otherwise we'll never add the new - // sheet! - self.dirty = true; - } - - fn insert_before(&mut self, sheet: S, before_sheet: &S) { - debug_assert!(!self.contains(&sheet)); - - let index = self - .entries - .iter() - .position(|entry| entry.sheet == *before_sheet) - .expect("`before_sheet` stylesheet not found"); - - // 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(DataValidity::CascadeInvalid); - self.entries.insert(index, StylesheetSetEntry::new(sheet)); - } - - fn set_data_validity_at_least(&mut self, validity: DataValidity) { - use std::cmp; - - debug_assert_ne!(validity, DataValidity::Valid); - - self.dirty = true; - self.data_validity = cmp::max(validity, self.data_validity); - } - - /// Returns an iterator over the current list of stylesheets. - 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 { - entries: &mut self.entries, - dirty, - validity, - } - } -} - -/// The set of stylesheets effective for a given document. -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub struct DocumentStylesheetSet<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// The collections of sheets per each origin. - collections: PerOrigin<SheetCollection<S>>, - - /// The invalidations for stylesheets added or removed from this document. - invalidations: StylesheetInvalidationSet, -} - -/// This macro defines methods common to DocumentStylesheetSet and -/// AuthorStylesheetSet. -/// -/// We could simplify the setup moving invalidations to SheetCollection, but -/// that would imply not sharing invalidations across origins of the same -/// documents, which is slightly annoying. -macro_rules! sheet_set_methods { - ($set_name:expr) => { - fn collect_invalidations_for( - &mut self, - device: Option<&Device>, - sheet: &S, - guard: &SharedRwLockReadGuard, - ) { - if let Some(device) = device { - self.invalidations - .collect_invalidations_for(device, sheet, guard); - } - } - - /// Appends a new stylesheet to the current set. - /// - /// No device implies not computing invalidations. - pub fn append_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::append_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); - let collection = self.collection_for(&sheet); - collection.append(sheet); - } - - /// Insert a given stylesheet before another stylesheet in the document. - pub fn insert_stylesheet_before( - &mut self, - device: Option<&Device>, - sheet: S, - before_sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::insert_stylesheet_before")); - self.collect_invalidations_for(device, &sheet, guard); - - let collection = self.collection_for(&sheet); - collection.insert_before(sheet, &before_sheet); - } - - /// Remove a given stylesheet from the set. - pub fn remove_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::remove_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); - - let collection = self.collection_for(&sheet); - collection.remove(&sheet) - } - - /// Notify the set that a rule from a given stylesheet has changed - /// somehow. - pub fn rule_changed( - &mut self, - device: Option<&Device>, - sheet: &S, - rule: &CssRule, - guard: &SharedRwLockReadGuard, - change_kind: RuleChangeKind, - ) { - if let Some(device) = device { - let quirks_mode = device.quirks_mode(); - self.invalidations.rule_changed( - sheet, - rule, - guard, - device, - quirks_mode, - change_kind, - ); - } - - let validity = match change_kind { - // Insertion / Removals need to rebuild both the cascade and - // invalidation data. For generic changes this is conservative, - // could be optimized on a per-case basis. - RuleChangeKind::Generic | RuleChangeKind::Insertion | RuleChangeKind::Removal => { - DataValidity::FullyInvalid - }, - // TODO(emilio): This, in theory, doesn't need to invalidate - // style data, if the rule we're modifying is actually in the - // CascadeData already. - // - // But this is actually a bit tricky to prove, because when we - // copy-on-write a stylesheet we don't bother doing a rebuild, - // so we may still have rules from the original stylesheet - // instead of the cloned one that we're modifying. So don't - // bother for now and unconditionally rebuild, it's no worse - // than what we were already doing anyway. - // - // Maybe we could record whether we saw a clone in this flush, - // and if so do the conservative thing, otherwise just - // early-return. - RuleChangeKind::StyleRuleDeclarations => DataValidity::FullyInvalid, - }; - - let collection = self.collection_for(&sheet); - collection.set_data_validity_at_least(validity); - } - }; -} - -impl<S> DocumentStylesheetSet<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Create a new empty DocumentStylesheetSet. - pub fn new() -> Self { - Self { - collections: Default::default(), - invalidations: StylesheetInvalidationSet::new(), - } - } - - fn collection_for(&mut self, sheet: &S) -> &mut SheetCollection<S> { - let origin = sheet.contents().origin; - self.collections.borrow_mut_for_origin(&origin) - } - - sheet_set_methods!("DocumentStylesheetSet"); - - /// Returns the number of stylesheets in the set. - pub fn len(&self) -> usize { - self.collections - .iter_origins() - .fold(0, |s, (item, _)| s + item.len()) - } - - /// Returns the count of stylesheets for a given origin. - #[inline] - pub fn sheet_count(&self, origin: Origin) -> usize { - self.collections.borrow_for_origin(&origin).len() - } - - /// Returns the `index`th stylesheet in the set for the given origin. - #[inline] - pub fn get(&self, origin: Origin, index: usize) -> Option<&S> { - self.collections.borrow_for_origin(&origin).get(index) - } - - /// Returns whether the given set has changed from the last flush. - pub fn has_changed(&self) -> bool { - !self.invalidations.is_empty() || - self.collections - .iter_origins() - .any(|(collection, _)| collection.dirty) - } - - /// Flush the current set, unmarking it as dirty, and returns a - /// `DocumentStylesheetFlusher` in order to rebuild the stylist. - pub fn flush<E>( - &mut self, - document_element: Option<E>, - snapshots: Option<&SnapshotMap>, - ) -> DocumentStylesheetFlusher<S> - where - E: TElement, - { - debug!("DocumentStylesheetSet::flush"); - - let had_invalidations = self.invalidations.flush(document_element, snapshots); - - DocumentStylesheetFlusher { - collections: &mut self.collections, - had_invalidations, - } - } - - /// Flush stylesheets, but without running any of the invalidation passes. - #[cfg(feature = "servo")] - pub fn flush_without_invalidation(&mut self) -> OriginSet { - debug!("DocumentStylesheetSet::flush_without_invalidation"); - - let mut origins = OriginSet::empty(); - self.invalidations.clear(); - - for (collection, origin) in self.collections.iter_mut_origins() { - 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 { - origins: OriginSet::all().iter(), - collections: &self.collections, - current: None, - } - } - - /// Mark the stylesheets for the specified origin as dirty, because - /// something external may have invalidated it. - pub fn force_dirty(&mut self, origins: OriginSet) { - self.invalidations.invalidate_fully(); - for origin in origins.iter() { - // We don't know what happened, assume the worse. - self.collections - .borrow_mut_for_origin(&origin) - .set_data_validity_at_least(DataValidity::FullyInvalid); - } - } -} - -/// The set of stylesheets effective for a given Shadow Root. -#[derive(MallocSizeOf)] -pub struct AuthorStylesheetSet<S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// The actual style sheets. - collection: SheetCollection<S>, - /// The set of invalidations scheduled for this collection. - 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, -{ - /// Create a new empty AuthorStylesheetSet. - #[inline] - pub fn new() -> Self { - Self { - collection: Default::default(), - invalidations: StylesheetInvalidationSet::new(), - } - } - - /// Whether anything has changed since the last time this was flushed. - pub fn dirty(&self) -> bool { - self.collection.dirty - } - - /// Whether the collection is empty. - pub fn is_empty(&self) -> bool { - self.collection.len() == 0 - } - - /// Returns the `index`th stylesheet in the collection of author styles if present. - pub fn get(&self, index: usize) -> Option<&S> { - self.collection.get(index) - } - - /// Returns the number of author stylesheets. - pub fn len(&self) -> usize { - self.collection.len() - } - - fn collection_for(&mut self, _sheet: &S) -> &mut SheetCollection<S> { - &mut self.collection - } - - sheet_set_methods!("AuthorStylesheetSet"); - - /// Iterate over the list of stylesheets. - pub fn iter(&self) -> StylesheetCollectionIterator<S> { - self.collection.iter() - } - - /// Mark the sheet set dirty, as appropriate. - pub fn force_dirty(&mut self) { - self.invalidations.invalidate_fully(); - self.collection - .set_data_validity_at_least(DataValidity::FullyInvalid); - } - - /// 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, - } - } -} |