Bug 1449838 part 1: Add utility function nsFlexContainerFrame::IsItemInlineAxisMainAxis(). r?mats draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 29 Mar 2018 14:49:28 -0700
changeset 774956 ea02754109868447a27cf6195a68f76e1253a233
parent 774928 e974a8ab639efe84bbf97de0379e9e41b34deac7
child 774957 f8aa01987a225acfc6f9a3ac6641f6be270ff953
push id104575
push userdholbert@mozilla.com
push dateThu, 29 Mar 2018 21:49:57 +0000
reviewersmats
bugs1449838
milestone61.0a1
Bug 1449838 part 1: Add utility function nsFlexContainerFrame::IsItemInlineAxisMainAxis(). r?mats This patch doesn't affect behavior - it's just refactoring / de-duplicating. (The refactored function does include some new "legacy box" code, just for completeness & to ensure that the included assertion passes. But beyond the assertion, that new code isn't exercised right now -- this function's only callsites are skipped if the NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX state-bit is set on the container. Hence, this patch still doesn't affect behavior, even though it's adding some new logic in the refactored-out function.) MozReview-Commit-ID: G5aCzwTwkTa
layout/generic/nsFlexContainerFrame.cpp
layout/generic/nsFlexContainerFrame.h
layout/generic/nsFrame.cpp
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -1818,16 +1818,20 @@ FlexItem::FlexItem(ReflowInput& aFlexIte
     // mNeedsMinSizeAutoResolution is initialized in CheckForMinSizeAuto()
     // mAlignSelf, see below
 {
   MOZ_ASSERT(mFrame, "expecting a non-null child frame");
   MOZ_ASSERT(!mFrame->IsPlaceholderFrame(),
              "placeholder frames should not be treated as flex items");
   MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
              "out-of-flow frames should not be treated as flex items");
+  MOZ_ASSERT(mIsInlineAxisMainAxis ==
+             nsFlexContainerFrame::IsItemInlineAxisMainAxis(mFrame),
+             "public API should be consistent with internal state (about "
+             "whether flex item's inline axis is flex container's main axis)");
 
   const ReflowInput* containerRS = aFlexItemReflowInput.mParentReflowInput;
   if (IsLegacyBox(containerRS->mFrame)) {
     // For -webkit-{inline-}box and -moz-{inline-}box, we need to:
     // (1) Use prefixed "box-align" instead of "align-items" to determine the
     //     container's cross-axis alignment behavior.
     // (2) Suppress the ability for flex items to override that with their own
     //     cross-axis alignment. (The legacy box model doesn't support this.)
@@ -4376,16 +4380,51 @@ nsFlexContainerFrame::GetFlexFrameWithCo
                   flexFrame->HasProperty(FlexContainerInfo()),
                   "The state bit should've made our forced-reflow "
                   "generate a FlexContainerInfo object");
     }
   }
   return flexFrame;
 }
 
