mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
style: Invalidate for CSSOM changes in a more fine-grained way.
Also, for changes in CSS declarations, like changing cssRules[i].style.color or something, we end up avoiding a lot of the work we were doing. This page still trips us in the sense that they add a stylesheet, then call getBoundingClientRect(), then insert more rules in the stylesheet, which causes us to rebuild a lot of the cascade data. We could try to detect appends to the last stylesheet on the list or something I guess, and avoid rebuilding the cascade data in some cases. Depends on D85615 Differential Revision: https://phabricator.services.mozilla.com/D85616
This commit is contained in:
parent
dfa715a8d8
commit
ca7e1ecfd8
6 changed files with 273 additions and 74 deletions
|
@ -16,10 +16,26 @@ use crate::selector_map::{MaybeCaseInsensitiveHashMap, PrecomputedHashMap};
|
|||
use crate::selector_parser::{SelectorImpl, Snapshot, SnapshotMap};
|
||||
use crate::shared_lock::SharedRwLockReadGuard;
|
||||
use crate::stylesheets::{CssRule, StylesheetInDocument};
|
||||
use crate::stylesheets::{EffectiveRules, EffectiveRulesIterator};
|
||||
use crate::Atom;
|
||||
use crate::LocalName as SelectorLocalName;
|
||||
use selectors::parser::{Component, LocalName, Selector};
|
||||
|
||||
/// The kind of change that happened for a given rule.
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
||||
pub enum RuleChangeKind {
|
||||
/// The rule was inserted.
|
||||
Insertion,
|
||||
/// The rule was removed.
|
||||
Removal,
|
||||
/// Some change in the rule which we don't know about, and could have made
|
||||
/// the rule change in any way.
|
||||
Generic,
|
||||
/// A change in the declarations of a style rule.
|
||||
StyleRuleDeclarations,
|
||||
}
|
||||
|
||||
/// A style sheet invalidation represents a kind of element or subtree that may
|
||||
/// need to be restyled. Whether it represents a whole subtree or just a single
|
||||
/// element is determined by the given InvalidationKind in
|
||||
|
@ -162,7 +178,8 @@ impl StylesheetInvalidationSet {
|
|||
have_invalidations
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
/// Returns whether there's no invalidation to process.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!self.fully_invalid &&
|
||||
self.classes.is_empty() &&
|
||||
self.ids.is_empty() &&
|
||||
|
@ -484,6 +501,75 @@ impl StylesheetInvalidationSet {
|
|||
true
|
||||
}
|
||||
|
||||
/// Collects invalidations for a given CSS rule, if not fully invalid
|
||||
/// already.
|
||||
///
|
||||
/// TODO(emilio): we can't check whether the rule is inside a non-effective
|
||||
/// subtree, we potentially could do that.
|
||||
pub fn rule_changed<S>(
|
||||
&mut self,
|
||||
stylesheet: &S,
|
||||
rule: &CssRule,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
device: &Device,
|
||||
quirks_mode: QuirksMode,
|
||||
change_kind: RuleChangeKind,
|
||||
) where
|
||||
S: StylesheetInDocument,
|
||||
{
|
||||
use crate::stylesheets::CssRule::*;
|
||||
|
||||
debug!("StylesheetInvalidationSet::rule_changed");
|
||||
if self.fully_invalid {
|
||||
return;
|
||||
}
|
||||
|
||||
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
|
||||
debug!(" > Stylesheet was not effective");
|
||||
return; // Nothing to do here.
|
||||
}
|
||||
|
||||
let is_generic_change = change_kind == RuleChangeKind::Generic;
|
||||
|
||||
match *rule {
|
||||
Namespace(..) => {
|
||||
// It's not clear what handling changes for this correctly would
|
||||
// look like.
|
||||
},
|
||||
CounterStyle(..) |
|
||||
Page(..) |
|
||||
Viewport(..) |
|
||||
FontFeatureValues(..) |
|
||||
FontFace(..) |
|
||||
Keyframes(..) |
|
||||
Style(..) => {
|
||||
if is_generic_change {
|
||||
// TODO(emilio): We need to do this for selector / keyframe
|
||||
// name / font-face changes, because we don't have the old
|
||||
// selector / name. If we distinguish those changes
|
||||
// specially, then we can at least use this invalidation for
|
||||
// style declaration changes.
|
||||
return self.invalidate_fully();
|
||||
}
|
||||
|
||||
self.collect_invalidations_for_rule(rule, guard, device, quirks_mode)
|
||||
},
|
||||
Document(..) | Import(..) | Media(..) | Supports(..) => {
|
||||
if !is_generic_change &&
|
||||
!EffectiveRules::is_effective(guard, device, quirks_mode, rule)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let rules =
|
||||
EffectiveRulesIterator::effective_children(device, quirks_mode, guard, rule);
|
||||
for rule in rules {
|
||||
self.collect_invalidations_for_rule(rule, guard, device, quirks_mode)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects invalidations for a given CSS rule.
|
||||
fn collect_invalidations_for_rule(
|
||||
&mut self,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue