From ce295f6daf78560b8e185ea07222834c6c0109a4 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 25 Jul 2017 18:45:37 -0700 Subject: [PATCH] Pass TraversalFlags from C++ into Rust. MozReview-Commit-ID: EVUzgnL5coN --- components/layout_thread/lib.rs | 3 +- components/style/context.rs | 3 +- components/style/dom.rs | 2 +- .../invalidation/element/restyle_hints.rs | 2 +- components/style/lib.rs | 1 + components/style/matching.rs | 7 +- components/style/traversal.rs | 58 +++-------------- components/style/traversal_flags.rs | 64 +++++++++++++++++++ ports/geckolib/glue.rs | 58 +++++++---------- 9 files changed, 107 insertions(+), 91 deletions(-) create mode 100644 components/style/traversal_flags.rs diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 576588abda8..9c02fc6c936 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -135,7 +135,8 @@ use style::stylesheets::{Origin, Stylesheet, StylesheetInDocument, UserAgentStyl use style::stylist::{ExtraStyleData, Stylist}; use style::thread_state; use style::timer::Timer; -use style::traversal::{DomTraversal, TraversalDriver, TraversalFlags}; +use style::traversal::{DomTraversal, TraversalDriver}; +use style::traversal_flags::TraversalFlags; /// Information needed by the layout thread. pub struct LayoutThread { diff --git a/components/style/context.rs b/components/style/context.rs index 5abad6c5e03..9393c3522d8 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -34,7 +34,8 @@ use stylist::Stylist; use thread_state; use time; use timer::Timer; -use traversal::{DomTraversal, TraversalFlags}; +use traversal::DomTraversal; +use traversal_flags::TraversalFlags; pub use selectors::matching::QuirksMode; diff --git a/components/style/dom.rs b/components/style/dom.rs index 58050757b30..f5afbde05dc 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -33,7 +33,7 @@ use std::hash::Hash; use std::ops::Deref; use stylist::Stylist; use thread_state; -use traversal::TraversalFlags; +use traversal_flags::TraversalFlags; pub use style_traits::UnsafeNode; diff --git a/components/style/invalidation/element/restyle_hints.rs b/components/style/invalidation/element/restyle_hints.rs index d846afa5e51..aac75ddea64 100644 --- a/components/style/invalidation/element/restyle_hints.rs +++ b/components/style/invalidation/element/restyle_hints.rs @@ -6,7 +6,7 @@ #[cfg(feature = "gecko")] use gecko_bindings::structs::nsRestyleHint; -use traversal::TraversalFlags; +use traversal_flags::TraversalFlags; bitflags! { /// The kind of restyle we need to do for a given element. diff --git a/components/style/lib.rs b/components/style/lib.rs index debcfd81676..aae19500a71 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -135,6 +135,7 @@ pub mod stylesheets; pub mod thread_state; pub mod timer; pub mod traversal; +pub mod traversal_flags; #[macro_use] #[allow(non_camel_case_types)] pub mod values; diff --git a/components/style/matching.rs b/components/style/matching.rs index ccd18f75f7b..13ade29e8c1 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -19,6 +19,7 @@ use rule_tree::{CascadeLevel, StrongRuleNode}; use selector_parser::{PseudoElement, RestyleDamage}; use selectors::matching::ElementSelectorFlags; use servo_arc::{Arc, ArcBorrow}; +use traversal_flags; /// Represents the result of comparing an element's old and new style. pub struct StyleDifference { @@ -172,7 +173,7 @@ trait PrivateMatchMethods: TElement { // running or not. // TODO: We should check which @keyframes changed/added/deleted // and update only animations corresponding to those @keyframes. - (context.shared.traversal_flags.for_css_rule_changes() && + (context.shared.traversal_flags.contains(traversal_flags::ForCSSRuleChanges) && has_new_animation_style) || !old_box_style.animations_equals(&new_box_style) || (old_display_style == display::T::none && @@ -302,7 +303,7 @@ trait PrivateMatchMethods: TElement { pseudo: Option<&PseudoElement>) -> ChildCascadeRequirement { // Don't accumulate damage if we're in a restyle for reconstruction. - if shared_context.traversal_flags.for_reconstruct() { + if shared_context.traversal_flags.contains(traversal_flags::ForReconstruct) { return ChildCascadeRequirement::MustCascadeChildren; } @@ -499,7 +500,7 @@ pub trait MatchMethods : TElement { } // Don't accumulate damage if we're in a restyle for reconstruction. - if context.shared.traversal_flags.for_reconstruct() { + if context.shared.traversal_flags.contains(traversal_flags::ForReconstruct) { return ChildCascadeRequirement::MustCascadeChildren; } diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 1f917aaee2a..988deb1a759 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -13,6 +13,7 @@ use sharing::StyleSharingTarget; use smallvec::SmallVec; use style_resolver::StyleResolverForElement; use stylist::RuleInclusion; +use traversal_flags::{TraversalFlags, self}; /// A per-traversal-level chunk of data. This is sent down by the traversal, and /// currently only holds the dom depth for the bloom filter. @@ -27,45 +28,6 @@ pub struct PerLevelTraversalData { pub current_dom_depth: usize, } -bitflags! { - /// Flags that control the traversal process. - pub flags TraversalFlags: u8 { - /// Traverse only unstyled children. - const UNSTYLED_CHILDREN_ONLY = 0x01, - /// Traverse only elements for animation restyles. - const ANIMATION_ONLY = 0x02, - /// Traverse without generating any change hints. - const FOR_RECONSTRUCT = 0x04, - /// Traverse triggered by CSS rule changes. - /// - /// Traverse and update all elements with CSS animations since - /// @keyframes rules may have changed - const FOR_CSS_RULE_CHANGES = 0x08, - } -} - -impl TraversalFlags { - /// Returns true if the traversal is for animation-only restyles. - pub fn for_animation_only(&self) -> bool { - self.contains(ANIMATION_ONLY) - } - - /// Returns true if the traversal is for unstyled children. - pub fn for_unstyled_children_only(&self) -> bool { - self.contains(UNSTYLED_CHILDREN_ONLY) - } - - /// Returns true if the traversal is for a frame reconstruction. - pub fn for_reconstruct(&self) -> bool { - self.contains(FOR_RECONSTRUCT) - } - - /// Returns true if the traversal is triggered by CSS rule changes. - pub fn for_css_rule_changes(&self) -> bool { - self.contains(FOR_CSS_RULE_CHANGES) - } -} - /// This structure exists to enforce that callers invoke pre_traverse, and also /// to pass information from the pre-traversal into the primary traversal. pub struct PreTraverseToken { @@ -208,12 +170,12 @@ pub trait DomTraversal : Sync { shared_context: &SharedStyleContext, traversal_flags: TraversalFlags ) -> PreTraverseToken { - debug_assert!(!(traversal_flags.for_reconstruct() && - traversal_flags.for_unstyled_children_only()), + debug_assert!(!(traversal_flags.contains(traversal_flags::ForReconstruct) && + traversal_flags.contains(traversal_flags::UnstyledChildrenOnly)), "must not specify FOR_RECONSTRUCT in combination with \ UNSTYLED_CHILDREN_ONLY"); - if traversal_flags.for_unstyled_children_only() { + if traversal_flags.contains(traversal_flags::UnstyledChildrenOnly) { if root.borrow_data().map_or(true, |d| d.has_styles() && d.styles.is_display_none()) { return PreTraverseToken { traverse: false, @@ -281,7 +243,7 @@ pub trait DomTraversal : Sync { return true; } - if traversal_flags.for_reconstruct() { + if traversal_flags.contains(traversal_flags::ForReconstruct) { return true; } @@ -358,7 +320,7 @@ pub trait DomTraversal : 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()) && + if (cfg!(feature = "servo") || traversal_flags.contains(traversal_flags::ForReconstruct)) && !data.restyle.damage.is_empty() { return true; } @@ -618,7 +580,7 @@ where !propagated_hint.is_empty() || context.thread_local.is_initial_style() || data.restyle.reconstructed_self() || - flags.for_reconstruct() || + flags.contains(traversal_flags::ForReconstruct) || is_servo_nonincremental_layout(); traverse_children = traverse_children && @@ -639,7 +601,7 @@ where // If we are in a restyle for reconstruction, drop the existing restyle // 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() { + if context.shared.traversal_flags.contains(traversal_flags::ForReconstruct) { data.clear_restyle_state(); } @@ -659,7 +621,7 @@ where // The second case is when we are in a restyle for reconstruction, where we // won't need to perform a post-traversal to pick up any change hints. if data.styles.is_display_none() || - context.shared.traversal_flags.for_reconstruct() { + context.shared.traversal_flags.contains(traversal_flags::ForReconstruct) { unsafe { element.unset_dirty_descendants(); } } @@ -822,7 +784,7 @@ where // If we are in a restyle for reconstruction, there is no need to // perform a post-traversal, so we don't need to set the dirty // descendants bit on the parent. - if !flags.for_reconstruct() && !is_initial_style { + if !flags.contains(traversal_flags::ForReconstruct) && !is_initial_style { if flags.for_animation_only() { unsafe { element.set_animation_only_dirty_descendants(); } } else { diff --git a/components/style/traversal_flags.rs b/components/style/traversal_flags.rs new file mode 100644 index 00000000000..3ec2486583e --- /dev/null +++ b/components/style/traversal_flags.rs @@ -0,0 +1,64 @@ +/* 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/. */ + +//! Flags that control the traversal process. +//! +//! We CamelCase rather than UPPER_CASING so that we can grep for the same +//! strings across gecko and servo. +#![allow(non_upper_case_globals)] + +bitflags! { + /// Flags that control the traversal process. + pub flags TraversalFlags: u32 { + /// Traverse only elements for animation restyles. + const AnimationOnly = 1 << 0, + /// Traverse and update all elements with CSS animations since + /// @keyframes rules may have changed. Triggered by CSS rule changes. + const ForCSSRuleChanges = 1 << 1, + /// Traverse only unstyled children of the root and their descendants. + const UnstyledChildrenOnly = 1 << 2, + /// FIXME(bholley): This will go away. + const ForReconstruct = 1 << 3, + /// FIXME(bholley): This will go away. + const ForNewlyBoundElement = 1 << 4, + /// FIXME(bholley): This will go away. + const ForThrottledAnimationFlush = 1 << 5, + } +} + +/// Asserts that all TraversalFlags flags have a matching ServoTraversalFlags value in gecko. +#[cfg(feature = "gecko")] +#[inline] +pub fn assert_traversal_flags_match() { + use gecko_bindings::structs; + + macro_rules! check_traversal_flags { + ( $( $a:ident => $b:ident ),*, ) => { + if cfg!(debug_assertions) { + let mut modes = TraversalFlags::all(); + $( + assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b)); + modes.remove($b); + )* + assert_eq!(modes, TraversalFlags::empty(), "all TraversalFlags bits should have an assertion"); + } + } + } + + check_traversal_flags! { + ServoTraversalFlags_AnimationOnly => AnimationOnly, + ServoTraversalFlags_ForCSSRuleChanges => ForCSSRuleChanges, + ServoTraversalFlags_UnstyledChildrenOnly => UnstyledChildrenOnly, + ServoTraversalFlags_ForReconstruct => ForReconstruct, + ServoTraversalFlags_ForNewlyBoundElement => ForNewlyBoundElement, + ServoTraversalFlags_ForThrottledAnimationFlush => ForThrottledAnimationFlush, + } +} + +impl TraversalFlags { + /// Returns true if the traversal is for animation-only restyles. + pub fn for_animation_only(&self) -> bool { + self.contains(AnimationOnly) + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 580d2503113..2f6f23d5f58 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -77,6 +77,7 @@ use style::gecko_bindings::structs::MallocSizeOf; use style::gecko_bindings::structs::RawGeckoGfxMatrix4x4; use style::gecko_bindings::structs::RawGeckoPresContextOwned; use style::gecko_bindings::structs::ServoElementSnapshotTable; +use style::gecko_bindings::structs::ServoTraversalFlags; use style::gecko_bindings::structs::StyleRuleInclusion; use style::gecko_bindings::structs::URLExtraData; use style::gecko_bindings::structs::nsCSSValueSharedList; @@ -92,7 +93,7 @@ use style::gecko_properties::{self, style_structs}; use style::invalidation::element::restyle_hints::{self, RestyleHint}; use style::media_queries::{MediaList, parse_media_query_list}; use style::parallel; -use style::parser::ParserContext; +use style::parser::{ParserContext, self}; use style::properties::{ComputedValues, Importance}; use style::properties::{IS_FIELDSET_CONTENT, LonghandIdSet}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyId, ShorthandId}; @@ -116,9 +117,9 @@ use style::stylesheets::supports_rule::parse_condition_or_declaration; use style::stylist::RuleInclusion; use style::thread_state; use style::timer::Timer; -use style::traversal::{ANIMATION_ONLY, DomTraversal, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT}; -use style::traversal::{TraversalDriver, TraversalFlags, UNSTYLED_CHILDREN_ONLY}; +use style::traversal::{DomTraversal, TraversalDriver}; use style::traversal::resolve_style; +use style::traversal_flags::{TraversalFlags, self}; use style::values::{CustomIdent, KeyframesName}; use style::values::animated::ToAnimatedZero; use style::values::computed::Context; @@ -140,8 +141,6 @@ static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData; #[no_mangle] pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { - use style::parser::assert_parsing_mode_match; - // Initialize logging. let mut builder = LogBuilder::new(); let default_level = if cfg!(debug_assertions) { "warn" } else { "error" }; @@ -155,7 +154,8 @@ pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { // Perform some debug-only runtime assertions. restyle_hints::assert_restyle_hints_match(); - assert_parsing_mode_match(); + parser::assert_parsing_mode_match(); + traversal_flags::assert_traversal_flags_match(); // Initialize some static data. gecko_properties::initialize(); @@ -259,32 +259,16 @@ fn traverse_subtree(element: GeckoElement, pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed, raw_data: RawServoStyleSetBorrowed, snapshots: *const ServoElementSnapshotTable, - root_behavior: structs::TraversalRootBehavior, - restyle_behavior: structs::TraversalRestyleBehavior) + raw_flags: ServoTraversalFlags) -> bool { - use self::structs::TraversalRestyleBehavior as Restyle; - use self::structs::TraversalRootBehavior as Root; + let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags); debug_assert!(!snapshots.is_null()); let element = GeckoElement(root); - debug!("Servo_TraverseSubtree: {:?} {:?}", element, restyle_behavior); - - let traversal_flags = match (root_behavior, restyle_behavior) { - (Root::Normal, Restyle::Normal) | - (Root::Normal, Restyle::ForNewlyBoundElement) | - (Root::Normal, Restyle::ForThrottledAnimationFlush) - => TraversalFlags::empty(), - (Root::UnstyledChildrenOnly, Restyle::Normal) | - (Root::UnstyledChildrenOnly, Restyle::ForNewlyBoundElement) - => UNSTYLED_CHILDREN_ONLY, - (Root::Normal, Restyle::ForCSSRuleChanges) => FOR_CSS_RULE_CHANGES, - (Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT, - _ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"), - }; // It makes no sense to do an animation restyle when we're restyling // newly-inserted content. - if !traversal_flags.contains(UNSTYLED_CHILDREN_ONLY) { + if !traversal_flags.contains(traversal_flags::UnstyledChildrenOnly) { let needs_animation_only_restyle = element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints(); @@ -292,12 +276,12 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed, if needs_animation_only_restyle { traverse_subtree(element, raw_data, - traversal_flags | ANIMATION_ONLY, + traversal_flags | traversal_flags::AnimationOnly, unsafe { &*snapshots }); } } - if restyle_behavior == Restyle::ForThrottledAnimationFlush { + if traversal_flags.contains(traversal_flags::ForThrottledAnimationFlush) { return element.has_animation_only_dirty_descendants() || element.borrow_data().unwrap().restyle.is_restyle(); } @@ -307,7 +291,7 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed, traversal_flags, unsafe { &*snapshots }); - if restyle_behavior == Restyle::ForNewlyBoundElement { + if traversal_flags.contains(traversal_flags::ForNewlyBoundElement) { // In this mode, we only ever restyle new elements, so there is no // need for a post-traversal, and the borrow_data().unwrap() call below // could panic, so we don't bother computing whether a post-traversal @@ -2767,9 +2751,10 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed, #[no_mangle] pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed, - restyle_behavior: structs::TraversalRestyleBehavior, + raw_flags: ServoTraversalFlags, was_restyled: *mut bool) -> nsChangeHint { + let flags = TraversalFlags::from_bits_truncate(raw_flags); let mut was_restyled = unsafe { was_restyled.as_mut().unwrap() }; let element = GeckoElement(element); @@ -2778,7 +2763,7 @@ pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed, *was_restyled = data.restyle.is_restyle(); let damage = data.restyle.damage; - if restyle_behavior == structs::TraversalRestyleBehavior::ForThrottledAnimationFlush { + if flags.contains(traversal_flags::ForThrottledAnimationFlush) { if !*was_restyled { // Don't touch elements if the element was not restyled // in throttled animation flush. @@ -2813,11 +2798,10 @@ pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed, #[no_mangle] pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed, _raw_data: RawServoStyleSetBorrowed, - restyle_behavior: structs::TraversalRestyleBehavior) + raw_flags: ServoTraversalFlags) -> ServoStyleContextStrong { - use self::structs::TraversalRestyleBehavior as Restyle; - + let flags = TraversalFlags::from_bits_truncate(raw_flags); let element = GeckoElement(element); debug!("Servo_ResolveStyle: {:?}", element); let data = @@ -2827,12 +2811,14 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed, assert!(data.has_styles(), "Resolving style on unstyled element"); // In the case where we process for throttled animation, there remaings // restyle hints other than animation hints. - let flags = if restyle_behavior == Restyle::ForThrottledAnimationFlush { - ANIMATION_ONLY + // + // FIXME(bholley): Unify these flags. + let assert_flags = if flags.contains(traversal_flags::ForThrottledAnimationFlush) { + traversal_flags::AnimationOnly } else { TraversalFlags::empty() }; - debug_assert!(element.has_current_styles_for_traversal(&*data, flags), + debug_assert!(element.has_current_styles_for_traversal(&*data, assert_flags), "Resolving style on {:?} without current styles: {:?}", element, data); data.styles.primary().clone().into() }