Bug 1221525 part 2 - [css-grid] Add GridItemInfo::mState member (for each axis) and make the mIsFlexing bool into a state flag, and add baseline state flags. Also add a baseline offset member. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Thu, 02 Jun 2016 17:46:58 +0200
changeset 339218 0a36a1082b8f4f0fb15f402b8239646841dd812a
parent 339217 1ad5e5ff1669c75e73910fbda77c9c4aae7c66c0
child 339219 1dd828a285324256dbdd2448f32fb600dd507050
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1221525
milestone49.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 1221525 part 2 - [css-grid] Add GridItemInfo::mState member (for each axis) and make the mIsFlexing bool into a state flag, and add baseline state flags. Also add a baseline offset member. r=dholbert
layout/generic/nsGridContainerFrame.cpp
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -604,38 +604,118 @@ struct nsGridContainerFrame::GridArea
     : mCols(aCols), mRows(aRows) {}
   bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
   LineRange mCols;
   LineRange mRows;
 };
 
 struct nsGridContainerFrame::GridItemInfo
 {
+  /**
+   * Item state per axis.
+   */
+  enum StateBits : uint8_t {
+    eIsFlexing =            0x1, // does the item span a flex track?
+    eFirstBaseline =        0x2, // participate in first-baseline alignment?
+    // ditto last-baseline, mutually exclusive w. eFirstBaseline
+    eLastBaseline =         0x4,
+    eIsBaselineAligned = eFirstBaseline | eLastBaseline,
+    // One of e[Self|Content]Baseline is set when eIsBaselineAligned is true
+    eSelfBaseline =         0x8, // is it *-self:[last-]baseline alignment?
+    // Ditto *-content:[last-]baseline. Mutually exclusive w. eSelfBaseline.
+    eContentBaseline =     0x10,
+    eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline,
+  };
+
   explicit GridItemInfo(nsIFrame* aFrame,
                         const GridArea& aArea)
     : mFrame(aFrame)
     , mArea(aArea)
   {
-    mIsFlexing[0] = false;
-    mIsFlexing[1] = false;
+    mState[eLogicalAxisBlock] = StateBits(0);
+    mState[eLogicalAxisInline] = StateBits(0);
+    mBaselineOffset[eLogicalAxisBlock] = nscoord(0);
+    mBaselineOffset[eLogicalAxisInline] = nscoord(0);
   }
 
+  /**
+   * If the item is [align|justify]-self:[last-]baseline aligned in the given
+   * axis then set aBaselineOffset to the baseline offset and return aAlign.
+   * Otherwise, return a fallback alignment.
+   */
+  uint8_t GetSelfBaseline(uint8_t aAlign, LogicalAxis aAxis,
+                          nscoord* aBaselineOffset) const
+  {
+    MOZ_ASSERT(aAlign == NS_STYLE_ALIGN_BASELINE ||
+               aAlign == NS_STYLE_ALIGN_LAST_BASELINE);
+    if (!(mState[aAxis] & eSelfBaseline)) {
+      return aAlign == NS_STYLE_ALIGN_BASELINE ? NS_STYLE_ALIGN_SELF_START
+                                               : NS_STYLE_ALIGN_SELF_END;
+    }
+    *aBaselineOffset = mBaselineOffset[aAxis];
+    return aAlign;
+  }
+
+#ifdef DEBUG
+  void Dump() const;
+#endif
+
   static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b)
   {
     return a->mArea.mRows.mStart < b->mArea.mRows.mStart;
   }
 
   nsIFrame* const mFrame;
   GridArea mArea;
-  bool mIsFlexing[2]; // does the item span a flex track? (LogicalAxis index)
+  // Offset from the margin edge to the baseline (LogicalAxis index).  It's from
+  // the start edge when eFirstBaseline is set, end edge otherwise. It's mutable
+  // since we update the value fairly late (just before reflowing the item).
+  mutable nscoord mBaselineOffset[2];
+  StateBits mState[2]; // state bits per axis (LogicalAxis index)
   static_assert(mozilla::eLogicalAxisBlock == 0, "unexpected index value");
   static_assert(mozilla::eLogicalAxisInline == 1, "unexpected index value");
 };
 
 using GridItemInfo = nsGridContainerFrame::GridItemInfo;
