mirror of
https://github.com/servo/servo.git
synced 2025-06-09 09:03:23 +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 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
|
||||
// damage has been computed and stored in the RestyleData.
|
||||
r.damage
|
||||
} else if !data.layout_data.borrow().flags.contains(::data::HAS_BEEN_TRAVERSED) {
|
||||
|
||||
if !data.layout_data.borrow().flags.contains(::data::HAS_BEEN_TRAVERSED) {
|
||||
// We're reflowing a node that was styled for the first time and
|
||||
// has never been visited by layout. Return rebuild_and_reflow,
|
||||
// because that's what the code expects.
|
||||
RestyleDamage::rebuild_and_reflow()
|
||||
} else {
|
||||
// We're reflowing a node whose style data didn't change, but whose
|
||||
// layout may change due to changes in ancestors or descendants.
|
||||
RestyleDamage::empty()
|
||||
data.style_data.element_data.borrow().restyle.damage
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1116,7 +1116,7 @@ impl LayoutThread {
|
|||
let el = node.as_element().unwrap();
|
||||
if let Some(mut d) = element.mutate_data() {
|
||||
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() {
|
||||
|
@ -1152,7 +1152,7 @@ impl LayoutThread {
|
|||
if needs_dirtying {
|
||||
if let Some(mut d) = element.mutate_data() {
|
||||
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 restyle_data = style_data.ensure_restyle();
|
||||
|
||||
// Stash the data on the element for processing by the style system.
|
||||
restyle_data.hint.insert(restyle.hint.into());
|
||||
restyle_data.damage = restyle.damage;
|
||||
debug!("Noting restyle for {:?}: {:?}", el, restyle_data);
|
||||
style_data.restyle.hint.insert(restyle.hint.into());
|
||||
style_data.restyle.damage = restyle.damage;
|
||||
debug!("Noting restyle for {:?}: {:?}", el, style_data.restyle);
|
||||
}
|
||||
|
||||
// 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
|
||||
/// either before or during restyle traversal, and is cleared at the end of node
|
||||
/// processing.
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
pub struct RestyleData {
|
||||
/// The restyle hint, which indicates whether selectors need to be rematched
|
||||
/// for this element, its children, and its descendants.
|
||||
pub hint: RestyleHint,
|
||||
|
||||
/// Whether we reframed/reconstructed any ancestor or self.
|
||||
pub reconstructed_ancestor: bool,
|
||||
/// A few flags to have in mind.
|
||||
flags: RestyleFlags,
|
||||
|
||||
/// The restyle damage, indicating what kind of layout changes are required
|
||||
/// afte restyling.
|
||||
|
@ -366,9 +375,53 @@ pub struct RestyleData {
|
|||
}
|
||||
|
||||
impl RestyleData {
|
||||
/// Returns true if this RestyleData might invalidate the current style.
|
||||
pub fn has_invalidations(&self) -> bool {
|
||||
self.hint.has_self_invalidations()
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
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.
|
||||
styles: Option<ElementStyles>,
|
||||
|
||||
/// Restyle tracking. We separate this into a separate allocation so that
|
||||
/// we can drop it when no restyles are pending on the elemnt.
|
||||
restyle: Option<Box<RestyleData>>,
|
||||
/// Restyle state.
|
||||
pub restyle: RestyleData,
|
||||
}
|
||||
|
||||
/// The kind of restyle that a single element should do.
|
||||
|
@ -402,6 +454,14 @@ pub enum RestyleKind {
|
|||
}
|
||||
|
||||
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,
|
||||
/// based on the snapshot of the element that we took when attributes or
|
||||
/// state changed.
|
||||
|
@ -437,7 +497,7 @@ impl ElementData {
|
|||
pub fn new(existing: Option<ElementStyles>) -> Self {
|
||||
ElementData {
|
||||
styles: existing,
|
||||
restyle: None,
|
||||
restyle: RestyleData::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +508,7 @@ impl ElementData {
|
|||
|
||||
/// Returns whether we have any outstanding style invalidation.
|
||||
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
|
||||
|
@ -465,10 +525,7 @@ impl ElementData {
|
|||
return RestyleKind::MatchAndCascade;
|
||||
}
|
||||
|
||||
debug_assert!(self.restyle.is_some());
|
||||
let restyle_data = self.restyle.as_ref().unwrap();
|
||||
|
||||
let hint = restyle_data.hint;
|
||||
let hint = self.restyle.hint;
|
||||
if shared_context.traversal_flags.for_animation_only() {
|
||||
// return either CascadeWithReplacements or CascadeOnly in case of
|
||||
// animation-only restyle.
|
||||
|
@ -488,7 +545,8 @@ impl ElementData {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -513,13 +571,6 @@ impl 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.
|
||||
pub fn set_styles(&mut self, styles: ElementStyles) {
|
||||
self.styles = Some(styles);
|
||||
|
@ -558,47 +609,9 @@ impl ElementData {
|
|||
important_rules != other_important_rules
|
||||
}
|
||||
|
||||
/// Returns true if the Element has a RestyleData.
|
||||
pub fn has_restyle(&self) -> bool {
|
||||
self.restyle.is_some()
|
||||
}
|
||||
|
||||
/// 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")
|
||||
/// Drops any restyle state from the element.
|
||||
pub fn clear_restyle_state(&mut self) {
|
||||
self.restyle.clear();
|
||||
}
|
||||
|
||||
/// Returns SMIL overriden value if exists.
|
||||
|
|
|
@ -567,8 +567,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint());
|
||||
return data.restyle.hint.has_animation_hint()
|
||||
}
|
||||
|
||||
/// 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
|
||||
// changes as well that imply additional hints.
|
||||
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();
|
||||
|
@ -211,7 +211,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
|||
|
||||
if invalidated_self {
|
||||
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 {
|
||||
None => return false,
|
||||
Some(ref data) => {
|
||||
if let Some(restyle) = data.get_restyle() {
|
||||
if restyle.hint.contains_subtree() {
|
||||
if data.restyle.hint.contains_subtree() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut sibling_invalidations = InvalidationVector::new();
|
||||
|
||||
|
@ -494,7 +492,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
|||
|
||||
if invalidated_self {
|
||||
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 {
|
||||
debug!("process_invalidations: fully_invalid({:?})",
|
||||
element);
|
||||
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
||||
data.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -165,19 +165,17 @@ impl StylesheetInvalidationSet {
|
|||
return false;
|
||||
}
|
||||
|
||||
if let Some(ref r) = data.get_restyle() {
|
||||
if r.hint.contains_subtree() {
|
||||
if data.restyle.hint.contains_subtree() {
|
||||
debug!("process_invalidations_in_subtree: {:?} was already invalid",
|
||||
element);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for scope in &self.invalid_scopes {
|
||||
if scope.matches(element) {
|
||||
debug!("process_invalidations_in_subtree: {:?} matched {:?}",
|
||||
element, scope);
|
||||
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree());
|
||||
data.restyle.hint.insert(RestyleHint::restyle_subtree());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -707,8 +707,7 @@ trait PrivateMatchMethods: TElement {
|
|||
// for followup work to make the optimization here more optimal by considering
|
||||
// each bit individually.
|
||||
let skip_applying_damage =
|
||||
restyle.damage.contains(RestyleDamage::reconstruct()) ||
|
||||
restyle.reconstructed_ancestor;
|
||||
restyle.reconstructed_self_or_ancestor();
|
||||
|
||||
let difference = self.compute_style_difference(&old_values,
|
||||
&new_values,
|
||||
|
@ -1187,12 +1186,10 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
});
|
||||
|
||||
if matches_different_pseudos {
|
||||
if let Some(r) = data.get_restyle_mut() {
|
||||
if matches_different_pseudos && data.restyle.is_restyle() {
|
||||
// Any changes to the matched pseudo-elements trigger
|
||||
// reconstruction.
|
||||
r.damage |= RestyleDamage::reconstruct();
|
||||
}
|
||||
data.restyle.damage |= RestyleDamage::reconstruct();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1257,16 +1254,11 @@ pub trait MatchMethods : TElement {
|
|||
/// Computes and applies restyle damage.
|
||||
fn accumulate_damage(&self,
|
||||
shared_context: &SharedStyleContext,
|
||||
restyle: Option<&mut RestyleData>,
|
||||
restyle: &mut RestyleData,
|
||||
old_values: Option<&ComputedValues>,
|
||||
new_values: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>)
|
||||
-> ChildCascadeRequirement {
|
||||
let restyle = match restyle {
|
||||
Some(r) => r,
|
||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||
};
|
||||
|
||||
let old_values = match old_values {
|
||||
Some(v) => v,
|
||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||
|
|
|
@ -377,10 +377,10 @@ impl<E: TElement> StyleSharingTarget<E> {
|
|||
// We used to have pseudos (because we had styles).
|
||||
// Check for damage from the set of pseudos changing or
|
||||
// pseudos being restyled.
|
||||
let (styles, restyle_data) = data.styles_and_restyle_mut();
|
||||
if let Some(restyle_data) = restyle_data {
|
||||
let (styles, mut restyle_data) = data.styles_and_restyle_mut();
|
||||
let old_pseudos = &styles.pseudos;
|
||||
let new_pseudos = &shared_style.pseudos;
|
||||
|
||||
if !old_pseudos.has_same_pseudos_as(new_pseudos) {
|
||||
restyle_data.damage |= RestyleDamage::reconstruct();
|
||||
} else {
|
||||
|
@ -394,7 +394,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
|||
new_pseudos.get(&pseudo).unwrap().values();
|
||||
self.element.accumulate_damage(
|
||||
&shared_context,
|
||||
Some(restyle_data),
|
||||
restyle_data,
|
||||
old_values,
|
||||
new_values,
|
||||
Some(&pseudo)
|
||||
|
@ -402,13 +402,13 @@ impl<E: TElement> StyleSharingTarget<E> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let old_values = data.get_styles_mut()
|
||||
.and_then(|s| s.primary.values.take());
|
||||
let old_values =
|
||||
data.get_styles_mut().and_then(|s| s.primary.values.take());
|
||||
|
||||
self.element.accumulate_damage(
|
||||
&shared_context,
|
||||
data.get_restyle_mut(),
|
||||
&mut data.restyle,
|
||||
old_values.as_ref().map(|v| &**v),
|
||||
shared_style.primary.values(),
|
||||
None
|
||||
|
@ -597,9 +597,6 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
|
|||
match sharing_result {
|
||||
Ok(shared_style) => {
|
||||
// Yay, cache hit. Share the style.
|
||||
|
||||
debug_assert_eq!(data.has_styles(), data.has_restyle());
|
||||
|
||||
let child_cascade_requirement =
|
||||
target.accumulate_damage_when_sharing(shared_context,
|
||||
&shared_style,
|
||||
|
|
|
@ -10,7 +10,6 @@ use data::{ElementData, ElementStyles};
|
|||
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
||||
use invalidation::element::restyle_hints::{RECASCADE_SELF, RECASCADE_DESCENDANTS, RestyleHint};
|
||||
use matching::{ChildCascadeRequirement, MatchMethods};
|
||||
use selector_parser::RestyleDamage;
|
||||
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
||||
#[cfg(feature = "servo")] use servo_config::opts;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -296,10 +295,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
if el.is_native_anonymous() {
|
||||
if let Some(parent) = el.traversal_parent() {
|
||||
let parent_data = parent.borrow_data().unwrap();
|
||||
let going_to_reframe = parent_data.get_restyle().map_or(false, |r| {
|
||||
r.reconstructed_ancestor ||
|
||||
r.damage.contains(RestyleDamage::reconstruct())
|
||||
});
|
||||
let going_to_reframe =
|
||||
parent_data.restyle.reconstructed_self_or_ancestor();
|
||||
|
||||
let mut is_before_or_after_pseudo = false;
|
||||
if let Some(pseudo) = el.implemented_pseudo_element() {
|
||||
|
@ -337,9 +334,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint() ||
|
||||
r.hint.has_recascade_self());
|
||||
return data.restyle.hint.has_animation_hint() ||
|
||||
data.restyle.hint.has_recascade_self();
|
||||
}
|
||||
|
||||
// If the dirty descendants bit is set, we need to traverse no
|
||||
|
@ -360,8 +356,6 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
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
|
||||
// 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
|
||||
// indicating that the element's descendants (but not necessarily
|
||||
// the element) need restyling.
|
||||
if !r.hint.is_empty() {
|
||||
if !data.restyle.hint.is_empty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Servo uses the post-order traversal for flow construction, so
|
||||
// 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
|
||||
// restyle data, so that this damage can be cleared.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// those operations and compute the propagated restyle hint.
|
||||
let mut propagated_hint = match data.get_restyle_mut() {
|
||||
None => RestyleHint::empty(),
|
||||
Some(r) => {
|
||||
let mut propagated_hint = {
|
||||
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-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
|
||||
// somewhere.
|
||||
propagated_hint.insert(hint.into());
|
||||
propagated_hint.insert(hint);
|
||||
|
||||
trace!("propagated_hint={:?} \
|
||||
is_display_none={:?}, implementing_pseudo={:?}",
|
||||
|
@ -730,10 +720,9 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
|||
DontLog) &&
|
||||
(has_dirty_descendants_for_this_restyle ||
|
||||
!propagated_hint.is_empty()) {
|
||||
let reconstructed_ancestor = data.get_restyle().map_or(false, |r| {
|
||||
r.reconstructed_ancestor ||
|
||||
r.damage.contains(RestyleDamage::reconstruct())
|
||||
});
|
||||
let reconstructed_ancestor =
|
||||
data.restyle.reconstructed_self_or_ancestor();
|
||||
|
||||
preprocess_children::<E, D>(
|
||||
context,
|
||||
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
|
||||
// any change hints.
|
||||
if context.shared.traversal_flags.for_reconstruct() {
|
||||
data.clear_restyle();
|
||||
data.clear_restyle_state();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if data.has_styles() {
|
||||
data.restyle.set_restyled();
|
||||
}
|
||||
|
||||
match kind {
|
||||
MatchAndCascade => {
|
||||
debug_assert!(!context.shared.traversal_flags.for_animation_only(),
|
||||
|
@ -870,31 +863,24 @@ where
|
|||
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: {:?}",
|
||||
child,
|
||||
child_data.get_restyle().map(|r| &r.hint),
|
||||
child_data.restyle.hint,
|
||||
propagated_hint,
|
||||
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
|
||||
// subtree.
|
||||
restyle_data.reconstructed_ancestor = reconstructed_ancestor;
|
||||
restyle_data.hint.insert(propagated_hint);
|
||||
if reconstructed_ancestor {
|
||||
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;
|
||||
}
|
||||
|
||||
element.has_dirty_descendants() || element.borrow_data().unwrap().has_restyle()
|
||||
element.has_dirty_descendants() || element.borrow_data().unwrap().restyle.contains_restyle_data()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -2461,7 +2461,7 @@ unsafe fn maybe_restyle<'a>(data: &'a mut AtomicRefMut<ElementData>,
|
|||
bindings::Gecko_SetOwnerDocumentNeedsStyleFlush(element.0);
|
||||
|
||||
// Ensure and return the RestyleData.
|
||||
Some(data.ensure_restyle())
|
||||
Some(&mut data.restyle)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -2518,13 +2518,16 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
|
|||
pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint
|
||||
{
|
||||
let element = GeckoElement(element);
|
||||
let damage = if let Some(mut data) = element.mutate_data() {
|
||||
let d = data.get_restyle().map_or(GeckoRestyleDamage::empty(), |r| r.damage);
|
||||
data.clear_restyle();
|
||||
d
|
||||
} else {
|
||||
let damage = match element.mutate_data() {
|
||||
Some(mut data) => {
|
||||
let damage = data.restyle.damage;
|
||||
data.clear_restyle_state();
|
||||
damage
|
||||
}
|
||||
None => {
|
||||
warn!("Trying to get change hint from unstyled element");
|
||||
GeckoRestyleDamage::empty()
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
|
||||
|
|
|
@ -7,7 +7,7 @@ use servo_arc::Arc;
|
|||
use std::mem::{size_of, align_of};
|
||||
use style;
|
||||
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::properties::ComputedValues;
|
||||
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_element_styles, ElementStyles, 48);
|
||||
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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue