Bug 1384769 - Pass TraversalFlags from C++ into Rust. r=emilio
authorBobby Holley <bobbyholley@gmail.com>
Tue, 25 Jul 2017 18:45:37 -0700
changeset 420229 81049c04c4ad1731f36e63666dc1f5ffaf98149b
parent 420228 c510f3e6e17f76d274f3b59d2620150703f05e56
child 420230 b393ef5e7becd8c15d5faceba56c83233ee5aa7c
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1384769
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1384769 - Pass TraversalFlags from C++ into Rust. r=emilio MozReview-Commit-ID: EVUzgnL5coN
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/base/nsCSSFrameConstructor.cpp
layout/style/ServoBindingList.h
layout/style/ServoBindings.toml
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/ServoTypes.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -249,17 +249,17 @@ ServoRestyleManager::ClearRestyleStateFr
       if (n->IsElement()) {
         ClearRestyleStateFromSubtree(n->AsElement());
       }
     }
   }
 
   bool wasRestyled;
   Unused << Servo_TakeChangeHint(aElement,
-                                 TraversalRestyleBehavior::Normal,
+                                 ServoTraversalFlags::Empty,
                                  &wasRestyled);
   aElement->UnsetHasDirtyDescendantsForServo();
   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
 }
 
 /**
  * This struct takes care of encapsulating some common state that text nodes may
@@ -487,51 +487,51 @@ UpdateFramePseudoElementStyles(nsIFrame*
   }
 
   UpdateBackdropIfNeeded(
     aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
 }
 
 static inline bool
 NeedsToTraverseElementChildren(const Element& aParent,
-                               TraversalRestyleBehavior aRestyleBehavior)
+                               ServoTraversalFlags aFlags)
 {
   if (aParent.HasAnimationOnlyDirtyDescendantsForServo()) {
     return true;
   }
 
-  if (aRestyleBehavior != TraversalRestyleBehavior::ForThrottledAnimationFlush) {
+  if (!(aFlags & ServoTraversalFlags::ForThrottledAnimationFlush)) {
     return aParent.HasDirtyDescendantsForServo() ||
            aParent.HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   }
   return false;
 }
 
 bool
 ServoRestyleManager::ProcessPostTraversal(
   Element* aElement,
   ServoStyleContext* aParentContext,
   ServoRestyleState& aRestyleState,
-  TraversalRestyleBehavior aRestyleBehavior)
+  ServoTraversalFlags aFlags)
 {
   nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
 
   // NOTE(emilio): This is needed because for table frames the bit is set on the
   // table wrapper (which is the primary frame), not on the table itself.
   const bool isOutOfFlow =
     aElement->GetPrimaryFrame() &&
     aElement->GetPrimaryFrame()->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
 
   // Grab the change hint from Servo.
   // In case of flushing throttled animations, any restyle hints other than
   // animations are preserved since they are the hints which will be processed
   // in normal restyle later.
   bool wasRestyled;
   nsChangeHint changeHint = Servo_TakeChangeHint(aElement,
-                                                 aRestyleBehavior,
+                                                 aFlags,
                                                  &wasRestyled);
 
   // We should really fix the weird primary frame mapping for image maps
   // (bug 135040)...
   if (styleFrame && styleFrame->GetContent() != aElement) {
     MOZ_ASSERT(styleFrame->IsImageFrame());
     styleFrame = nullptr;
   }
@@ -599,17 +599,17 @@ ServoRestyleManager::ProcessPostTraversa
   // other elements without frames).
   ServoRestyleState& childrenRestyleState =
     thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
 
   RefPtr<ServoStyleContext> newContext = nullptr;
   if (wasRestyled && oldStyleContext) {
     MOZ_ASSERT(styleFrame || displayContentsNode);
     newContext =
-      aRestyleState.StyleSet().ResolveServoStyle(aElement, aRestyleBehavior);
+      aRestyleState.StyleSet().ResolveServoStyle(aElement, aFlags);
     MOZ_ASSERT(oldStyleContext->ComputedData() != newContext->ComputedData());
 
     newContext->ResolveSameStructsAs(oldStyleContext);
 
     // We want to walk all the continuations here, even the ones with different
     // styles.  In practice, the only reason we get continuations with different
     // styles here is ::first-line (::first-letter never affects element
     // styles).  But in that case, newContext is the right context for the
@@ -653,38 +653,38 @@ ServoRestyleManager::ProcessPostTraversa
     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
     // style or not, we need to call it *after* setting |newContext| to
     // |styleFrame| to ensure the animated transform has been removed first.
     AddLayerChangesForAnimation(
       styleFrame, aElement, aRestyleState.ChangeList());
   }
 
   const bool traverseElementChildren =
-    NeedsToTraverseElementChildren(*aElement, aRestyleBehavior);
+    NeedsToTraverseElementChildren(*aElement, aFlags);
   const bool descendantsNeedFrames =
     aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   const bool forThrottledAnimationFlush =
-    aRestyleBehavior == TraversalRestyleBehavior::ForThrottledAnimationFlush;
+    !!(aFlags & ServoTraversalFlags::ForThrottledAnimationFlush);
   const bool traverseTextChildren =
     wasRestyled || (!forThrottledAnimationFlush && descendantsNeedFrames);
   bool recreatedAnyContext = wasRestyled;
   if (traverseElementChildren || traverseTextChildren) {
     ServoStyleContext* upToDateContext =
       wasRestyled ? newContext : oldStyleContext;
 
     StyleChildrenIterator it(aElement);
     TextPostTraversalState textState(*upToDateContext,
                                      displayContentsNode && wasRestyled,
                                      childrenRestyleState);
     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
       if (traverseElementChildren && n->IsElement()) {
         recreatedAnyContext |= ProcessPostTraversal(n->AsElement(),
                                                     upToDateContext,
                                                     childrenRestyleState,
-                                                    aRestyleBehavior);
+                                                    aFlags);
       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
         recreatedAnyContext |= ProcessPostTraversalForText(n, textState);
       }
     }
   }
 
   // We want to update frame pseudo-element styles after we've traversed our
   // kids, because some of those updates (::first-line/::first-letter) need to
@@ -805,18 +805,17 @@ ServoRestyleManager::FrameForPseudoEleme
   }
 
   MOZ_CRASH("Unkown pseudo-element given to "
             "ServoRestyleManager::FrameForPseudoElement");
   return nullptr;
 }
 
 void
-ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
-                                                aRestyleBehavior)
+ServoRestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags)
 {
   MOZ_ASSERT(PresContext()->Document(), "No document?  Pshaw!");
   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
   MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?");
 
   if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) {
     // PresShell::FlushPendingNotifications doesn't early-return in the case
     // where the PreShell hasn't yet been initialized (and therefore we haven't
@@ -829,54 +828,55 @@ ServoRestyleManager::DoProcessPendingRes
   // Create a AnimationsWithDestroyedFrame during restyling process to
   // stop animations and transitions on elements that have no frame at the end
   // of the restyling process.
   AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this);
 
   ServoStyleSet* styleSet = StyleSet();
   nsIDocument* doc = PresContext()->Document();
   bool forThrottledAnimationFlush =
-    aRestyleBehavior == TraversalRestyleBehavior::ForThrottledAnimationFlush;
+    !!(aFlags & ServoTraversalFlags::ForThrottledAnimationFlush);
 
   // Ensure the refresh driver is active during traversal to avoid mutating
   // mActiveTimer and mMostRecentRefresh time.
   PresContext()->RefreshDriver()->MostRecentRefresh();
 
 
   // Perform the Servo traversal, and the post-traversal if required. We do this
   // in a loop because certain rare paths in the frame constructor (like
   // uninstalling XBL bindings) can trigger additional style validations.
   mInStyleRefresh = true;
   if (mHaveNonAnimationRestyles && !forThrottledAnimationFlush) {
     ++mAnimationGeneration;
   }
 
-  TraversalRestyleBehavior restyleBehavior = mRestyleForCSSRuleChanges
-    ? TraversalRestyleBehavior::ForCSSRuleChanges
-    : TraversalRestyleBehavior::Normal;
+  if (mRestyleForCSSRuleChanges) {
+    aFlags |= ServoTraversalFlags::ForCSSRuleChanges;
+  }
+
   while (forThrottledAnimationFlush
           ? styleSet->StyleDocumentForThrottledAnimationFlush()
-          : styleSet->StyleDocument(restyleBehavior)) {
+          : styleSet->StyleDocument(aFlags)) {
     if (!forThrottledAnimationFlush) {
       ClearSnapshots();
     }
 
     nsStyleChangeList currentChanges(StyleBackendType::Servo);
     bool anyStyleChanged = false;
 
     // Recreate style contexts, and queue up change hints (which also handle
     // lazy frame construction).
     {
       AutoRestyleTimelineMarker marker(
         mPresContext->GetDocShell(), forThrottledAnimationFlush);
       DocumentStyleRootIterator iter(doc);
       while (Element* root = iter.GetNextStyleRoot()) {
         ServoRestyleState state(*styleSet, currentChanges);
         anyStyleChanged |=
-          ProcessPostTraversal(root, nullptr, state, aRestyleBehavior);
+          ProcessPostTraversal(root, nullptr, state, aFlags);
       }
     }
 
     // Process the change hints.
     //
     // Unfortunately, the frame constructor can generate new change hints while
     // processing existing ones. We redirect those into a secondary queue and
     // iterate until there's nothing left.
@@ -936,29 +936,29 @@ ServoRestyleManager::DoProcessPendingRes
   //       |mAnimationsWithDestroyedFrame| is still valid.
   MOZ_ASSERT(mAnimationsWithDestroyedFrame);
   mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
 }
 
 void
 ServoRestyleManager::ProcessPendingRestyles()
 {
-  DoProcessPendingRestyles(TraversalRestyleBehavior::Normal);
+  DoProcessPendingRestyles(ServoTraversalFlags::Empty);
 }
 
 void
 ServoRestyleManager::UpdateOnlyAnimationStyles()
 {
   // Bug 1365855: We also need to implement this for SMIL.
   bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
   if (!doCSS) {
     return;
   }
 
-  DoProcessPendingRestyles(TraversalRestyleBehavior::ForThrottledAnimationFlush);
+  DoProcessPendingRestyles(ServoTraversalFlags::ForThrottledAnimationFlush);
 }
 
 void
 ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
                                          EventStates aChangedBits)
 {
   MOZ_ASSERT(!mInStyleRefresh);
 
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -186,17 +186,17 @@ private:
    * Returns whether any style did actually change. There may be cases where we
    * didn't need to change any style after all, for example, when a content
    * attribute changes that happens not to have any effect on the style of that
    * element or any descendant or sibling.
    */
   bool ProcessPostTraversal(Element* aElement,
                             ServoStyleContext* aParentContext,
                             ServoRestyleState& aRestyleState,
-                            TraversalRestyleBehavior aRestyleBehavior);
+                            ServoTraversalFlags aFlags);
 
   struct TextPostTraversalState;
   bool ProcessPostTraversalForText(nsIContent* aTextNode,
                                    TextPostTraversalState& aState);
 
   inline ServoStyleSet* StyleSet() const
   {
     MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
@@ -207,17 +207,17 @@ private:
 
   const SnapshotTable& Snapshots() const { return mSnapshots; }
   void ClearSnapshots();
   ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
   void TakeSnapshotForAttributeChange(mozilla::dom::Element* aElement,
                                       int32_t aNameSpaceID,
                                       nsIAtom* aAttribute);
 
-  void DoProcessPendingRestyles(TraversalRestyleBehavior aRestyleBehavior);
+  void DoProcessPendingRestyles(ServoTraversalFlags aFlags);
 
   // We use a separate data structure from nsStyleChangeList because we need a
   // frame to create nsStyleChangeList entries, and the primary frame may not be
   // attached yet.
   struct ReentrantChange {
     nsCOMPtr<nsIContent> mContent;
     nsChangeHint mHint;
   };
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2517,17 +2517,17 @@ nsCSSFrameConstructor::ConstructDocEleme
   // siblings.
   aDocElement->UnsetRestyleFlagsIfGecko();
 
   // --------- CREATE AREA OR BOX FRAME -------
   if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
     // NOTE(emilio): If the root has a non-null binding, we'll stop at the
     // document element and won't process any children, loading the bindings (or
     // failing to do so) will take care of the rest.
-    set->StyleDocument(TraversalRestyleBehavior::Normal);
+    set->StyleDocument(ServoTraversalFlags::Empty);
   }
 
   // FIXME: Should this use ResolveStyleContext?  (The calls in this
   // function are the only case in nsCSSFrameConstructor where we don't
   // do so for the construction of a style context for an element.)
   RefPtr<nsStyleContext> styleContext =
     mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
                                             nullptr,
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -497,22 +497,22 @@ SERVO_BINDING_FUNC(Servo_Initialize, voi
 SERVO_BINDING_FUNC(Servo_Shutdown, void)
 
 // Restyle and change hints.
 SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
                    nsRestyleHint restyle_hint, nsChangeHint change_hint)
 SERVO_BINDING_FUNC(Servo_TakeChangeHint,
                    nsChangeHint,
                    RawGeckoElementBorrowed element,
-                   mozilla::TraversalRestyleBehavior restyle_behavior,
+                   mozilla::ServoTraversalFlags flags,
                    bool* was_restyled)
 SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoStyleContextStrong,
                    RawGeckoElementBorrowed element,
                    RawServoStyleSetBorrowed set,
-                   mozilla::TraversalRestyleBehavior restyle_behavior)
+                   mozilla::ServoTraversalFlags flags)
 SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoStyleContextStrong,
                    RawGeckoElementBorrowed element,
                    mozilla::CSSPseudoElementType pseudo_type,
                    bool is_probe,
                    ServoStyleContextBorrowedOrNull inherited_style,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_SetExplicitStyle, void,
                    RawGeckoElementBorrowed element,
@@ -539,18 +539,17 @@ SERVO_BINDING_FUNC(Servo_ResolveStyleLaz
 
 // Use ServoStyleSet::PrepareAndTraverseSubtree instead of calling this
 // directly
 SERVO_BINDING_FUNC(Servo_TraverseSubtree,
                    bool,
                    RawGeckoElementBorrowed root,
                    RawServoStyleSetBorrowed set,
                    const mozilla::ServoElementSnapshotTable* snapshots,
-                   mozilla::TraversalRootBehavior root_behavior,
-                   mozilla::TraversalRestyleBehavior restyle_behavior)
+                   mozilla::ServoTraversalFlags flags)
 
 // Assert that the tree has no pending or unconsumed restyles.
 SERVO_BINDING_FUNC(Servo_AssertTreeIsClean, void, RawGeckoElementBorrowed root)
 
 // Checks whether the rule tree has crossed its threshold for unused rule nodes,
 // and if so, frees them.
 SERVO_BINDING_FUNC(Servo_MaybeGCRuleTree, void, RawServoStyleSetBorrowed set)
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -88,16 +88,17 @@ hide-types = [
 bitfield-enums = [
     "nsChangeHint",
     "nsRestyleHint",
 ]
 constified-enums = [
     "UpdateAnimationsTasks",
     "ParsingMode",
     "ThemeWidgetType",
+    "ServoTraversalFlags",
 ]
 constified-enum-variants = [
     { enum = "nsCSSPropertyID", variants = ["eCSSProperty_COUNT.*"] },
 ]
 whitelist-vars = [
     "NS_AUTHOR_SPECIFIED_.*",
     "NS_THEME_.*",
     "NODE_.*",
@@ -127,18 +128,17 @@ whitelist-types = [
     "mozilla::CSSPseudoClassType",
     "mozilla::css::ErrorReporter",
     "mozilla::css::SheetParsingMode",
     "mozilla::css::URLMatchingFunction",
     "mozilla::dom::IterationCompositeOperation",
     "mozilla::dom::StyleChildrenIterator",
     "mozilla::HalfCorner",
     "mozilla::PropertyStyleAnimationValuePair",
-    "mozilla::TraversalRestyleBehavior",
-    "mozilla::TraversalRootBehavior",
+    "mozilla::ServoTraversalFlags",
     "mozilla::StyleShapeRadius",
     "mozilla::StyleGrid.*",
     "mozilla::UpdateAnimationsTasks",
     "mozilla::LookAndFeel",
     "mozilla::gfx::Float",
     "mozilla::gfx::FontVariation",
     ".*ThreadSafe.*Holder",
     "AnonymousContent",
@@ -381,18 +381,17 @@ structs-types = [
     "RawGeckoStyleAnimationList",
     "RawGeckoStyleChildrenIteratorBorrowedMut",
     "RawGeckoServoStyleRuleList",
     "RawGeckoURLExtraData",
     "RawGeckoXBLBinding",
     "RefPtr",
     "CSSPseudoClassType",
     "CSSPseudoElementType",
-    "TraversalRestyleBehavior",
-    "TraversalRootBehavior",
+    "ServoTraversalFlags",
     "ComputedTimingFunction_BeforeFlag",
     "CounterStylePtr",
     "FontFamilyList",
     "FontFamilyType",
     "FontSizePrefs",
     "GeckoFontMetrics",
     "IterationCompositeOperation",
     "Keyframe",
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -177,17 +177,17 @@ ServoStyleSet::ResolveStyleFor(Element* 
 {
   RefPtr<ServoStyleContext> computedValues;
   if (aMayCompute == LazyComputeBehavior::Allow) {
     PreTraverseSync();
     return ResolveStyleLazily(
         aElement, CSSPseudoElementType::NotPseudo, nullptr, aParentContext);
   }
 
-  return ResolveServoStyle(aElement, TraversalRestyleBehavior::Normal);
+  return ResolveServoStyle(aElement, ServoTraversalFlags::Empty);
 }
 
 
 const ServoElementSnapshotTable&
 ServoStyleSet::Snapshots()
 {
   return mPresContext->RestyleManager()->AsServo()->Snapshots();
 }
@@ -265,44 +265,41 @@ ServoStyleSet::PreTraverse(Element* aRoo
       smilController->PreTraverse();
     }
   }
 }
 
 bool
 ServoStyleSet::PrepareAndTraverseSubtree(
   RawGeckoElementBorrowed aRoot,
-  TraversalRootBehavior aRootBehavior,
-  TraversalRestyleBehavior aRestyleBehavior)
+  ServoTraversalFlags aFlags)
 {
   bool forThrottledAnimationFlush =
-    aRestyleBehavior == TraversalRestyleBehavior::ForThrottledAnimationFlush;
+    !!(aFlags & ServoTraversalFlags::ForThrottledAnimationFlush);
 
   AutoRestyleTimelineMarker marker(
     mPresContext->GetDocShell(), forThrottledAnimationFlush);
 
   // Get the Document's root element to ensure that the cache is valid before
   // calling into the (potentially-parallel) Servo traversal, where a cache hit
   // is necessary to avoid a data race when updating the cache.
   mozilla::Unused << aRoot->OwnerDoc()->GetRootElement();
 
   MOZ_ASSERT(!StylistNeedsUpdate());
   AutoSetInServoTraversal guard(this);
 
   const SnapshotTable& snapshots = Snapshots();
 
   bool isInitial = !aRoot->HasServoData();
-  bool forReconstruct =
-    aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
+  bool forReconstruct = !!(aFlags & ServoTraversalFlags::ForReconstruct);
 #ifdef DEBUG
-  bool forNewlyBoundElement =
-    aRestyleBehavior == TraversalRestyleBehavior::ForNewlyBoundElement;
+  bool forNewlyBoundElement = !!(aFlags & ServoTraversalFlags::ForNewlyBoundElement);
 #endif
-  bool postTraversalRequired = Servo_TraverseSubtree(
-    aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
+  bool postTraversalRequired =
+    Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, aFlags);
   MOZ_ASSERT(!(isInitial || forReconstruct || forNewlyBoundElement) ||
              !postTraversalRequired);
 
   // We don't need to trigger a second traversal if this restyle only for
   // flushing throttled animations. That's because the first traversal only
   // performs the animation-only restyle, skipping the normal restyle, and so
   // will not generate any SequentialTask that could update animation state
   // requiring a subsequent traversal.
@@ -319,18 +316,17 @@ ServoStyleSet::PrepareAndTraverseSubtree
   // values once at the begin of a tick. As a result, even if the previous
   // traversal caused, for example, the font-size to change, the SMIL style
   // won't be updated until the next tick anyway.
   EffectCompositor* compositor = mPresContext->EffectCompositor();
   EffectCompositor::AnimationRestyleType restyleType =
     EffectCompositor::AnimationRestyleType::Throttled;
   if (forReconstruct ? compositor->PreTraverseInSubtree(root, restyleType)
                      : compositor->PreTraverse(restyleType)) {
-    if (Servo_TraverseSubtree(
-          aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior)) {
+    if (Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, aFlags)) {
       MOZ_ASSERT(!forReconstruct);
       if (isInitial) {
         // We're doing initial styling, and the additional animation
         // traversal changed the styles that were set by the first traversal.
         // This would normally require a post-traversal to update the style
         // contexts, and the DOM now has dirty descendant bits and RestyleData
         // in expectation of that post-traversal. But since this is actually
         // the initial styling, there are no style contexts to update and no
@@ -415,17 +411,17 @@ ServoStyleSet::ResolvePseudoElementStyle
 
   RefPtr<ServoStyleContext> computedValues;
 
   if (aPseudoElement) {
     MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
     computedValues =
       Servo_ResolveStyle(aPseudoElement,
                          mRawSet.get(),
-                         TraversalRestyleBehavior::Normal).Consume();
+                         ServoTraversalFlags::Empty).Consume();
   } else {
     computedValues =
       Servo_ResolvePseudoStyle(aOriginatingElement,
                                aType,
                                /* is_probe = */ false,
                                aParentContext,
                                mRawSet.get()).Consume();
   }
@@ -777,80 +773,69 @@ ServoStyleSet::HasStateDependentStyle(do
                                       dom::Element* aPseudoElement,
                                       EventStates aStateMask)
 {
   NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
   return nsRestyleHint(0);
 }
 
 bool
-ServoStyleSet::StyleDocument(TraversalRestyleBehavior aRestyleBehavior)
+ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags)
 {
-  MOZ_ASSERT(
-    aRestyleBehavior == TraversalRestyleBehavior::Normal ||
-    aRestyleBehavior == TraversalRestyleBehavior::ForCSSRuleChanges,
-    "StyleDocument() should be only called for normal traversal or CSS rule "
-    "changes");
+  MOZ_ASSERT(aFlags == ServoTraversalFlags::Empty ||
+             aFlags == ServoTraversalFlags::ForCSSRuleChanges,
+             "Should only be called for normal traversal or CSS rule changes");
 
   PreTraverse();
 
   // Restyle the document from the root element and each of the document level
   // NAC subtree roots.
   bool postTraversalRequired = false;
   DocumentStyleRootIterator iter(mPresContext->Document());
   while (Element* root = iter.GetNextStyleRoot()) {
-    if (PrepareAndTraverseSubtree(root,
-                                  TraversalRootBehavior::Normal,
-                                  aRestyleBehavior)) {
+    if (PrepareAndTraverseSubtree(root, aFlags)) {
       postTraversalRequired = true;
     }
   }
   return postTraversalRequired;
 }
 
 bool
 ServoStyleSet::StyleDocumentForThrottledAnimationFlush()
 {
   PreTraverse(nullptr, EffectCompositor::AnimationRestyleType::Full);
 
   bool postTraversalRequired = false;
   DocumentStyleRootIterator iter(mPresContext->Document());
   while (Element* root = iter.GetNextStyleRoot()) {
-    if (PrepareAndTraverseSubtree(
-          root,
-          TraversalRootBehavior::Normal,
-          TraversalRestyleBehavior::ForThrottledAnimationFlush)) {
+    if (PrepareAndTraverseSubtree(root, ServoTraversalFlags::ForThrottledAnimationFlush)) {
       postTraversalRequired = true;
     }
   }
   return postTraversalRequired;
 }
 
 void
 ServoStyleSet::StyleNewSubtree(Element* aRoot)
 {
   MOZ_ASSERT(!aRoot->HasServoData());
 
   PreTraverse();
 
   DebugOnly<bool> postTraversalRequired =
-    PrepareAndTraverseSubtree(aRoot,
-                              TraversalRootBehavior::Normal,
-                              TraversalRestyleBehavior::Normal);
+    PrepareAndTraverseSubtree(aRoot, ServoTraversalFlags::Empty);
   MOZ_ASSERT(!postTraversalRequired);
 }
 
 void
 ServoStyleSet::StyleNewChildren(Element* aParent)
 {
   PreTraverse();
 
-  PrepareAndTraverseSubtree(aParent,
-                            TraversalRootBehavior::UnstyledChildrenOnly,
-                            TraversalRestyleBehavior::Normal);
+  PrepareAndTraverseSubtree(aParent, ServoTraversalFlags::UnstyledChildrenOnly);
   // We can't assert that Servo_TraverseSubtree returns false, since aParent
   // or some of its other children might have pending restyles.
 }
 
 void
 ServoStyleSet::StyleNewlyBoundElement(Element* aElement)
 {
   PreTraverse();
@@ -863,35 +848,31 @@ ServoStyleSet::StyleNewlyBoundElement(El
   // resolve the style first, but it's easy enough to just handle here.
   //
   // Also, when applying XBL bindings to elements within a display:none or
   // unstyled subtree (for example, when <object> elements are wrapped to be
   // exposed to JS), we need to tell the traversal that it is OK to
   // skip restyling, rather than panic when trying to unwrap the styles
   // it expects to have just computed.
 
-  TraversalRootBehavior rootBehavior =
-    MOZ_UNLIKELY(!aElement->HasServoData())
-      ? TraversalRootBehavior::Normal
-      : TraversalRootBehavior::UnstyledChildrenOnly;
+  ServoTraversalFlags flags = ServoTraversalFlags::ForNewlyBoundElement |
+    (MOZ_UNLIKELY(!aElement->HasServoData())
+      ? ServoTraversalFlags::Empty
+      : ServoTraversalFlags::UnstyledChildrenOnly);
 
-  PrepareAndTraverseSubtree(aElement,
-                            rootBehavior,
-                            TraversalRestyleBehavior::ForNewlyBoundElement);
+  PrepareAndTraverseSubtree(aElement, flags);
 }
 
 void
 ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
 {
   PreTraverse(aRoot);
 
   DebugOnly<bool> postTraversalRequired =
-    PrepareAndTraverseSubtree(aRoot,
-                              TraversalRootBehavior::Normal,
-                              TraversalRestyleBehavior::ForReconstruct);
+    PrepareAndTraverseSubtree(aRoot, ServoTraversalFlags::ForReconstruct);
   MOZ_ASSERT(!postTraversalRequired);
 }
 
 void
 ServoStyleSet::ForceAllStyleDirty()
 {
   SetStylistStyleSheetsDirty();
   Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get(), mAuthorStyleDisabled);
@@ -1080,24 +1061,23 @@ UpdateBodyTextColorIfNeeded(
   // NOTE(emilio): We do the ComputedData() dance to avoid triggering the
   // IsInServoTraversal() assertion in StyleColor(), which seems useful enough
   // in the general case, I guess...
   aPresContext.SetBodyTextColor(
       aStyleContext.ComputedData()->GetStyleColor()->mColor);
 }
 
 already_AddRefed<ServoStyleContext>
-ServoStyleSet::ResolveServoStyle(Element* aElement,
-                                 TraversalRestyleBehavior aRestyleBehavior)
+ServoStyleSet::ResolveServoStyle(Element* aElement, ServoTraversalFlags aFlags)
 {
   UpdateStylistIfNeeded();
   RefPtr<ServoStyleContext> result =
     Servo_ResolveStyle(aElement,
                        mRawSet.get(),
-                       aRestyleBehavior).Consume();
+                       aFlags).Consume();
   UpdateBodyTextColorIfNeeded(*aElement, *result, *mPresContext);
   return result.forget();
 }
 
 void
 ServoStyleSet::ClearNonInheritingStyleContexts()
 {
   for (RefPtr<ServoStyleContext>& ptr : mNonInheritingStyleContexts) {
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -259,24 +259,24 @@ public:
 
   /**
    * Performs a Servo traversal to compute style for all dirty nodes in the
    * document.
    *
    * This will traverse all of the document's style roots (that is, its document
    * element, and the roots of the document-level native anonymous content).
    *
-   * |aRestyleBehavior| should be `Normal` or `ForCSSRuleChanges`.
+   * The only allowed flag (for now ) is `ForCSSRuleChanges`.
    * We need to specify |ForCSSRuleChanges| to try to update all CSS animations
    * when we call this function due to CSS rule changes since @keyframes rules
    * may have changed.
    *
    * Returns true if a post-traversal is required.
    */
-  bool StyleDocument(TraversalRestyleBehavior aRestyleBehavior);
+  bool StyleDocument(ServoTraversalFlags aFlags);
 
   /**
    * Performs a Servo animation-only traversal to compute style for all nodes
    * with the animation-only dirty bit in the document.
    *
    * This will traverse all of the document's style roots (that is, its document
    * element, and the roots of the document-level native anonymous content).
    */
@@ -359,18 +359,17 @@ public:
 
   /**
    * Resolve style for the given element, and return it as a
    * ServoStyleContext.
    *
    * FIXME(emilio): Is there a point in this after bug 1367904?
    */
   already_AddRefed<ServoStyleContext>
-  ResolveServoStyle(dom::Element* aElement,
-                    TraversalRestyleBehavior aRestyleBehavior);
+  ResolveServoStyle(dom::Element* aElement, ServoTraversalFlags aFlags);
 
   bool GetKeyframesForName(const nsString& aName,
                            const nsTimingFunction& aTimingFunction,
                            nsTArray<Keyframe>& aKeyframes);
 
   nsTArray<ComputedKeyframeValues>
   GetComputedKeyframeValuesFor(const nsTArray<Keyframe>& aKeyframes,
                                dom::Element* aElement,
@@ -502,18 +501,17 @@ private:
 
   /**
    * Perform all lazy operations required before traversing
    * a subtree.
    *
    * Returns whether a post-traversal is required.
    */
   bool PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
-                                 TraversalRootBehavior aRootBehavior,
-                                 TraversalRestyleBehavior aRestyleBehavior);
+                                 ServoTraversalFlags aFlags);
 
   /**
    * Clear our cached mNonInheritingStyleContexts.
    *
    * We do this when we want to make sure those style contexts won't live too
    * long (e.g. when rebuilding all style data or when shutting down the style
    * set).
    */
--- a/layout/style/ServoTypes.h
+++ b/layout/style/ServoTypes.h
@@ -44,52 +44,43 @@ struct ServoCell {
 // Indicates whether the Servo style system should expect the style on an element
 // to have already been resolved (i.e. via a parallel traversal), or whether it
 // may be lazily computed.
 enum class LazyComputeBehavior {
   Allow,
   Assert,
 };
 
-// Indicates whether the Servo style system should perform normal processing or
-// whether it should only process unstyled children of the root and their
-// descendants.
-enum class TraversalRootBehavior {
-  Normal,
-  UnstyledChildrenOnly,
-};
-
-// Indicates whether the Servo style system should perform normal processing,
-// animation-only processing (so we can flush any throttled animation styles),
-// or whether it should traverse in a mode that doesn't generate any change
-// hints, which is what's required when handling frame reconstruction.
-// The change hints in this case are unneeded, since the old frames have
-// already been destroyed.
-// Indicates how the Servo style system should perform.
-enum class TraversalRestyleBehavior {
-  // Normal processing.
-  Normal,
-  // Normal processing, but tolerant to calls to restyle elements in unstyled
-  // or display:none subtrees (which can occur when styling elements with
-  // newly applied XBL bindings).
-  ForNewlyBoundElement,
+// Various flags for the servo traversal.
+enum class ServoTraversalFlags : uint32_t {
+  Empty = 0,
+  // Perform animation processing but not regular styling.
+  AnimationOnly = 1 << 0,
+  // Traverses as normal mode but tries to update all CSS animations.
+  ForCSSRuleChanges = 1 << 1,
+  // Traverse only unstyled children of the root (and their descendants).
+  UnstyledChildrenOnly = 1 << 2,
   // Traverses in a mode that doesn't generate any change hints, which is what's
   // required when handling frame reconstruction.  The change hints in this case
   // are unneeded, since the old frames have already been destroyed.
-  ForReconstruct,
+  ForReconstruct = 1 << 3,
+  // Be tolerant to calls to restyle elements in unstyled
+  // or display:none subtrees (which can occur when styling elements with
+  // newly applied XBL bindings).
+  ForNewlyBoundElement = 1 << 4,
   // Processes just the traversal for animation-only restyles and skips the
   // normal traversal for other restyles unrelated to animations.
   // This is used to bring throttled animations up-to-date such as when we need
   // to get correct position for transform animations that are throttled because
   // they are running on the compositor.
-  ForThrottledAnimationFlush,
-  // Traverses as normal mode but tries to update all CSS animations.
-  ForCSSRuleChanges,
+  ForThrottledAnimationFlush = 1 << 5,
 };
 
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoTraversalFlags)
+
 // Indicates which rules should be included when performing selecting matching
 // on an element.  DefaultOnly is used to exclude all rules except for those
 // that come from UA style sheets, and is used to implemented
 // getDefaultComputedStyle.
 enum class StyleRuleInclusion {
   All,
   DefaultOnly,
 };