+using ItemState = GridItemInfo::StateBits;
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ItemState)
+
+#ifdef DEBUG
+void
+nsGridContainerFrame::GridItemInfo::Dump() const
+{
+  auto Dump1 = [this] (const char* aMsg, LogicalAxis aAxis) {
+    auto state = mState[aAxis];
+    if (!state) {
+      return;
+    }
+    printf("%s", aMsg);
+    if (state & ItemState::eIsFlexing) {
+      printf("flexing ");
+    }
+    if (state & ItemState::eFirstBaseline) {
+      printf("baseline %s-alignment ",
+             (state & ItemState::eSelfBaseline) ? "self" : "content");
+    }
+    if (state & ItemState::eLastBaseline) {
+      printf("last-baseline %s-alignment ",
+             (state & ItemState::eSelfBaseline) ? "self" : "content");
+    }
+    if (state & ItemState::eIsBaselineAligned) {
+      printf("%.2fpx", NSAppUnitsToFloatPixels(mBaselineOffset[aAxis],
+                                               AppUnitsPerCSSPixel()));
+    }
+    printf("\n");
+  };
+  printf("grid-row: %d %d\n", mArea.mRows.mStart, mArea.mRows.mEnd);
+  Dump1("  grid block-axis: ", eLogicalAxisBlock);
+  printf("grid-column: %d %d\n", mArea.mCols.mStart, mArea.mCols.mEnd);
+  Dump1("  grid inline-axis: ", eLogicalAxisInline);
+}
+#endif
 
 /**
  * Utility class to find line names.  It provides an interface to lookup line
  * names with a dynamic number of repeat(auto-fill/fit) tracks taken into
  * account.
  */
 class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap
 {
@@ -3444,17 +3524,17 @@ nsGridContainerFrame::Tracks::ResolveInt
     static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b)
     {
       return a.mSpan < b.mSpan;
     }
   };
 
   // Resolve Intrinsic Track Sizes
   // http://dev.w3.org/csswg/css-grid/#algo-content
-  // We're also setting mIsFlexing on the item here to speed up
+  // We're also setting eIsFlexing on the item state here to speed up
   // FindUsedFlexFraction later.
   AutoTArray<TrackSize::StateBits, 16> stateBitsPerSpan;
   nsTArray<Step2ItemData> step2Items;
   GridItemCSSOrderIterator& iter = aState.mIter;
   nsRenderingContext* rc = &aState.mRenderingContext;
   WritingMode wm = aState.mWM;
   uint32_t maxSpan = 0; // max span of the step2Items items
   const TrackSize::StateBits flexMin =
@@ -3463,19 +3543,20 @@ nsGridContainerFrame::Tracks::ResolveInt
   iter.Reset();
   for (; !iter.AtEnd(); iter.Next()) {
     auto& gridItem = aGridItems[iter.GridItemIndex()];
     const GridArea& area = gridItem.mArea;
     const LineRange& lineRange = area.*aRange;
     uint32_t span = lineRange.Extent();
     if (span == 1) {
       // Step 1. Size tracks to fit non-spanning items.
-      gridItem.mIsFlexing[mAxis] =
-        ResolveIntrinsicSizeStep1(aState, aFunctions, aPercentageBasis,
-                                  aConstraint, lineRange, gridItem);
+      if (ResolveIntrinsicSizeStep1(aState, aFunctions, aPercentageBasis,
+                                    aConstraint, lineRange, gridItem)) {
+        gridItem.mState[mAxis] |= ItemState::eIsFlexing;
+      }
     } else {
       TrackSize::StateBits state = TrackSize::StateBits(0);
       if (HasIntrinsicButNoFlexSizingInRange(lineRange, aConstraint, &state)) {
         // Collect data for Step 2.
         maxSpan = std::max(maxSpan, span);
         if (span >= stateBitsPerSpan.Length()) {
           uint32_t len = 2 * span;
           stateBitsPerSpan.SetCapacity(len);
@@ -3498,19 +3579,18 @@ nsGridContainerFrame::Tracks::ResolveInt
         if (state & (TrackSize::eMaxContentMinSizing |         // for 2.3
                      TrackSize::eAutoOrMaxContentMaxSizing)) { // for 2.6
           maxContent = MaxContentContribution(gridItem, aState.mReflowState,
                                               rc, wm, mAxis);
         }
         step2Items.AppendElement(
           Step2ItemData({span, state, lineRange, minSize,
                          minContent, maxContent, *iter}));
-      } else {
-        aGridItems[iter.GridItemIndex()].mIsFlexing[mAxis] =
-          !!(state & TrackSize::eFlexMaxSizing);
+      } else if (state & TrackSize::eFlexMaxSizing) {
+        gridItem.mState[mAxis] |= ItemState::eIsFlexing;
       }
     }
   }
 
   // Step 2.
   if (maxSpan) {
     // Sort the collected items on span length, shortest first.
     std::stable_sort(step2Items.begin(), step2Items.end(),
@@ -3754,17 +3834,17 @@ nsGridContainerFrame::Tracks::FindUsedFl
   nsRenderingContext* rc = &aState.mRenderingContext;
   const nsHTMLReflowState* rs = aState.mReflowState;
   GridItemCSSOrderIterator& iter = aState.mIter;
   iter.Reset();
   // ... the result of 'finding the size of an fr' for each item that spans
   // a flex track with its max-content contribution as 'space to fill'
   for (; !iter.AtEnd(); iter.Next()) {
     const GridItemInfo& item = aGridItems[iter.GridItemIndex()];
-    if (item.mIsFlexing[mAxis]) {
+    if (item.mState[mAxis] & ItemState::eIsFlexing) {
       nscoord spaceToFill = MaxContentContribution(item, rs, rc, wm, mAxis);
       if (spaceToFill <= 0) {
         continue;
       }
       // ... and all its spanned tracks as input.
       const LineRange& range =
         mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
       nsTArray<uint32_t> itemFlexTracks;