Bug 1341981 Part 2 - Convert frame completion status to a tri-state enum class. draft
authorTing-Yu Lin <tlin@mozilla.com>
Fri, 24 Feb 2017 14:34:50 +0800
changeset 490477 6f22218f7cd1f895d494e397cfaa74bfef85f0b4
parent 490476 c245c00fe456318b8ebcb76016335849b9927ad3
child 490478 0b517415e76a01b1c9a5146fdec0ca6dd7ec3120
push id47110
push userbmo:tlin@mozilla.com
push dateTue, 28 Feb 2017 15:38:33 +0000
bugs1341981
milestone54.0a1
Bug 1341981 Part 2 - Convert frame completion status to a tri-state enum class. MozReview-Commit-ID: 8DrGnwoRz7
layout/generic/nsContainerFrame.h
layout/generic/nsIFrame.h
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -322,19 +322,19 @@ public:
   /* Overflow containers are continuation frames that hold overflow. They
    * are created when the frame runs out of computed height, but still has
    * too much content to fit in the availableHeight. The parent creates a
    * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
    * and adds it to its next-in-flow's overflow container list, either by
    * adding it directly or by putting it in its own excess overflow containers
    * list (to be drained by the next-in-flow when it calls
    * ReflowOverflowContainerChildren). The parent continues reflow as if
-   * the frame was complete once it ran out of computed height, but returns
-   * with either the mIncomplete or mOverflowIncomplete bit set in reflow
-   * status to request a next-in-flow. The parent's next-in-flow is then
+   * the frame was complete once it ran out of computed height, but returns a
+   * reflow status with either IsIncomplete() or IsOverflowIncomplete() equal
+   * to true to request a next-in-flow. The parent's next-in-flow is then
    * responsible for calling ReflowOverflowContainerChildren to (drain and)
    * reflow these overflow continuations. Overflow containers do not affect
    * other frames' size or position during reflow (but do affect their
    * parent's overflow area).
    *
    * Overflow container continuations are different from normal continuations
    * in that
    *   - more than one child of the frame can have its next-in-flow broken
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -197,76 +197,84 @@ enum nsSpread {
 //----------------------------------------------------------------------
 // Reflow status returned by the Reflow() methods.
 class nsReflowStatus final {
   using StyleClear = mozilla::StyleClear;
 
 public:
   nsReflowStatus()
     : mBreakType(StyleClear::None)
-    , mIncomplete(false)
-    , mOverflowIncomplete(false)
+    , mCompletion(Completion::FullyComplete)
     , mNextInFlowNeedsReflow(false)
     , mTruncated(false)
     , mInlineBreak(false)
     , mInlineBreakAfter(false)
     , mFirstLetterComplete(false)
   {}
 
-  // Reset all the bit-fields.
+  // Reset all the member variables.
   void Reset() {
     mBreakType = StyleClear::None;
-    mIncomplete = false;
-    mOverflowIncomplete = false;
+    mCompletion = Completion::FullyComplete;
     mNextInFlowNeedsReflow = false;
     mTruncated = false;
     mInlineBreak = false;
     mInlineBreakAfter = false;
     mFirstLetterComplete = false;
   }
 
-  // Return true if all flags are cleared.
+  // Return true if all member variables have their default values.
   bool IsEmpty() const {
-    return (!mIncomplete &&
-            !mOverflowIncomplete &&
+    return (IsFullyComplete() &&
             !mNextInFlowNeedsReflow &&
             !mTruncated &&
             !mInlineBreak &&
             !mInlineBreakAfter &&
             !mFirstLetterComplete);
   }
 
-  // mIncomplete bit flag means the frame does not map all its content, and
-  // that the parent frame should create a continuing frame. If this bit
-  // isn't set, it means the frame does map all its content. This bit is
-  // mutually exclusive with mOverflowIncomplete.
+  // There are three possible completion statuses, represented by
+  // mCompletion.
   //
-  // mOverflowIncomplete bit flag means that the frame has overflow that is
-  // not complete, but its own box is complete. (This happens when content
+  // Incomplete means the frame does *not* map all its content, and the
+  // parent frame should create a continuing frame.
+  //
+  // OverflowIncomplete means that the frame has an overflow that is not
+  // complete, but its own box is complete. (This happens when the content
   // overflows a fixed-height box.) The reflower should place and size the
-  // frame and continue its reflow, but needs to create an overflow
-  // container as a continuation for this frame. See nsContainerFrame.h for
-  // more information. This bit is mutually exclusive with mIncomplete.
+  // frame and continue its reflow, but it needs to create an overflow
+  // container as a continuation for this frame. See "Overflow containers"
+  // documentation in nsContainerFrame.h for more information.
+  //
+  // FullyComplete means the frame is neither Incomplete nor
+  // OverflowIncomplete. This is the default state for a nsReflowStatus.
   //
-  // If both mIncomplete and mOverflowIncomplete are not set, the frame is
-  // fully complete.
-  bool IsComplete() const { return !mIncomplete; }
-  bool IsIncomplete() const { return mIncomplete; }
-  bool IsOverflowIncomplete() const { return mOverflowIncomplete; }
+  enum class Completion : uint8_t {
+    // The order of the enum values is important, which represents the
+    // precedence when merging.
+    FullyComplete,
+    OverflowIncomplete,
+    Incomplete,
+  };
+
+  bool IsIncomplete() const { return mCompletion == Completion::Incomplete; }
+  bool IsOverflowIncomplete() const {
+    return mCompletion == Completion::OverflowIncomplete;
+  }
   bool IsFullyComplete() const {
-    return !IsIncomplete() && !IsOverflowIncomplete();
+    return mCompletion == Completion::FullyComplete;
   }
+  // Just for convenience; not a distinct state.
+  bool IsComplete() const { return !IsIncomplete(); }
 
   void SetIncomplete() {
-    mIncomplete = true;
-    mOverflowIncomplete = false;
+    mCompletion = Completion::Incomplete;
   }
   void SetOverflowIncomplete() {
-    mIncomplete = false;
-    mOverflowIncomplete = true;
+    mCompletion = Completion::OverflowIncomplete;
   }
 
   // mNextInFlowNeedsReflow bit flag means that the next-in-flow is dirty,
   // and also needs to be reflowed. This status only makes sense for a frame
   // that is not complete, i.e. you wouldn't set mNextInFlowNeedsReflow when
   // IsComplete() is true.
   bool NextInFlowNeedsReflow() const { return mNextInFlowNeedsReflow; }
   void SetNextInFlowNeedsReflow() { mNextInFlowNeedsReflow = true; }
@@ -278,23 +286,28 @@ public:
   // be truncated. Doing so would likely cause an infinite loop.
   bool IsTruncated() const { return mTruncated; }
   void UpdateTruncated(const mozilla::ReflowInput& aReflowInput,
                        const mozilla::ReflowOutput& aMetrics);
 
   // Merge the frame completion status bits from aStatus into this.
   void MergeCompletionStatusFrom(const nsReflowStatus& aStatus)
   {
-    mIncomplete |= aStatus.mIncomplete;
-    mOverflowIncomplete |= aStatus.mOverflowIncomplete;
+    if (mCompletion < aStatus.mCompletion) {
+      mCompletion = aStatus.mCompletion;
+    }
+
+    // These asserts ensure that the mCompletion merging works as we expect.
+    // (Incomplete beats OverflowIncomplete, which beats FullyComplete.)
+    static_assert(Completion::Incomplete > Completion::OverflowIncomplete &&
+                  Completion::OverflowIncomplete > Completion::FullyComplete,
+                  "mCompletion merging won't work without this!");
+
     mNextInFlowNeedsReflow |= aStatus.mNextInFlowNeedsReflow;
     mTruncated |= aStatus.mTruncated;
-    if (mIncomplete) {
-      mOverflowIncomplete = false;
-    }
   }
 
   // mInlineBreak bit flag means a break is requested.
   bool IsInlineBreak() const { return mInlineBreak; }
 
   // Suppose a break is requested. When mInlineBreakAfter is set, the break
   // should occur after the frame just reflowed; when mInlineBreakAfter is
   // clear, the break should occur before the frame just reflowed.
@@ -322,20 +335,17 @@ public:
 
   // mFirstLetterComplete bit flag means the break was induced by
   // completion of a first-letter.
   bool FirstLetterComplete() const { return mFirstLetterComplete; }
   void SetFirstLetterComplete() { mFirstLetterComplete = true; }
 
 private:
   StyleClear mBreakType;
-
-  // Frame completion status bit flags.
-  bool mIncomplete : 1;
-  bool mOverflowIncomplete : 1;
+  Completion mCompletion;
   bool mNextInFlowNeedsReflow : 1;
   bool mTruncated : 1;
 
   // Inline break status bit flags.
   bool mInlineBreak : 1;
   bool mInlineBreakAfter : 1;
   bool mFirstLetterComplete : 1;
 };
@@ -2318,17 +2328,17 @@ public:
    * frame the status returned by the Reflow member function.
    *
    * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set, before
    * it is finally called once with a NS_FRAME_REFLOW_COMPLETE value. When called
    * with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW bit in the
    * frame state will be cleared.
    *
    * XXX This doesn't make sense. If the frame is reflowed but not complete, then
-   * the status should have mIncomplete bit set.
+   * the status should have IsIncomplete() equal to true.
    * XXX Don't we want the semantics to dictate that we only call this once for
    * a given reflow?
    */
   virtual void DidReflow(nsPresContext*           aPresContext,
                          const ReflowInput* aReflowInput,
                          nsDidReflowStatus        aStatus) = 0;
 
   /**