diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2016-11-02 18:46:04 -0700 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2016-11-07 11:10:48 -0800 |
commit | a2c7a9d0fb7174f9188640ba2fb5a3df7821c1a8 (patch) | |
tree | 8fe3228394856e7f55053c3399e2887a64d263e8 /components/style | |
parent | b69fdad8e44d77b5a946ee4155ab3da3320d93cd (diff) | |
download | servo-a2c7a9d0fb7174f9188640ba2fb5a3df7821c1a8.tar.gz servo-a2c7a9d0fb7174f9188640ba2fb5a3df7821c1a8.zip |
Stop using associated types for the concrete TRestyleDamage implementation.
MozReview-Commit-ID: LfaZFCVlIb1
Diffstat (limited to 'components/style')
-rw-r--r-- | components/style/dom.rs | 7 | ||||
-rw-r--r-- | components/style/gecko/mod.rs | 1 | ||||
-rw-r--r-- | components/style/gecko/restyle_damage.rs | 53 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 45 | ||||
-rw-r--r-- | components/style/lib.rs | 2 | ||||
-rw-r--r-- | components/style/matching.rs | 34 | ||||
-rw-r--r-- | components/style/selector_impl.rs | 12 | ||||
-rw-r--r-- | components/style/servo/mod.rs | 6 | ||||
-rw-r--r-- | components/style/servo/restyle_damage.rs | 267 | ||||
-rw-r--r-- | components/style/servo/selector_impl.rs (renamed from components/style/servo_selector_impl.rs) | 0 |
10 files changed, 358 insertions, 69 deletions
diff --git a/components/style/dom.rs b/components/style/dom.rs index 493a38bdc59..388a7310ab0 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -14,7 +14,7 @@ use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::longhands::display::computed_value as display; use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; -use selector_impl::{ElementExt, PseudoElement, Snapshot}; +use selector_impl::{ElementExt, PseudoElement, RestyleDamage, Snapshot}; use selector_matching::ApplicableDeclarationBlock; use sink::Push; use std::fmt::Debug; @@ -173,7 +173,6 @@ pub trait PresentationalHintsSynthetizer { pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>; type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>; - type ConcreteRestyleDamage: TRestyleDamage; fn as_node(&self) -> Self::ConcreteNode; @@ -185,7 +184,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre fn attr_equals(&self, namespace: &Namespace, attr: &LocalName, value: &Atom) -> bool; /// Set the restyle damage field. - fn set_restyle_damage(self, damage: Self::ConcreteRestyleDamage); + fn set_restyle_damage(self, damage: RestyleDamage); /// XXX: It's a bit unfortunate we need to pass the current computed values /// as an argument here, but otherwise Servo would crash due to double @@ -193,7 +192,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre fn existing_style_for_restyle_damage<'a>(&'a self, current_computed_values: Option<&'a Arc<ComputedValues>>, pseudo: Option<&PseudoElement>) - -> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage>::PreExistingComputedValues>; + -> Option<&'a <RestyleDamage as TRestyleDamage>::PreExistingComputedValues>; /// The concept of a dirty bit doesn't exist in our new restyle algorithm. /// Instead, we associate restyle and change hints with nodes. However, we diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index 7153a7e3da2..ee462ef4b81 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -5,6 +5,7 @@ pub mod context; pub mod data; +pub mod restyle_damage; pub mod snapshot; pub mod snapshot_helpers; pub mod traversal; diff --git a/components/style/gecko/restyle_damage.rs b/components/style/gecko/restyle_damage.rs new file mode 100644 index 00000000000..ed23bb15062 --- /dev/null +++ b/components/style/gecko/restyle_damage.rs @@ -0,0 +1,53 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use dom::TRestyleDamage; +use gecko_bindings::bindings; +use gecko_bindings::structs::{nsChangeHint, nsStyleContext}; +use gecko_bindings::sugar::ownership::FFIArcHelpers; +use properties::ComputedValues; +use std::ops::BitOr; +use std::sync::Arc; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct GeckoRestyleDamage(nsChangeHint); + +impl GeckoRestyleDamage { + pub fn as_change_hint(&self) -> nsChangeHint { + self.0 + } +} + +impl TRestyleDamage for GeckoRestyleDamage { + type PreExistingComputedValues = nsStyleContext; + + fn empty() -> Self { + use std::mem; + GeckoRestyleDamage(unsafe { mem::transmute(0u32) }) + } + + fn compute(source: &nsStyleContext, + new_style: &Arc<ComputedValues>) -> Self { + let context = source as *const nsStyleContext as *mut nsStyleContext; + let hint = unsafe { + bindings::Gecko_CalcStyleDifference(context, + new_style.as_borrowed_opt().unwrap()) + }; + GeckoRestyleDamage(hint) + } + + fn rebuild_and_reflow() -> Self { + GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame) + } +} + +impl BitOr for GeckoRestyleDamage { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + use std::mem; + GeckoRestyleDamage(unsafe { mem::transmute(self.0 as u32 | other.0 as u32) }) + } +} + diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 4da1e1af4f9..9adac5f269f 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -7,15 +7,15 @@ use atomic_refcell::{AtomicRef, AtomicRefCell}; use data::ElementData; -use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; +use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; +use gecko::restyle_damage::GeckoRestyleDamage; use gecko::selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot::GeckoElementSnapshot; use gecko::snapshot_helpers; use gecko_bindings::bindings; -use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference}; use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator}; use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement}; use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild}; @@ -26,10 +26,10 @@ use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode}; use gecko_bindings::bindings::Gecko_ClassOrClassList; use gecko_bindings::bindings::Gecko_GetStyleContext; use gecko_bindings::bindings::Gecko_SetNodeFlags; +use gecko_bindings::bindings::Gecko_StoreStyleDifference; use gecko_bindings::structs; use gecko_bindings::structs::{NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO, NODE_IS_DIRTY_FOR_SERVO}; -use gecko_bindings::structs::{nsChangeHint, nsIAtom, nsIContent, nsStyleContext}; -use gecko_bindings::sugar::ownership::FFIArcHelpers; +use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext}; use libc::uintptr_t; use parking_lot::RwLock; use parser::ParserContextExtraData; @@ -41,7 +41,6 @@ use selectors::Element; use selectors::parser::{AttrSelector, NamespaceConstraint}; use sink::Push; use std::fmt; -use std::ops::BitOr; use std::ptr; use std::sync::Arc; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; @@ -66,39 +65,6 @@ impl<'ln> GeckoNode<'ln> { } } -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct GeckoRestyleDamage(nsChangeHint); - -impl TRestyleDamage for GeckoRestyleDamage { - type PreExistingComputedValues = nsStyleContext; - - fn empty() -> Self { - use std::mem; - GeckoRestyleDamage(unsafe { mem::transmute(0u32) }) - } - - fn compute(source: &nsStyleContext, - new_style: &Arc<ComputedValues>) -> Self { - let context = source as *const nsStyleContext as *mut nsStyleContext; - let hint = unsafe { Gecko_CalcStyleDifference(context, new_style.as_borrowed_opt().unwrap()) }; - GeckoRestyleDamage(hint) - } - - fn rebuild_and_reflow() -> Self { - GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame) - } -} - -impl BitOr for GeckoRestyleDamage { - type Output = Self; - - fn bitor(self, other: Self) -> Self { - use std::mem; - GeckoRestyleDamage(unsafe { mem::transmute(self.0 as u32 | other.0 as u32) }) - } -} - - impl<'ln> NodeInfo for GeckoNode<'ln> { fn is_element(&self) -> bool { use gecko_bindings::structs::nsINode_BooleanFlag; @@ -358,7 +324,6 @@ lazy_static! { impl<'le> TElement for GeckoElement<'le> { type ConcreteNode = GeckoNode<'le>; type ConcreteDocument = GeckoDocument<'le>; - type ConcreteRestyleDamage = GeckoRestyleDamage; fn as_node(&self) -> Self::ConcreteNode { unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } @@ -400,7 +365,7 @@ impl<'le> TElement for GeckoElement<'le> { // drive the post-traversal. This will go away soon. unsafe { self.set_flags(NODE_IS_DIRTY_FOR_SERVO as u32) } - unsafe { Gecko_StoreStyleDifference(self.as_node().0, damage.0) } + unsafe { Gecko_StoreStyleDifference(self.as_node().0, damage.as_change_hint()) } } fn existing_style_for_restyle_damage<'a>(&'a self, diff --git a/components/style/lib.rs b/components/style/lib.rs index c6010def374..d7312bbb904 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -117,8 +117,8 @@ pub mod restyle_hints; pub mod rule_tree; pub mod selector_impl; pub mod selector_matching; +#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo; pub mod sequential; -#[cfg(feature = "servo")] pub mod servo_selector_impl; pub mod sink; pub mod str; pub mod stylesheets; diff --git a/components/style/matching.rs b/components/style/matching.rs index ac4bdb0b59a..97faf4d0a6a 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -17,7 +17,7 @@ use dom::{TElement, TNode, TRestyleDamage, UnsafeNode}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade}; use properties::longhands::display::computed_value as display; use rule_tree::StrongRuleNode; -use selector_impl::{TheSelectorImpl, PseudoElement}; +use selector_impl::{PseudoElement, RestyleDamage, TheSelectorImpl}; use selector_matching::{ApplicableDeclarationBlock, Stylist}; use selectors::MatchAttr; use selectors::bloom::BloomFilter; @@ -373,14 +373,14 @@ impl StyleSharingCandidateCache { } /// The results of attempting to share a style. -pub enum StyleSharingResult<ConcreteRestyleDamage: TRestyleDamage> { +pub enum StyleSharingResult { /// We didn't find anybody to share the style with. CannotShare, /// The node's style can be shared. The integer specifies the index in the /// LRU cache that was hit and the damage that was done, and the restyle /// result the original result of the candidate's styling, that is, whether /// it should stop the traversal or not. - StyleWasShared(usize, ConcreteRestyleDamage), + StyleWasShared(usize, RestyleDamage), } // Callers need to pass several boolean flags to cascade_node_pseudo_element. @@ -565,7 +565,7 @@ pub trait MatchMethods : TElement { &mut StyleSharingCandidateCache, shared_context: &SharedStyleContext, data: &mut AtomicRefMut<ElementData>) - -> StyleSharingResult<Self::ConcreteRestyleDamage> { + -> StyleSharingResult { if opts::get().disable_share_style_cache { return StyleSharingResult::CannotShare } @@ -591,12 +591,8 @@ pub trait MatchMethods : TElement { // replaced content, or similar stuff! let damage = match self.existing_style_for_restyle_damage(data.previous_styles().map(|x| &x.primary), None) { - Some(ref source) => { - Self::ConcreteRestyleDamage::compute(source, &shared_style) - } - None => { - Self::ConcreteRestyleDamage::rebuild_and_reflow() - } + Some(ref source) => RestyleDamage::compute(source, &shared_style), + None => RestyleDamage::rebuild_and_reflow(), }; data.finish_styling(ElementStyles::new(shared_style, rule_node)); @@ -678,13 +674,10 @@ pub trait MatchMethods : TElement { old_style: Option<&Arc<ComputedValues>>, new_style: &Arc<ComputedValues>, pseudo: Option<&PseudoElement>) - -> Self::ConcreteRestyleDamage + -> RestyleDamage { match self.existing_style_for_restyle_damage(old_style, pseudo) { - Some(ref source) => { - Self::ConcreteRestyleDamage::compute(source, - new_style) - } + Some(ref source) => RestyleDamage::compute(source, new_style), None => { // If there's no style source, two things can happen: // @@ -710,7 +703,7 @@ pub trait MatchMethods : TElement { // stick without the assertions. debug_assert!(pseudo.is_none() || new_style.get_box().clone_display() != display::T::none); - Self::ConcreteRestyleDamage::rebuild_and_reflow() + RestyleDamage::rebuild_and_reflow() } } } @@ -783,7 +776,7 @@ pub trait MatchMethods : TElement { new_pseudos: &mut PseudoStyles, context: &Ctx, applicable_declarations: &mut ApplicableDeclarations) - -> Self::ConcreteRestyleDamage + -> RestyleDamage where Ctx: StyleContext<'a> { // Here we optimise the case of the style changing but both the @@ -800,9 +793,9 @@ pub trait MatchMethods : TElement { // otherwise, we don't do anything. let damage = match old_display { Some(display) if display == this_display => { - Self::ConcreteRestyleDamage::empty() + RestyleDamage::empty() } - _ => Self::ConcreteRestyleDamage::rebuild_and_reflow() + _ => RestyleDamage::rebuild_and_reflow() }; debug!("Short-circuiting traversal: {:?} {:?} {:?}", @@ -820,8 +813,7 @@ pub trait MatchMethods : TElement { return damage; } - let rebuild_and_reflow = - Self::ConcreteRestyleDamage::rebuild_and_reflow(); + let rebuild_and_reflow = RestyleDamage::rebuild_and_reflow(); debug_assert!(new_pseudos.is_empty()); <Self as MatchAttr>::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index d4a7f2645b4..85734d51387 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -11,23 +11,29 @@ use selectors::parser::{AttrSelector, SelectorImpl}; pub type AttrValue = <TheSelectorImpl as SelectorImpl>::AttrValue; #[cfg(feature = "servo")] -pub use servo_selector_impl::*; +pub use servo::selector_impl::*; #[cfg(feature = "gecko")] pub use gecko::selector_impl::*; #[cfg(feature = "servo")] -pub use servo_selector_impl::ServoSelectorImpl as TheSelectorImpl; +pub use servo::selector_impl::ServoSelectorImpl as TheSelectorImpl; #[cfg(feature = "gecko")] pub use gecko::selector_impl::GeckoSelectorImpl as TheSelectorImpl; #[cfg(feature = "servo")] -pub use servo_selector_impl::ServoElementSnapshot as Snapshot; +pub use servo::selector_impl::ServoElementSnapshot as Snapshot; #[cfg(feature = "gecko")] pub use gecko::snapshot::GeckoElementSnapshot as Snapshot; +#[cfg(feature = "servo")] +pub use servo::restyle_damage::ServoRestyleDamage as RestyleDamage; + +#[cfg(feature = "gecko")] +pub use gecko::restyle_damage::GeckoRestyleDamage as RestyleDamage; + /// This function determines if a pseudo-element is eagerly cascaded or not. /// /// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e. diff --git a/components/style/servo/mod.rs b/components/style/servo/mod.rs new file mode 100644 index 00000000000..bd3db996eff --- /dev/null +++ b/components/style/servo/mod.rs @@ -0,0 +1,6 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +pub mod restyle_damage; +pub mod selector_impl; diff --git a/components/style/servo/restyle_damage.rs b/components/style/servo/restyle_damage.rs new file mode 100644 index 00000000000..08dd549b288 --- /dev/null +++ b/components/style/servo/restyle_damage.rs @@ -0,0 +1,267 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use computed_values::display; +use dom::TRestyleDamage; +use properties::ServoComputedValues; +use std::fmt; +use std::sync::Arc; + +bitflags! { + #[doc = "Individual layout actions that may be necessary after restyling."] + pub flags ServoRestyleDamage: u8 { + #[doc = "Repaint the node itself."] + #[doc = "Currently unused; need to decide how this propagates."] + const REPAINT = 0x01, + + #[doc = "The stacking-context-relative position of this node or its descendants has \ + changed."] + #[doc = "Propagates both up and down the flow tree."] + const REPOSITION = 0x02, + + #[doc = "Recompute the overflow regions (bounding box of object and all descendants)."] + #[doc = "Propagates down the flow tree because the computation is bottom-up."] + const STORE_OVERFLOW = 0x04, + + #[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."] + #[doc = "Propagates down the flow tree because the computation is"] + #[doc = "bottom-up."] + const BUBBLE_ISIZES = 0x08, + + #[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \ + into account. \ + Propagates up the flow tree because the computation is top-down."] + const REFLOW_OUT_OF_FLOW = 0x10, + + #[doc = "Recompute actual inline_sizes and block_sizes."] + #[doc = "Propagates up the flow tree because the computation is"] + #[doc = "top-down."] + const REFLOW = 0x20, + + #[doc = "Re-resolve generated content. \ + Propagates up the flow tree because the computation is inorder."] + const RESOLVE_GENERATED_CONTENT = 0x40, + + #[doc = "The entire flow needs to be reconstructed."] + const RECONSTRUCT_FLOW = 0x80 + } +} + +impl TRestyleDamage for ServoRestyleDamage { + /// For Servo the style source is always the computed values. + type PreExistingComputedValues = Arc<ServoComputedValues>; + + fn empty() -> Self { + ServoRestyleDamage::empty() + } + + fn compute(old: &Arc<ServoComputedValues>, + new: &Arc<ServoComputedValues>) -> ServoRestyleDamage { + compute_damage(old, new) + } + + /// Returns a bitmask that represents a flow that needs to be rebuilt and + /// reflowed. + /// + /// Use this instead of `ServoRestyleDamage::all()` because + /// `ServoRestyleDamage::all()` will result in unnecessary sequential resolution + /// of generated content. + fn rebuild_and_reflow() -> ServoRestyleDamage { + REPAINT | REPOSITION | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | + RECONSTRUCT_FLOW + } +} + +impl ServoRestyleDamage { + /// Supposing a flow has the given `position` property and this damage, + /// returns the damage that we should add to the *parent* of this flow. + pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> ServoRestyleDamage { + if child_is_absolutely_positioned { + self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | + RESOLVE_GENERATED_CONTENT) + } else { + self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW | + RESOLVE_GENERATED_CONTENT) + } + } + + /// Supposing the *parent* of a flow with the given `position` property has this damage, + /// returns the damage that we should add to this flow. + pub fn damage_for_child(self, + parent_is_absolutely_positioned: bool, + child_is_absolutely_positioned: bool) + -> ServoRestyleDamage { + match (parent_is_absolutely_positioned, child_is_absolutely_positioned) { + (false, true) => { + // Absolute children are out-of-flow and therefore insulated from changes. + // + // FIXME(pcwalton): Au contraire, if the containing block dimensions change! + self & (REPAINT | REPOSITION) + } + (true, false) => { + // Changing the position of an absolutely-positioned block requires us to reflow + // its kids. + if self.contains(REFLOW_OUT_OF_FLOW) { + self | REFLOW + } else { + self + } + } + _ => { + // TODO(pcwalton): Take floatedness into account. + self & (REPAINT | REPOSITION | REFLOW) + } + } + } +} + +impl fmt::Display for ServoRestyleDamage { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let mut first_elem = true; + + let to_iter = + [ (REPAINT, "Repaint") + , (REPOSITION, "Reposition") + , (STORE_OVERFLOW, "StoreOverflow") + , (BUBBLE_ISIZES, "BubbleISizes") + , (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow") + , (REFLOW, "Reflow") + , (RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent") + , (RECONSTRUCT_FLOW, "ReconstructFlow") + ]; + + for &(damage, damage_str) in &to_iter { + if self.contains(damage) { + if !first_elem { try!(write!(f, " | ")); } + try!(write!(f, "{}", damage_str)); + first_elem = false; + } + } + + if first_elem { + try!(write!(f, "NoDamage")); + } + + Ok(()) + } +} + +// NB: We need the braces inside the RHS due to Rust #8012. This particular +// version of this macro might be safe anyway, but we want to avoid silent +// breakage on modifications. +macro_rules! add_if_not_equal( + ($old:ident, $new:ident, $damage:ident, + [ $($effect:ident),* ], [ $($style_struct_getter:ident.$name:ident),* ]) => ({ + if $( ($old.$style_struct_getter().$name != $new.$style_struct_getter().$name) )||* { + $damage.insert($($effect)|*); + true + } else { + false + } + }) +); + +fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> ServoRestyleDamage { + let mut damage = ServoRestyleDamage::empty(); + + // This should check every CSS property, as enumerated in the fields of + // http://doc.servo.org/style/properties/struct.ServoComputedValues.html + + // FIXME: Test somehow that every property is included. + + add_if_not_equal!(old, new, damage, + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, + REFLOW, RECONSTRUCT_FLOW], [ + get_box.float, get_box.display, get_box.position, get_counters.content, + get_counters.counter_reset, get_counters.counter_increment, + get_inheritedbox._servo_under_display_none, + get_list.quotes, get_list.list_style_type, + + // If these text or font properties change, we need to reconstruct the flow so that + // text shaping is re-run. + get_inheritedtext.letter_spacing, get_inheritedtext.text_rendering, + get_inheritedtext.text_transform, get_inheritedtext.word_spacing, + get_inheritedtext.overflow_wrap, get_inheritedtext.text_justify, + get_inheritedtext.white_space, get_inheritedtext.word_break, get_text.text_overflow, + get_font.font_family, get_font.font_style, get_font.font_variant, get_font.font_weight, + get_font.font_size, get_font.font_stretch, + get_inheritedbox.direction, get_inheritedbox.writing_mode, + get_inheritedbox.text_orientation, + get_text.text_decoration, get_text.unicode_bidi, + get_inheritedtable.empty_cells, get_inheritedtable.caption_side, + get_column.column_width, get_column.column_count + ]) || (new.get_box().display == display::T::inline && + add_if_not_equal!(old, new, damage, + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, + REFLOW_OUT_OF_FLOW, REFLOW, RECONSTRUCT_FLOW], [ + // For inline boxes only, border/padding styles are used in flow construction (to decide + // whether to create fragments for empty flows). + get_border.border_top_width, get_border.border_right_width, + get_border.border_bottom_width, get_border.border_left_width, + get_padding.padding_top, get_padding.padding_right, + get_padding.padding_bottom, get_padding.padding_left + ])) || add_if_not_equal!(old, new, damage, + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, + REFLOW_OUT_OF_FLOW, REFLOW], + [get_border.border_top_width, get_border.border_right_width, + get_border.border_bottom_width, get_border.border_left_width, + get_margin.margin_top, get_margin.margin_right, + get_margin.margin_bottom, get_margin.margin_left, + get_padding.padding_top, get_padding.padding_right, + get_padding.padding_bottom, get_padding.padding_left, + get_position.width, get_position.height, + get_inheritedtext.line_height, + get_inheritedtext.text_align, get_inheritedtext.text_indent, + get_table.table_layout, + get_inheritedtable.border_collapse, + get_inheritedtable.border_spacing, + get_column.column_gap, + get_position.flex_direction, + get_position.flex_wrap, + get_position.justify_content, + get_position.align_items, + get_position.align_content, + get_position.order, + get_position.flex_basis, + get_position.flex_grow, + get_position.flex_shrink, + get_position.align_self + ]) || add_if_not_equal!(old, new, damage, + [REPAINT, REPOSITION, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW], [ + get_position.top, get_position.left, + get_position.right, get_position.bottom, + get_effects.opacity, + get_effects.transform, get_effects.transform_style, get_effects.transform_origin, + get_effects.perspective, get_effects.perspective_origin + ]) || add_if_not_equal!(old, new, damage, + [REPAINT], [ + get_color.color, get_background.background_color, + get_background.background_image, get_background.background_position, + get_background.background_repeat, get_background.background_attachment, + get_background.background_clip, get_background.background_origin, + get_background.background_size, + get_border.border_top_color, get_border.border_right_color, + get_border.border_bottom_color, get_border.border_left_color, + get_border.border_top_style, get_border.border_right_style, + get_border.border_bottom_style, get_border.border_left_style, + get_border.border_top_left_radius, get_border.border_top_right_radius, + get_border.border_bottom_left_radius, get_border.border_bottom_right_radius, + get_position.z_index, get_box._servo_overflow_clip_box, + get_inheritedtext._servo_text_decorations_in_effect, + get_pointing.cursor, get_pointing.pointer_events, + get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter, + get_effects.mix_blend_mode, get_inheritedbox.image_rendering, + + // Note: May require REFLOW et al. if `visibility: collapse` is implemented. + get_inheritedbox.visibility + ]); + + // If the layer requirements of this flow have changed due to the value + // of the transform, then reflow is required to rebuild the layers. + if old.transform_requires_layer() != new.transform_requires_layer() { + damage.insert(ServoRestyleDamage::rebuild_and_reflow()); + } + + damage +} diff --git a/components/style/servo_selector_impl.rs b/components/style/servo/selector_impl.rs index 9e5516da9cc..9e5516da9cc 100644 --- a/components/style/servo_selector_impl.rs +++ b/components/style/servo/selector_impl.rs |