mirror of
https://github.com/servo/servo.git
synced 2025-06-09 17:13:24 +00:00
Auto merge of #17348 - emilio:bup, r=bholley
style: Inline RestyleData. Bug: 1368236 MozReview-Commit-ID: 49s3SO0PMHf <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17348) <!-- Reviewable:end -->
This commit is contained in:
commit
33766b2714
11 changed files with 183 additions and 202 deletions
|
@ -171,19 +171,14 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T {
|
||||||
|
|
||||||
let damage = {
|
let damage = {
|
||||||
let data = node.get_raw_data().unwrap();
|
let data = node.get_raw_data().unwrap();
|
||||||
if let Some(r) = data.style_data.element_data.borrow().get_restyle() {
|
|
||||||
// We're reflowing a node that just got a restyle, and so the
|
if !data.layout_data.borrow().flags.contains(::data::HAS_BEEN_TRAVERSED) {
|
||||||
// damage has been computed and stored in the RestyleData.
|
|
||||||
r.damage
|
|
||||||
} else if !data.layout_data.borrow().flags.contains(::data::HAS_BEEN_TRAVERSED) {
|
|
||||||
// We're reflowing a node that was styled for the first time and
|
// We're reflowing a node that was styled for the first time and
|
||||||
// has never been visited by layout. Return rebuild_and_reflow,
|
// has never been visited by layout. Return rebuild_and_reflow,
|
||||||
// because that's what the code expects.
|
// because that's what the code expects.
|
||||||
RestyleDamage::rebuild_and_reflow()
|
RestyleDamage::rebuild_and_reflow()
|
||||||
} else {
|
} else {
|
||||||
// We're reflowing a node whose style data didn't change, but whose
|
data.style_data.element_data.borrow().restyle.damage
|
||||||
// layout may change due to changes in ancestors or descendants.
|
|
||||||
RestyleDamage::empty()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1116,7 +1116,7 @@ impl LayoutThread {
|
||||||
let el = node.as_element().unwrap();
|
let el = node.as_element().unwrap();
|
||||||
if let Some(mut d) = element.mutate_data() {
|
if let Some(mut d) = element.mutate_data() {
|
||||||
if d.has_styles() {
|
if d.has_styles() {
|
||||||
d.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
d.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(p) = el.parent_element() {
|
if let Some(p) = el.parent_element() {
|
||||||
|
@ -1152,7 +1152,7 @@ impl LayoutThread {
|
||||||
if needs_dirtying {
|
if needs_dirtying {
|
||||||
if let Some(mut d) = element.mutate_data() {
|
if let Some(mut d) = element.mutate_data() {
|
||||||
if d.has_styles() {
|
if d.has_styles() {
|
||||||
d.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
d.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1197,12 +1197,11 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut style_data = style_data.borrow_mut();
|
let mut style_data = style_data.borrow_mut();
|
||||||
let mut restyle_data = style_data.ensure_restyle();
|
|
||||||
|
|
||||||
// Stash the data on the element for processing by the style system.
|
// Stash the data on the element for processing by the style system.
|
||||||
restyle_data.hint.insert(restyle.hint.into());
|
style_data.restyle.hint.insert(restyle.hint.into());
|
||||||
restyle_data.damage = restyle.damage;
|
style_data.restyle.damage = restyle.damage;
|
||||||
debug!("Noting restyle for {:?}: {:?}", el, restyle_data);
|
debug!("Noting restyle for {:?}: {:?}", el, style_data.restyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a layout context for use throughout the following passes.
|
// Create a layout context for use throughout the following passes.
|
||||||
|
|
|
@ -348,17 +348,26 @@ impl ElementStyles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags RestyleFlags: u8 {
|
||||||
|
/// Whether the styles changed for this restyle.
|
||||||
|
const WAS_RESTYLED = 1 << 0,
|
||||||
|
/// Whether we reframed/reconstructed any ancestor or self.
|
||||||
|
const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transient data used by the restyle algorithm. This structure is instantiated
|
/// Transient data used by the restyle algorithm. This structure is instantiated
|
||||||
/// either before or during restyle traversal, and is cleared at the end of node
|
/// either before or during restyle traversal, and is cleared at the end of node
|
||||||
/// processing.
|
/// processing.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct RestyleData {
|
pub struct RestyleData {
|
||||||
/// The restyle hint, which indicates whether selectors need to be rematched
|
/// The restyle hint, which indicates whether selectors need to be rematched
|
||||||
/// for this element, its children, and its descendants.
|
/// for this element, its children, and its descendants.
|
||||||
pub hint: RestyleHint,
|
pub hint: RestyleHint,
|
||||||
|
|
||||||
/// Whether we reframed/reconstructed any ancestor or self.
|
/// A few flags to have in mind.
|
||||||
pub reconstructed_ancestor: bool,
|
flags: RestyleFlags,
|
||||||
|
|
||||||
/// The restyle damage, indicating what kind of layout changes are required
|
/// The restyle damage, indicating what kind of layout changes are required
|
||||||
/// afte restyling.
|
/// afte restyling.
|
||||||
|
@ -366,9 +375,53 @@ pub struct RestyleData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestyleData {
|
impl RestyleData {
|
||||||
/// Returns true if this RestyleData might invalidate the current style.
|
fn new() -> Self {
|
||||||
pub fn has_invalidations(&self) -> bool {
|
Self {
|
||||||
self.hint.has_self_invalidations()
|
hint: RestyleHint::empty(),
|
||||||
|
flags: RestyleFlags::empty(),
|
||||||
|
damage: RestyleDamage::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear all the restyle state associated with this element.
|
||||||
|
fn clear(&mut self) {
|
||||||
|
*self = Self::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this element or any ancestor is going to be
|
||||||
|
/// reconstructed.
|
||||||
|
pub fn reconstructed_self_or_ancestor(&self) -> bool {
|
||||||
|
self.reconstructed_ancestor() ||
|
||||||
|
self.damage.contains(RestyleDamage::reconstruct())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether any ancestor of this element was restyled.
|
||||||
|
fn reconstructed_ancestor(&self) -> bool {
|
||||||
|
self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the flag that tells us whether we've reconstructed an ancestor.
|
||||||
|
pub fn set_reconstructed_ancestor(&mut self) {
|
||||||
|
// If it weren't for animation-only traversals, we could assert
|
||||||
|
// `!self.reconstructed_ancestor()` here.
|
||||||
|
self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark this element as restyled, which is useful to know whether we need
|
||||||
|
/// to do a post-traversal.
|
||||||
|
pub fn set_restyled(&mut self) {
|
||||||
|
self.flags.insert(WAS_RESTYLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark this element as restyled, which is useful to know whether we need
|
||||||
|
/// to do a post-traversal.
|
||||||
|
pub fn is_restyle(&self) -> bool {
|
||||||
|
self.flags.contains(WAS_RESTYLED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this element has been part of a restyle.
|
||||||
|
pub fn contains_restyle_data(&self) -> bool {
|
||||||
|
self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,9 +435,8 @@ pub struct ElementData {
|
||||||
/// The computed styles for the element and its pseudo-elements.
|
/// The computed styles for the element and its pseudo-elements.
|
||||||
styles: Option<ElementStyles>,
|
styles: Option<ElementStyles>,
|
||||||
|
|
||||||
/// Restyle tracking. We separate this into a separate allocation so that
|
/// Restyle state.
|
||||||
/// we can drop it when no restyles are pending on the elemnt.
|
pub restyle: RestyleData,
|
||||||
restyle: Option<Box<RestyleData>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of restyle that a single element should do.
|
/// The kind of restyle that a single element should do.
|
||||||
|
@ -402,6 +454,14 @@ pub enum RestyleKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementData {
|
impl ElementData {
|
||||||
|
/// Borrows both styles and restyle mutably at the same time.
|
||||||
|
pub fn styles_and_restyle_mut(
|
||||||
|
&mut self
|
||||||
|
) -> (&mut ElementStyles, &mut RestyleData) {
|
||||||
|
(self.styles.as_mut().unwrap(),
|
||||||
|
&mut self.restyle)
|
||||||
|
}
|
||||||
|
|
||||||
/// Invalidates style for this element, its descendants, and later siblings,
|
/// Invalidates style for this element, its descendants, and later siblings,
|
||||||
/// based on the snapshot of the element that we took when attributes or
|
/// based on the snapshot of the element that we took when attributes or
|
||||||
/// state changed.
|
/// state changed.
|
||||||
|
@ -437,7 +497,7 @@ impl ElementData {
|
||||||
pub fn new(existing: Option<ElementStyles>) -> Self {
|
pub fn new(existing: Option<ElementStyles>) -> Self {
|
||||||
ElementData {
|
ElementData {
|
||||||
styles: existing,
|
styles: existing,
|
||||||
restyle: None,
|
restyle: RestyleData::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,7 +508,7 @@ impl ElementData {
|
||||||
|
|
||||||
/// Returns whether we have any outstanding style invalidation.
|
/// Returns whether we have any outstanding style invalidation.
|
||||||
pub fn has_invalidations(&self) -> bool {
|
pub fn has_invalidations(&self) -> bool {
|
||||||
self.restyle.as_ref().map_or(false, |r| r.has_invalidations())
|
self.restyle.hint.has_self_invalidations()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the kind of restyling that we're going to need to do on this
|
/// Returns the kind of restyling that we're going to need to do on this
|
||||||
|
@ -465,10 +525,7 @@ impl ElementData {
|
||||||
return RestyleKind::MatchAndCascade;
|
return RestyleKind::MatchAndCascade;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(self.restyle.is_some());
|
let hint = self.restyle.hint;
|
||||||
let restyle_data = self.restyle.as_ref().unwrap();
|
|
||||||
|
|
||||||
let hint = restyle_data.hint;
|
|
||||||
if shared_context.traversal_flags.for_animation_only() {
|
if shared_context.traversal_flags.for_animation_only() {
|
||||||
// return either CascadeWithReplacements or CascadeOnly in case of
|
// return either CascadeWithReplacements or CascadeOnly in case of
|
||||||
// animation-only restyle.
|
// animation-only restyle.
|
||||||
|
@ -488,7 +545,8 @@ impl ElementData {
|
||||||
return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
|
return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(hint.has_recascade_self(), "We definitely need to do something!");
|
debug_assert!(hint.has_recascade_self(),
|
||||||
|
"We definitely need to do something!");
|
||||||
return RestyleKind::CascadeOnly;
|
return RestyleKind::CascadeOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,13 +571,6 @@ impl ElementData {
|
||||||
self.styles.as_mut().expect("Calling styles_mut() on unstyled ElementData")
|
self.styles.as_mut().expect("Calling styles_mut() on unstyled ElementData")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows both styles and restyle mutably at the same time.
|
|
||||||
pub fn styles_and_restyle_mut(&mut self) -> (&mut ElementStyles,
|
|
||||||
Option<&mut RestyleData>) {
|
|
||||||
(self.styles.as_mut().unwrap(),
|
|
||||||
self.restyle.as_mut().map(|r| &mut **r))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the computed element styles.
|
/// Sets the computed element styles.
|
||||||
pub fn set_styles(&mut self, styles: ElementStyles) {
|
pub fn set_styles(&mut self, styles: ElementStyles) {
|
||||||
self.styles = Some(styles);
|
self.styles = Some(styles);
|
||||||
|
@ -558,47 +609,9 @@ impl ElementData {
|
||||||
important_rules != other_important_rules
|
important_rules != other_important_rules
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the Element has a RestyleData.
|
/// Drops any restyle state from the element.
|
||||||
pub fn has_restyle(&self) -> bool {
|
pub fn clear_restyle_state(&mut self) {
|
||||||
self.restyle.is_some()
|
self.restyle.clear();
|
||||||
}
|
|
||||||
|
|
||||||
/// Drops any RestyleData.
|
|
||||||
pub fn clear_restyle(&mut self) {
|
|
||||||
self.restyle = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a RestyleData if one doesn't exist.
|
|
||||||
///
|
|
||||||
/// Asserts that the Element has been styled.
|
|
||||||
pub fn ensure_restyle(&mut self) -> &mut RestyleData {
|
|
||||||
debug_assert!(self.styles.is_some(), "restyling unstyled element");
|
|
||||||
if self.restyle.is_none() {
|
|
||||||
self.restyle = Some(Box::new(RestyleData::default()));
|
|
||||||
}
|
|
||||||
self.restyle.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the restyle data, if any.
|
|
||||||
pub fn get_restyle(&self) -> Option<&RestyleData> {
|
|
||||||
self.restyle.as_ref().map(|r| &**r)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the restyle data. Panic if the element does not
|
|
||||||
/// have restyle data.
|
|
||||||
pub fn restyle(&self) -> &RestyleData {
|
|
||||||
self.get_restyle().expect("Calling restyle without RestyleData")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a mutable reference to the restyle data, if any.
|
|
||||||
pub fn get_restyle_mut(&mut self) -> Option<&mut RestyleData> {
|
|
||||||
self.restyle.as_mut().map(|r| &mut **r)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a mutable reference to the restyle data. Panic if the element does
|
|
||||||
/// not have restyle data.
|
|
||||||
pub fn restyle_mut(&mut self) -> &mut RestyleData {
|
|
||||||
self.get_restyle_mut().expect("Calling restyle_mut without RestyleData")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns SMIL overriden value if exists.
|
/// Returns SMIL overriden value if exists.
|
||||||
|
|
|
@ -567,8 +567,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
return data.get_restyle()
|
return data.restyle.hint.has_animation_hint()
|
||||||
.map_or(false, |r| r.hint.has_animation_hint());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets declarations from XBL bindings from the element. Only gecko element could have this.
|
/// Gets declarations from XBL bindings from the element. Only gecko element could have this.
|
||||||
|
|
|
@ -114,7 +114,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
// We can't just return here because there may also be attribute
|
// We can't just return here because there may also be attribute
|
||||||
// changes as well that imply additional hints.
|
// changes as well that imply additional hints.
|
||||||
let mut data = self.data.as_mut().unwrap();
|
let mut data = self.data.as_mut().unwrap();
|
||||||
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree().into());
|
data.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut classes_removed = SmallVec::<[Atom; 8]>::new();
|
let mut classes_removed = SmallVec::<[Atom; 8]>::new();
|
||||||
|
@ -211,7 +211,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
|
|
||||||
if invalidated_self {
|
if invalidated_self {
|
||||||
if let Some(ref mut data) = self.data {
|
if let Some(ref mut data) = self.data {
|
||||||
data.ensure_restyle().hint.insert(RESTYLE_SELF.into());
|
data.restyle.hint.insert(RESTYLE_SELF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,13 +287,11 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
match self.data {
|
match self.data {
|
||||||
None => return false,
|
None => return false,
|
||||||
Some(ref data) => {
|
Some(ref data) => {
|
||||||
if let Some(restyle) = data.get_restyle() {
|
if data.restyle.hint.contains_subtree() {
|
||||||
if restyle.hint.contains_subtree() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut sibling_invalidations = InvalidationVector::new();
|
let mut sibling_invalidations = InvalidationVector::new();
|
||||||
|
|
||||||
|
@ -494,7 +492,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
|
|
||||||
if invalidated_self {
|
if invalidated_self {
|
||||||
if let Some(ref mut data) = self.data {
|
if let Some(ref mut data) = self.data {
|
||||||
data.ensure_restyle().hint.insert(RESTYLE_SELF.into());
|
data.restyle.hint.insert(RESTYLE_SELF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl StylesheetInvalidationSet {
|
||||||
if self.fully_invalid {
|
if self.fully_invalid {
|
||||||
debug!("process_invalidations: fully_invalid({:?})",
|
debug!("process_invalidations: fully_invalid({:?})",
|
||||||
element);
|
element);
|
||||||
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
data.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,19 +165,17 @@ impl StylesheetInvalidationSet {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref r) = data.get_restyle() {
|
if data.restyle.hint.contains_subtree() {
|
||||||
if r.hint.contains_subtree() {
|
|
||||||
debug!("process_invalidations_in_subtree: {:?} was already invalid",
|
debug!("process_invalidations_in_subtree: {:?} was already invalid",
|
||||||
element);
|
element);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for scope in &self.invalid_scopes {
|
for scope in &self.invalid_scopes {
|
||||||
if scope.matches(element) {
|
if scope.matches(element) {
|
||||||
debug!("process_invalidations_in_subtree: {:?} matched {:?}",
|
debug!("process_invalidations_in_subtree: {:?} matched {:?}",
|
||||||
element, scope);
|
element, scope);
|
||||||
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
data.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -707,8 +707,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
// for followup work to make the optimization here more optimal by considering
|
// for followup work to make the optimization here more optimal by considering
|
||||||
// each bit individually.
|
// each bit individually.
|
||||||
let skip_applying_damage =
|
let skip_applying_damage =
|
||||||
restyle.damage.contains(RestyleDamage::reconstruct()) ||
|
restyle.reconstructed_self_or_ancestor();
|
||||||
restyle.reconstructed_ancestor;
|
|
||||||
|
|
||||||
let difference = self.compute_style_difference(&old_values,
|
let difference = self.compute_style_difference(&old_values,
|
||||||
&new_values,
|
&new_values,
|
||||||
|
@ -1187,12 +1186,10 @@ pub trait MatchMethods : TElement {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if matches_different_pseudos {
|
if matches_different_pseudos && data.restyle.is_restyle() {
|
||||||
if let Some(r) = data.get_restyle_mut() {
|
|
||||||
// Any changes to the matched pseudo-elements trigger
|
// Any changes to the matched pseudo-elements trigger
|
||||||
// reconstruction.
|
// reconstruction.
|
||||||
r.damage |= RestyleDamage::reconstruct();
|
data.restyle.damage |= RestyleDamage::reconstruct();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1257,16 +1254,11 @@ pub trait MatchMethods : TElement {
|
||||||
/// Computes and applies restyle damage.
|
/// Computes and applies restyle damage.
|
||||||
fn accumulate_damage(&self,
|
fn accumulate_damage(&self,
|
||||||
shared_context: &SharedStyleContext,
|
shared_context: &SharedStyleContext,
|
||||||
restyle: Option<&mut RestyleData>,
|
restyle: &mut RestyleData,
|
||||||
old_values: Option<&ComputedValues>,
|
old_values: Option<&ComputedValues>,
|
||||||
new_values: &Arc<ComputedValues>,
|
new_values: &Arc<ComputedValues>,
|
||||||
pseudo: Option<&PseudoElement>)
|
pseudo: Option<&PseudoElement>)
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
let restyle = match restyle {
|
|
||||||
Some(r) => r,
|
|
||||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
|
||||||
};
|
|
||||||
|
|
||||||
let old_values = match old_values {
|
let old_values = match old_values {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||||
|
|
|
@ -377,10 +377,10 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
// We used to have pseudos (because we had styles).
|
// We used to have pseudos (because we had styles).
|
||||||
// Check for damage from the set of pseudos changing or
|
// Check for damage from the set of pseudos changing or
|
||||||
// pseudos being restyled.
|
// pseudos being restyled.
|
||||||
let (styles, restyle_data) = data.styles_and_restyle_mut();
|
let (styles, mut restyle_data) = data.styles_and_restyle_mut();
|
||||||
if let Some(restyle_data) = restyle_data {
|
|
||||||
let old_pseudos = &styles.pseudos;
|
let old_pseudos = &styles.pseudos;
|
||||||
let new_pseudos = &shared_style.pseudos;
|
let new_pseudos = &shared_style.pseudos;
|
||||||
|
|
||||||
if !old_pseudos.has_same_pseudos_as(new_pseudos) {
|
if !old_pseudos.has_same_pseudos_as(new_pseudos) {
|
||||||
restyle_data.damage |= RestyleDamage::reconstruct();
|
restyle_data.damage |= RestyleDamage::reconstruct();
|
||||||
} else {
|
} else {
|
||||||
|
@ -394,7 +394,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
new_pseudos.get(&pseudo).unwrap().values();
|
new_pseudos.get(&pseudo).unwrap().values();
|
||||||
self.element.accumulate_damage(
|
self.element.accumulate_damage(
|
||||||
&shared_context,
|
&shared_context,
|
||||||
Some(restyle_data),
|
restyle_data,
|
||||||
old_values,
|
old_values,
|
||||||
new_values,
|
new_values,
|
||||||
Some(&pseudo)
|
Some(&pseudo)
|
||||||
|
@ -402,13 +402,13 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let old_values = data.get_styles_mut()
|
let old_values =
|
||||||
.and_then(|s| s.primary.values.take());
|
data.get_styles_mut().and_then(|s| s.primary.values.take());
|
||||||
|
|
||||||
self.element.accumulate_damage(
|
self.element.accumulate_damage(
|
||||||
&shared_context,
|
&shared_context,
|
||||||
data.get_restyle_mut(),
|
&mut data.restyle,
|
||||||
old_values.as_ref().map(|v| &**v),
|
old_values.as_ref().map(|v| &**v),
|
||||||
shared_style.primary.values(),
|
shared_style.primary.values(),
|
||||||
None
|
None
|
||||||
|
@ -597,9 +597,6 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
|
||||||
match sharing_result {
|
match sharing_result {
|
||||||
Ok(shared_style) => {
|
Ok(shared_style) => {
|
||||||
// Yay, cache hit. Share the style.
|
// Yay, cache hit. Share the style.
|
||||||
|
|
||||||
debug_assert_eq!(data.has_styles(), data.has_restyle());
|
|
||||||
|
|
||||||
let child_cascade_requirement =
|
let child_cascade_requirement =
|
||||||
target.accumulate_damage_when_sharing(shared_context,
|
target.accumulate_damage_when_sharing(shared_context,
|
||||||
&shared_style,
|
&shared_style,
|
||||||
|
|
|
@ -10,7 +10,6 @@ use data::{ElementData, ElementStyles};
|
||||||
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
||||||
use invalidation::element::restyle_hints::{RECASCADE_SELF, RECASCADE_DESCENDANTS, RestyleHint};
|
use invalidation::element::restyle_hints::{RECASCADE_SELF, RECASCADE_DESCENDANTS, RestyleHint};
|
||||||
use matching::{ChildCascadeRequirement, MatchMethods};
|
use matching::{ChildCascadeRequirement, MatchMethods};
|
||||||
use selector_parser::RestyleDamage;
|
|
||||||
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
||||||
#[cfg(feature = "servo")] use servo_config::opts;
|
#[cfg(feature = "servo")] use servo_config::opts;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -296,10 +295,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
if el.is_native_anonymous() {
|
if el.is_native_anonymous() {
|
||||||
if let Some(parent) = el.traversal_parent() {
|
if let Some(parent) = el.traversal_parent() {
|
||||||
let parent_data = parent.borrow_data().unwrap();
|
let parent_data = parent.borrow_data().unwrap();
|
||||||
let going_to_reframe = parent_data.get_restyle().map_or(false, |r| {
|
let going_to_reframe =
|
||||||
r.reconstructed_ancestor ||
|
parent_data.restyle.reconstructed_self_or_ancestor();
|
||||||
r.damage.contains(RestyleDamage::reconstruct())
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut is_before_or_after_pseudo = false;
|
let mut is_before_or_after_pseudo = false;
|
||||||
if let Some(pseudo) = el.implemented_pseudo_element() {
|
if let Some(pseudo) = el.implemented_pseudo_element() {
|
||||||
|
@ -337,9 +334,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
return data.get_restyle()
|
return data.restyle.hint.has_animation_hint() ||
|
||||||
.map_or(false, |r| r.hint.has_animation_hint() ||
|
data.restyle.hint.has_recascade_self();
|
||||||
r.hint.has_recascade_self());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the dirty descendants bit is set, we need to traverse no
|
// If the dirty descendants bit is set, we need to traverse no
|
||||||
|
@ -360,8 +356,6 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the restyle data.
|
|
||||||
if let Some(r) = data.get_restyle() {
|
|
||||||
// If we have a restyle hint or need to recascade, we need to
|
// If we have a restyle hint or need to recascade, we need to
|
||||||
// visit the element.
|
// visit the element.
|
||||||
//
|
//
|
||||||
|
@ -369,10 +363,9 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
// since that can return true even if we have a restyle hint
|
// since that can return true even if we have a restyle hint
|
||||||
// indicating that the element's descendants (but not necessarily
|
// indicating that the element's descendants (but not necessarily
|
||||||
// the element) need restyling.
|
// the element) need restyling.
|
||||||
if !r.hint.is_empty() {
|
if !data.restyle.hint.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Servo uses the post-order traversal for flow construction, so
|
// Servo uses the post-order traversal for flow construction, so
|
||||||
// we need to traverse any element with damage so that we can perform
|
// we need to traverse any element with damage so that we can perform
|
||||||
|
@ -381,7 +374,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
// We also need to traverse nodes with explicit damage and no other
|
// We also need to traverse nodes with explicit damage and no other
|
||||||
// restyle data, so that this damage can be cleared.
|
// restyle data, so that this damage can be cleared.
|
||||||
if (cfg!(feature = "servo") || traversal_flags.for_reconstruct()) &&
|
if (cfg!(feature = "servo") || traversal_flags.for_reconstruct()) &&
|
||||||
data.get_restyle().map_or(false, |r| !r.damage.is_empty()) {
|
!data.restyle.damage.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,20 +683,17 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
|
|
||||||
// Now that matching and cascading is done, clear the bits corresponding to
|
// Now that matching and cascading is done, clear the bits corresponding to
|
||||||
// those operations and compute the propagated restyle hint.
|
// those operations and compute the propagated restyle hint.
|
||||||
let mut propagated_hint = match data.get_restyle_mut() {
|
let mut propagated_hint = {
|
||||||
None => RestyleHint::empty(),
|
|
||||||
Some(r) => {
|
|
||||||
debug_assert!(context.shared.traversal_flags.for_animation_only() ||
|
debug_assert!(context.shared.traversal_flags.for_animation_only() ||
|
||||||
!r.hint.has_animation_hint(),
|
!data.restyle.hint.has_animation_hint(),
|
||||||
"animation restyle hint should be handled during \
|
"animation restyle hint should be handled during \
|
||||||
animation-only restyles");
|
animation-only restyles");
|
||||||
r.hint.propagate(&context.shared.traversal_flags)
|
data.restyle.hint.propagate(&context.shared.traversal_flags)
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(bholley): Need to handle explicitly-inherited reset properties
|
// FIXME(bholley): Need to handle explicitly-inherited reset properties
|
||||||
// somewhere.
|
// somewhere.
|
||||||
propagated_hint.insert(hint.into());
|
propagated_hint.insert(hint);
|
||||||
|
|
||||||
trace!("propagated_hint={:?} \
|
trace!("propagated_hint={:?} \
|
||||||
is_display_none={:?}, implementing_pseudo={:?}",
|
is_display_none={:?}, implementing_pseudo={:?}",
|
||||||
|
@ -730,10 +720,9 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
DontLog) &&
|
DontLog) &&
|
||||||
(has_dirty_descendants_for_this_restyle ||
|
(has_dirty_descendants_for_this_restyle ||
|
||||||
!propagated_hint.is_empty()) {
|
!propagated_hint.is_empty()) {
|
||||||
let reconstructed_ancestor = data.get_restyle().map_or(false, |r| {
|
let reconstructed_ancestor =
|
||||||
r.reconstructed_ancestor ||
|
data.restyle.reconstructed_self_or_ancestor();
|
||||||
r.damage.contains(RestyleDamage::reconstruct())
|
|
||||||
});
|
|
||||||
preprocess_children::<E, D>(
|
preprocess_children::<E, D>(
|
||||||
context,
|
context,
|
||||||
element,
|
element,
|
||||||
|
@ -746,7 +735,7 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
// data here, since we won't need to perform a post-traversal to pick up
|
// data here, since we won't need to perform a post-traversal to pick up
|
||||||
// any change hints.
|
// any change hints.
|
||||||
if context.shared.traversal_flags.for_reconstruct() {
|
if context.shared.traversal_flags.for_reconstruct() {
|
||||||
data.clear_restyle();
|
data.clear_restyle_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
if context.shared.traversal_flags.for_animation_only() {
|
if context.shared.traversal_flags.for_animation_only() {
|
||||||
|
@ -792,6 +781,10 @@ fn compute_style<E, D>(_traversal: &D,
|
||||||
|
|
||||||
debug!("compute_style: {:?} (kind={:?})", element, kind);
|
debug!("compute_style: {:?} (kind={:?})", element, kind);
|
||||||
|
|
||||||
|
if data.has_styles() {
|
||||||
|
data.restyle.set_restyled();
|
||||||
|
}
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
MatchAndCascade => {
|
MatchAndCascade => {
|
||||||
debug_assert!(!context.shared.traversal_flags.for_animation_only(),
|
debug_assert!(!context.shared.traversal_flags.for_animation_only(),
|
||||||
|
@ -870,31 +863,24 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle element snapshots and invalidation of descendants and siblings
|
|
||||||
// as needed.
|
|
||||||
//
|
|
||||||
// NB: This will be a no-op if there's no restyle data and no snapshot.
|
|
||||||
child_data.invalidate_style_if_needed(child, &context.shared);
|
|
||||||
|
|
||||||
trace!(" > {:?} -> {:?} + {:?}, pseudo: {:?}",
|
trace!(" > {:?} -> {:?} + {:?}, pseudo: {:?}",
|
||||||
child,
|
child,
|
||||||
child_data.get_restyle().map(|r| &r.hint),
|
child_data.restyle.hint,
|
||||||
propagated_hint,
|
propagated_hint,
|
||||||
child.implemented_pseudo_element());
|
child.implemented_pseudo_element());
|
||||||
|
|
||||||
// If the child doesn't have pre-existing RestyleData and we don't have
|
|
||||||
// any reason to create one, avoid the useless allocation and move on to
|
|
||||||
// the next child.
|
|
||||||
if !reconstructed_ancestor && propagated_hint.is_empty() && !child_data.has_restyle() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut restyle_data = child_data.ensure_restyle();
|
|
||||||
|
|
||||||
// Propagate the parent restyle hint, that may make us restyle the whole
|
// Propagate the parent restyle hint, that may make us restyle the whole
|
||||||
// subtree.
|
// subtree.
|
||||||
restyle_data.reconstructed_ancestor = reconstructed_ancestor;
|
if reconstructed_ancestor {
|
||||||
restyle_data.hint.insert(propagated_hint);
|
child_data.restyle.set_reconstructed_ancestor();
|
||||||
|
}
|
||||||
|
child_data.restyle.hint.insert(propagated_hint);
|
||||||
|
|
||||||
|
// Handle element snapshots and invalidation of descendants and siblings
|
||||||
|
// as needed.
|
||||||
|
//
|
||||||
|
// NB: This will be a no-op if there's no snapshot.
|
||||||
|
child_data.invalidate_style_if_needed(child, &context.shared);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
element.has_dirty_descendants() || element.borrow_data().unwrap().has_restyle()
|
element.has_dirty_descendants() || element.borrow_data().unwrap().restyle.contains_restyle_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -2461,7 +2461,7 @@ unsafe fn maybe_restyle<'a>(data: &'a mut AtomicRefMut<ElementData>,
|
||||||
bindings::Gecko_SetOwnerDocumentNeedsStyleFlush(element.0);
|
bindings::Gecko_SetOwnerDocumentNeedsStyleFlush(element.0);
|
||||||
|
|
||||||
// Ensure and return the RestyleData.
|
// Ensure and return the RestyleData.
|
||||||
Some(data.ensure_restyle())
|
Some(&mut data.restyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -2518,13 +2518,16 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
|
||||||
pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint
|
pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint
|
||||||
{
|
{
|
||||||
let element = GeckoElement(element);
|
let element = GeckoElement(element);
|
||||||
let damage = if let Some(mut data) = element.mutate_data() {
|
let damage = match element.mutate_data() {
|
||||||
let d = data.get_restyle().map_or(GeckoRestyleDamage::empty(), |r| r.damage);
|
Some(mut data) => {
|
||||||
data.clear_restyle();
|
let damage = data.restyle.damage;
|
||||||
d
|
data.clear_restyle_state();
|
||||||
} else {
|
damage
|
||||||
|
}
|
||||||
|
None => {
|
||||||
warn!("Trying to get change hint from unstyled element");
|
warn!("Trying to get change hint from unstyled element");
|
||||||
GeckoRestyleDamage::empty()
|
GeckoRestyleDamage::empty()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
|
debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use servo_arc::Arc;
|
||||||
use std::mem::{size_of, align_of};
|
use std::mem::{size_of, align_of};
|
||||||
use style;
|
use style;
|
||||||
use style::applicable_declarations::ApplicableDeclarationBlock;
|
use style::applicable_declarations::ApplicableDeclarationBlock;
|
||||||
use style::data::{ComputedStyle, ElementData, ElementStyles};
|
use style::data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
|
||||||
use style::gecko::selector_parser as real;
|
use style::gecko::selector_parser as real;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::rule_tree::{RuleNode, StrongRuleNode};
|
use style::rule_tree::{RuleNode, StrongRuleNode};
|
||||||
|
@ -34,6 +34,7 @@ size_of_test!(test_size_of_option_rule_node, Option<StrongRuleNode>, 8);
|
||||||
size_of_test!(test_size_of_computed_style, ComputedStyle, 32);
|
size_of_test!(test_size_of_computed_style, ComputedStyle, 32);
|
||||||
size_of_test!(test_size_of_element_styles, ElementStyles, 48);
|
size_of_test!(test_size_of_element_styles, ElementStyles, 48);
|
||||||
size_of_test!(test_size_of_element_data, ElementData, 56);
|
size_of_test!(test_size_of_element_data, ElementData, 56);
|
||||||
|
size_of_test!(test_size_of_restyle_data, RestyleData, 8);
|
||||||
|
|
||||||
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
|
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue