mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Do a second pass on the sharing cache to reuse style by rule node identity.
MozReview-Commit-ID: H67j3Sbt3gr
This commit is contained in:
parent
7a7070e075
commit
1c9b39a8e8
6 changed files with 122 additions and 8 deletions
|
@ -22,8 +22,9 @@ use std::ops::{Deref, DerefMut};
|
|||
use style_resolver::{PrimaryStyle, ResolvedElementStyles, ResolvedStyle};
|
||||
|
||||
bitflags! {
|
||||
/// Various flags stored on ElementData.
|
||||
#[derive(Default)]
|
||||
flags ElementDataFlags: u8 {
|
||||
pub flags ElementDataFlags: u8 {
|
||||
/// Whether the styles changed for this restyle.
|
||||
const WAS_RESTYLED = 1 << 0,
|
||||
/// Whether the last traversal of this element did not do
|
||||
|
@ -37,6 +38,13 @@ bitflags! {
|
|||
const TRAVERSED_WITHOUT_STYLING = 1 << 1,
|
||||
/// Whether we reframed/reconstructed any ancestor or self.
|
||||
const ANCESTOR_WAS_RECONSTRUCTED = 1 << 2,
|
||||
/// Whether the primary style of this element data was reused from another
|
||||
/// element via a rule node comparison. This allows us to differentiate
|
||||
/// between elements that shared styles because they met all the criteria
|
||||
/// of the style sharing cache, compared to elements that reused style
|
||||
/// structs via rule node identity. The former gives us stronger transitive
|
||||
/// guarantees that allows us to apply the style sharing cache to cousins.
|
||||
const PRIMARY_STYLE_REUSED_VIA_RULE_NODE = 1 << 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +210,7 @@ pub struct ElementData {
|
|||
pub hint: RestyleHint,
|
||||
|
||||
/// Flags.
|
||||
flags: ElementDataFlags,
|
||||
pub flags: ElementDataFlags,
|
||||
}
|
||||
|
||||
/// The kind of restyle that a single element should do.
|
||||
|
@ -276,11 +284,17 @@ impl ElementData {
|
|||
|
||||
/// Returns this element's primary style as a resolved style to use for sharing.
|
||||
pub fn share_primary_style(&self) -> PrimaryStyle {
|
||||
PrimaryStyle(ResolvedStyle::new(self.styles.primary().clone()))
|
||||
let primary_is_reused = self.flags.contains(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
|
||||
PrimaryStyle(ResolvedStyle::new(self.styles.primary().clone(), primary_is_reused))
|
||||
}
|
||||
|
||||
/// Sets a new set of styles, returning the old ones.
|
||||
pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
|
||||
if new_styles.primary.0.reused_via_rule_node {
|
||||
self.flags.insert(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
|
||||
} else {
|
||||
self.flags.remove(PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
|
||||
}
|
||||
mem::replace(&mut self.styles, new_styles.into())
|
||||
}
|
||||
|
||||
|
@ -442,6 +456,28 @@ impl ElementData {
|
|||
#[cfg(feature = "servo")]
|
||||
pub fn skip_applying_damage(&self) -> bool { false }
|
||||
|
||||
/// Returns whether it is safe to perform cousin sharing based on the ComputedValues
|
||||
/// identity of the primary style in this ElementData. There are a few subtle things
|
||||
/// to check.
|
||||
///
|
||||
/// First, if a parent element was already styled and we traversed past it without
|
||||
/// restyling it, that may be because our clever invalidation logic was able to prove
|
||||
/// that the styles of that element would remain unchanged despite changes to the id
|
||||
/// or class attributes. However, style sharing relies on the strong guarantee that all
|
||||
/// the classes and ids up the respective parent chains are identical. As such, if we
|
||||
/// skipped styling for one (or both) of the parents on this traversal, we can't share
|
||||
/// styles across cousins. Note that this is a somewhat conservative check. We could
|
||||
/// tighten it by having the invalidation logic explicitly flag elements for which it
|
||||
/// ellided styling.
|
||||
///
|
||||
/// Second, we want to only consider elements whose ComputedValues match due to a hit
|
||||
/// in the style sharing cache, rather than due to the rule-node-based reuse that
|
||||
/// happens later in the styling pipeline. The former gives us the stronger guarantees
|
||||
/// we need for style sharing, the latter does not.
|
||||
pub fn safe_for_cousin_sharing(&self) -> bool {
|
||||
!self.flags.intersects(TRAVERSED_WITHOUT_STYLING | PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
|
||||
}
|
||||
|
||||
/// Measures memory usage.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue