Bug 1256429 part 2 - [css-grid] Implement Grid layout for align|justify-content:baseline|last-baseline (aka "Baseline Content-Alignment"). r=dholbert
authorMats Palmgren <mats@mozilla.com>
Thu, 02 Jun 2016 17:46:59 +0200
changeset 341236 7ea32b5e7ecfe284bb739dbe65c96f80a36f4f31
parent 341235 7294fad22949eef3cf91c5e484f5c8a02e4a105b
child 341237 2b4dfcc5160c9557397bcf7a366e94def8731999
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1256429
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 1256429 part 2 - [css-grid] Implement Grid layout for align|justify-content:baseline|last-baseline (aka "Baseline Content-Alignment"). r=dholbert
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsIFrame.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -4544,31 +4544,60 @@ nsGridContainerFrame::ReflowInFlowChild(
   LogicalMargin pad(aState.mReflowState->ComputedLogicalPadding());
   const LogicalPoint padStart(wm, pad.IStart(wm), pad.BStart(wm));
   const bool isGridItem = !!aGridItemInfo;
   MOZ_ASSERT(isGridItem == (aChild->GetType() != nsGkAtoms::placeholderFrame));
   LogicalRect cb(wm);
   WritingMode childWM = aChild->GetWritingMode();
   bool isConstrainedBSize = false;
   nscoord toFragmentainerEnd;
+  const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
   if (MOZ_LIKELY(isGridItem)) {
     MOZ_ASSERT(aGridItemInfo->mFrame == aChild);
     const GridArea& area = aGridItemInfo->mArea;
     MOZ_ASSERT(area.IsDefinite());
     cb = aState.ContainingBlockFor(area);
     isConstrainedBSize = aFragmentainer && !wm.IsOrthogonalTo(childWM);
     if (isConstrainedBSize) {
       cb.BStart(wm) = std::max(0, cb.BStart(wm) - aState.mFragBStart);
       toFragmentainerEnd = aFragmentainer->mToFragmentainerEnd -
         aState.mFragBStart - cb.BStart(wm);
       toFragmentainerEnd = std::max(toFragmentainerEnd, 0);
     }
     cb += aContentArea.Origin(wm);
     aState.mRows.AlignBaselineSubtree(*aGridItemInfo);
     aState.mCols.AlignBaselineSubtree(*aGridItemInfo);
+    // Setup [align|justify]-content:[last-]baseline related frame properties.
+    // These are added to the padding in nsCSSOffsetState::InitOffsets.
+    // (a negative value signals the value is for 'last-baseline' and should be
+    //  added to the (logical) end padding)
+    typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
+    auto SetProp = [aGridItemInfo, aChild] (LogicalAxis aGridAxis,
+                                            Prop aProp) {
+      auto state = aGridItemInfo->mState[aGridAxis];
+      auto baselineAdjust = (state & ItemState::eContentBaseline) ?
+             aGridItemInfo->mBaselineOffset[aGridAxis] : nscoord(0);
+      if (baselineAdjust < nscoord(0)) {
+        // This happens when the subtree overflows its track.
+        // XXX spec issue? it's unclear how to handle this.
+        baselineAdjust = nscoord(0);
+      } else if (baselineAdjust > nscoord(0) &&
+                 (state & ItemState::eLastBaseline)) {
+        baselineAdjust = -baselineAdjust;
+      }
+      if (baselineAdjust != nscoord(0)) {
+        aChild->Properties().Set(aProp, baselineAdjust);
+      } else {
+        aChild->Properties().Delete(aProp);
+      }
+    };
+    SetProp(eLogicalAxisBlock, isOrthogonal ? IBaselinePadProperty() :
+                                              BBaselinePadProperty());
+    SetProp(eLogicalAxisInline, isOrthogonal ? BBaselinePadProperty() :
+                                               IBaselinePadProperty());
   } else {
     cb = aContentArea;
   }
 
   LogicalSize reflowSize(cb.Size(wm));
   if (isConstrainedBSize) {
     reflowSize.BSize(wm) = toFragmentainerEnd;
   }
@@ -4613,19 +4642,29 @@ nsGridContainerFrame::ReflowInFlowChild(
   LogicalPoint childPos =
     cb.Origin(wm).ConvertTo(childWM, wm,
                             aContainerSize - childSize.PhysicalSize());
   // Apply align/justify-self and reflow again if that affects the size.
   if (MOZ_LIKELY(isGridItem)) {
     LogicalSize size = childSize.Size(childWM); // from the ReflowChild()
     if (NS_FRAME_IS_COMPLETE(aStatus)) {
       auto align = childRS.mStylePosition->ComputedAlignSelf(containerSC);
+      auto state = aGridItemInfo->mState[eLogicalAxisBlock];
+      if (state & ItemState::eContentBaseline) {
+        align = (state & ItemState::eFirstBaseline) ? NS_STYLE_ALIGN_SELF_START
+                                                    : NS_STYLE_ALIGN_SELF_END;
+      }
       AlignSelf(*aGridItemInfo, align, cb, wm, childRS, size, &childPos);
     }
     auto justify = childRS.mStylePosition->ComputedJustifySelf(containerSC);
+    auto state = aGridItemInfo->mState[eLogicalAxisInline];
+    if (state & ItemState::eContentBaseline) {
+      justify = (state & ItemState::eFirstBaseline) ? NS_STYLE_JUSTIFY_SELF_START
+                                                    : NS_STYLE_JUSTIFY_SELF_END;
+    }
     JustifySelf(*aGridItemInfo, justify, cb, wm, childRS, size, &childPos);
   } else {
     // Put a placeholder at the padding edge, in case an ancestor is its CB.
     childPos -= padStart;
   }
   childRS.ApplyRelativePositioning(&childPos, aContainerSize);
   FinishReflowChild(aChild, pc, childSize, &childRS, childWM, childPos,
                     aContainerSize, 0);
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -156,17 +156,19 @@ nsCSSOffsetState::nsCSSOffsetState(nsIFr
                                    nscoord aContainingBlockISize)
   : frame(aFrame)
   , rendContext(aRenderingContext)
   , mWritingMode(aFrame->GetWritingMode())
 {
   MOZ_ASSERT(!aFrame->IsFlexOrGridItem(),
              "We're about to resolve percent margin & padding "
              "values against CB inline size, which is incorrect for "
-             "flex/grid items");
+             "flex/grid items. "
+             "Additionally for grid items, this path doesn't handle baseline "
+             "padding contribution - see nsCSSOffsetState::InitOffsets");
   LogicalSize cbSize(aContainingBlockWritingMode, aContainingBlockISize,
                      aContainingBlockISize);
   ReflowStateFlags flags;
   InitOffsets(aContainingBlockWritingMode, cbSize, frame->GetType(), flags);
 }
 
 // Initialize a reflow state for a child frame's reflow. Some state
 // is copied from the parent reflow state; the remaining state is
@@ -2485,16 +2487,43 @@ nsCSSOffsetState::InitOffsets(WritingMod
     ComputedPhysicalPadding() = *aPadding;
     needPaddingProp = frame->StylePadding()->IsWidthDependent() ||
 	  (frame->GetStateBits() & NS_FRAME_REFLOW_ROOT);
   }
   else {
     needPaddingProp = ComputePadding(aWM, aPercentBasis, aFrameType);
   }
 
+  // Add [align|justify]-content:baseline padding contribution.
+  typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
+  auto ApplyBaselinePadding = [this, &needPaddingProp]
+         (LogicalAxis aAxis, Prop aProp) {
+    bool found;
+    nscoord val = frame->Properties().Get(aProp, &found);
+    if (found) {
+      NS_ASSERTION(val != nscoord(0), "zero in this property is useless");
+      WritingMode wm = GetWritingMode();
+      LogicalSide side;
+      if (val > 0) {
+        side = MakeLogicalSide(aAxis, eLogicalEdgeStart);
+      } else {
+        side = MakeLogicalSide(aAxis, eLogicalEdgeEnd);
+        val = -val;
+      }
+      mComputedPadding.Side(wm.PhysicalSide(side)) += val;
+      needPaddingProp = true;
+    }
+  };
+  if (!aFlags.mUseAutoBSize) {
+    ApplyBaselinePadding(eLogicalAxisBlock, nsIFrame::BBaselinePadProperty());
+  }
+  if (!aFlags.mShrinkWrap) {
+    ApplyBaselinePadding(eLogicalAxisInline, nsIFrame::IBaselinePadProperty());
+  }
+
   if (isThemed) {
     nsIntMargin widget;
     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
                                              frame, disp->mAppearance,
                                              &widget);
     ComputedPhysicalBorderPadding().top =
       presContext->DevPixelsToAppUnits(widget.top);
     ComputedPhysicalBorderPadding().right =
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -940,16 +940,19 @@ public:
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(CachedBackgroundImageDT, DrawTarget)
 
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(InvalidationRect, nsRect)
 
   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(RefusedAsyncAnimationProperty, bool)
 
   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FragStretchBSizeProperty, nscoord)
 
+  NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
+  NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
+
   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(GenConProperty, ContentArray,
                                       DestroyContentArray)
 
   nsTArray<nsIContent*>* GetGenConPseudos() {
     return Properties().Get(GenConProperty());
   }
 
   /**