+/* static */
+bool
+nsFlexContainerFrame::IsItemInlineAxisMainAxis(nsIFrame* aFrame)
+{
+  MOZ_ASSERT(aFrame && aFrame->IsFlexItem(), "expecting arg to be a flex item");
+  const WritingMode flexItemWM = aFrame->GetWritingMode();
+  const nsIFrame* flexContainer = aFrame->GetParent();
+
+  if (IsLegacyBox(flexContainer)) {
+    // For legacy boxes, the main axis is determined by "box-orient", and we can
+    // just directly check if that's vertical, and compare that to whether the
+    // item's WM is also vertical:
+    bool boxOrientIsVertical =
+      (flexContainer->StyleXUL()->mBoxOrient == StyleBoxOrient::Vertical);
+    return flexItemWM.IsVertical() == boxOrientIsVertical;
+  }
+
+  // For modern CSS flexbox, we get our return value by asking two questions
+  // and comparing their answers.
+  // Question 1: does aFrame have the same inline axis as its flex container?
+  bool itemInlineAxisIsParallelToParent =
+    !flexItemWM.IsOrthogonalTo(flexContainer->GetWritingMode());
+
+  // Question 2: is aFrame's flex container row-oriented? (This tells us
+  // whether the flex container's main axis is its inline axis.)
+  auto flexDirection = flexContainer->StylePosition()->mFlexDirection;
+  bool flexContainerIsRowOriented =
+    flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
+    flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
+
+  // aFrame's inline axis is its flex container's main axis IFF the above
+  // questions have the same answer.
+  return flexContainerIsRowOriented == itemInlineAxisIsParallelToParent;
+}
+
 void
 nsFlexContainerFrame::DoFlexLayout(nsPresContext*           aPresContext,
                                    ReflowOutput&     aDesiredSize,
                                    const ReflowInput& aReflowInput,
                                    nsReflowStatus&          aStatus,
                                    nscoord aContentBoxMainSize,
                                    nscoord aAvailableBSizeForContent,
                                    nsTArray<StrutInfo>& aStruts,
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -192,16 +192,31 @@ public:
   /**
    * Return aFrame as a flex frame after ensuring it has computed flex info.
    * @return nullptr if aFrame is null or doesn't have a flex frame
    *         as its content insertion frame.
    * @note this might destroy layout/style data since it may flush layout.
    */
   static nsFlexContainerFrame* GetFlexFrameWithComputedInfo(nsIFrame* aFrame);
 
+  /**
+   * Given a frame for a flex item, this method returns true IFF that flex
+   * item's inline axis is the same as (i.e. not orthogonal to) its flex
+   * container's main axis.
+   *
+   * (This method is only intended to be used from external
+   * callers. Inside of flex reflow code, FlexItem::IsInlineAxisMainAxis() is
+   * equivalent & more optimal.)
+   *
+   * @param aFrame a flex item (must return true from IsFlexItem)
+   * @return true iff aFrame's inline axis is the same as (i.e. not orthogonal
+   *              to) its flex container's main axis. Otherwise, false.
+   */
+  static bool IsItemInlineAxisMainAxis(nsIFrame* aFrame);
+
 protected:
   // Protected constructor & destructor
   explicit nsFlexContainerFrame(ComputedStyle* aStyle)
     : nsContainerFrame(aStyle, kClassID)
     , mBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
     , mLastBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
   {}
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5667,35 +5667,20 @@ nsFrame::ComputeSize(gfxContext*        
     !parentFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX) &&
     !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
   // This bool only gets set (and used) if isFlexItem is true.
   // It indicates (for flex items) whether we're using their flex-basis for the
   // item's own ISize property vs. for its BSize property.
   bool usingFlexBasisForISize = false;
   if (isFlexItem) {
     // Flex items use their "flex-basis" property in place of their main-size
-    // property (e.g. "width") for sizing purposes, *unless* they have
-    // "flex-basis:auto", in which case they use their main-size property after
-    // all.
-    uint32_t flexDirection = GetParent()->StylePosition()->mFlexDirection;
-    const bool flexContainerIsRowOriented =
-      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
-      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
-    const bool inlineAxisSameAsParent =
-      !aWM.IsOrthogonalTo(parentFrame->GetWritingMode());
-
-    // If parent is row-oriented, its main axis (i.e. the flex-basis axis) is
-    // its own inline axis. So if it's row oriented and our own inline axis
-    // is the same as our parent's, then we'll be using flex-basis in place
-    // of our _ISize_ sizing property.
-    // Otherwise, we'll be using flex-basis for our _BSize_ sizing property
-    // (unless both conditions are false, in which case we flip back around to
-    // using our ISize sizing property).
+    // property for sizing purposes, *unless* they have "flex-basis:auto", in
+    // which case they use their main-size property after all.
     usingFlexBasisForISize =
-      (flexContainerIsRowOriented == inlineAxisSameAsParent);
+      nsFlexContainerFrame::IsItemInlineAxisMainAxis(this);
 
     // NOTE: The logic here should match the similar chunk for determining
     // inlineStyleCoord and blockStyleCoord in
     // nsFrame::ComputeSizeWithIntrinsicDimensions().
     const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
     if (flexBasis->GetUnit() != eStyleUnit_Auto) {
       // Override whichever styleCoord is in flex container's main axis:
       (usingFlexBasisForISize ? inlineStyleCoord : blockStyleCoord) =
@@ -5907,27 +5892,18 @@ nsFrame::ComputeSizeWithIntrinsicDimensi
   Maybe<nsStyleCoord> imposedMainSizeStyleCoord;
 
   // If this is a flex item, and we're measuring its cross size after flexing
   // to resolve its main size, then we need to use the resolved main size
   // that the container provides to us *instead of* the main-size coordinate
   // from our style struct. (Otherwise, we'll be using an irrelevant value in
   // the aspect-ratio calculations below.)
   if (isFlexItem) {
-    uint32_t flexDirection =
-      GetParent()->StylePosition()->mFlexDirection;
-    const bool flexContainerIsRowOriented =
-      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
-      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
-    const bool inlineAxisSameAsParent =
-      !aWM.IsOrthogonalTo(parentFrame->GetWritingMode());
-
-    // (See explanatory comment in similar code within ComputeSize.)
     usingFlexBasisForISize =
-      (flexContainerIsRowOriented == inlineAxisSameAsParent);
+      nsFlexContainerFrame::IsItemInlineAxisMainAxis(this);
 
     // If FlexItemMainSizeOverride frame-property is set, then that means the
     // flex container is imposing a main-size on this flex item for it to use
     // as its size in the container's main axis.
     bool didImposeMainSize;
     nscoord imposedMainSize =
       GetProperty(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize);
     if (didImposeMainSize) {