Bug 1269046 part 1: Spin out some grid alignment code into a helper method, in a new CSSAlignUtils class. r=mats draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 28 Oct 2016 22:46:59 -0700
changeset 431581 7ba5587ddbecf9ee170a8787210a8dbcd0600b06
parent 431580 7cdfe7c3b9b8ed1da744d4f7c89bc088645964be
child 431582 a099ee7f46743984541611298940e8e89d480a13
push id34071
push userdholbert@mozilla.com
push dateSun, 30 Oct 2016 20:01:42 +0000
reviewersmats
bugs1269046
milestone52.0a1
Bug 1269046 part 1: Spin out some grid alignment code into a helper method, in a new CSSAlignUtils class. r=mats MozReview-Commit-ID: 1Eh2CreOLTC
layout/generic/CSSAlignUtils.cpp
layout/generic/CSSAlignUtils.h
layout/generic/moz.build
layout/generic/nsGridContainerFrame.cpp
new file mode 100644
--- /dev/null
+++ b/layout/generic/CSSAlignUtils.cpp
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Utility code for performing CSS Box Alignment */
+
+#include "CSSAlignUtils.h"
+
+namespace mozilla {
+
+static nscoord
+SpaceToFill(WritingMode aWM, const LogicalSize& aSize, nscoord aMargin,
+            LogicalAxis aAxis, nscoord aCBSize)
+{
+  nscoord size = aAxis == eLogicalAxisBlock ? aSize.BSize(aWM)
+                                            : aSize.ISize(aWM);
+  return aCBSize - (size + aMargin);
+}
+
+nscoord
+CSSAlignUtils::AlignJustifySelf(uint8_t aAlignment, bool aOverflowSafe,
+                                LogicalAxis aAxis, bool aSameSide,
+                                nscoord aBaselineAdjust, nscoord aCBSize,
+                                const ReflowInput& aRI,
+                                const LogicalSize& aChildSize)
+{
+  MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_AUTO,
+             "auto values should have resolved already");
+  MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_LEFT &&
+             aAlignment != NS_STYLE_ALIGN_RIGHT,
+             "caller should map that to the corresponding START/END");
+
+  // Map some alignment values to 'start' / 'end'.
+  switch (aAlignment) {
+    case NS_STYLE_ALIGN_SELF_START: // align/justify-self: self-start
+      aAlignment = MOZ_LIKELY(aSameSide) ? NS_STYLE_ALIGN_START
+                                         : NS_STYLE_ALIGN_END;
+      break;
+    case NS_STYLE_ALIGN_SELF_END: // align/justify-self: self-end
+      aAlignment = MOZ_LIKELY(aSameSide) ? NS_STYLE_ALIGN_END
+                                         : NS_STYLE_ALIGN_START;
+      break;
+    case NS_STYLE_ALIGN_FLEX_START: // same as 'start' for Grid
+      aAlignment = NS_STYLE_ALIGN_START;
+      break;
+    case NS_STYLE_ALIGN_FLEX_END: // same as 'end' for Grid
+      aAlignment = NS_STYLE_ALIGN_END;
+      break;
+  }
+
+  // XXX try to condense this code a bit by adding the necessary convenience
+  // methods? (bug 1209710)
+
+  // Get the item's margin corresponding to the container's start/end side.
+  const LogicalMargin margin = aRI.ComputedLogicalMargin();
+  WritingMode wm = aRI.GetWritingMode();
+  nscoord marginStart, marginEnd;
+  if (aAxis == eLogicalAxisBlock) {
+    if (MOZ_LIKELY(aSameSide)) {
+      marginStart = margin.BStart(wm);
+      marginEnd = margin.BEnd(wm);
+    } else {
+      marginStart = margin.BEnd(wm);
+      marginEnd = margin.BStart(wm);
+    }
+  } else {
+    if (MOZ_LIKELY(aSameSide)) {
+      marginStart = margin.IStart(wm);
+      marginEnd = margin.IEnd(wm);
+    } else {
+      marginStart = margin.IEnd(wm);
+      marginEnd = margin.IStart(wm);
+    }
+  }
+
+  const auto& styleMargin = aRI.mStyleMargin->mMargin;
+  bool hasAutoMarginStart;
+  bool hasAutoMarginEnd;
+  if (aAxis == eLogicalAxisBlock) {
+    hasAutoMarginStart = styleMargin.GetBStartUnit(wm) == eStyleUnit_Auto;
+    hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
+  } else {
+    hasAutoMarginStart = styleMargin.GetIStartUnit(wm) == eStyleUnit_Auto;
+    hasAutoMarginEnd = styleMargin.GetIEndUnit(wm) == eStyleUnit_Auto;
+  }
+
+  // https://drafts.csswg.org/css-align-3/#overflow-values
+  // This implements <overflow-position> = 'safe'.
+  // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
+  if ((MOZ_UNLIKELY(aOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) ||
+      hasAutoMarginStart || hasAutoMarginEnd) {
+    nscoord space = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
+                                aAxis, aCBSize);
+    // XXX we might want to include == 0 here as an optimization -
+    // I need to see what the baseline/last-baseline code looks like first.
+    if (space < 0) {
+      // "Overflowing elements ignore their auto margins and overflow
+      // in the end directions"
+      aAlignment = NS_STYLE_ALIGN_START;
+    } else if (hasAutoMarginEnd) {
+      aAlignment = hasAutoMarginStart ? NS_STYLE_ALIGN_CENTER
+                                      : (aSameSide ? NS_STYLE_ALIGN_START
+                                                   : NS_STYLE_ALIGN_END);
+    } else if (hasAutoMarginStart) {
+      aAlignment = aSameSide ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
+    }
+  }
+
+  // Determine the offset for the child frame (its border-box) which will
+  // achieve the requested alignment.
+  nscoord offset = 0;
+  switch (aAlignment) {
+    case NS_STYLE_ALIGN_BASELINE:
+    case NS_STYLE_ALIGN_LAST_BASELINE:
+      if (MOZ_LIKELY(aSameSide == (aAlignment == NS_STYLE_ALIGN_BASELINE))) {
+        offset = marginStart + aBaselineAdjust;
+      } else {
+        nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
+                                                  : aChildSize.ISize(wm);
+        offset = aCBSize - (size + marginEnd) - aBaselineAdjust;
+      }
+      break;
+    case NS_STYLE_ALIGN_STRETCH:
+      MOZ_FALLTHROUGH; // ComputeSize() deals with it
+    case NS_STYLE_ALIGN_START:
+      offset = marginStart;
+      break;
+    case NS_STYLE_ALIGN_END: {
+      nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
+                                                : aChildSize.ISize(wm);
+      offset = aCBSize - (size + marginEnd);
+      break;
+    }
+    case NS_STYLE_ALIGN_CENTER: {
+      nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
+                                                : aChildSize.ISize(wm);
+      offset = (aCBSize - size + marginStart - marginEnd) / 2;
+      break;
+    }
+    default:
+      MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
+  }
+
+  return offset;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/generic/CSSAlignUtils.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Utility code for performing CSS Box Alignment */
+
+#ifndef mozilla_CSSAlignUtils_h
+#define mozilla_CSSAlignUtils_h
+
+#include "mozilla/WritingModes.h"
+
+namespace mozilla {
+
+class CSSAlignUtils {
+public:
+  /**
+   * This computes the aligned offset of a CSS-aligned child within its
+   * alignment container. The returned offset is distance between the
+   * logical "start" edge of the alignment container & the logical "start" edge
+   * of the aligned child (in terms of the alignment container's writing mode).
+   *
+   * @param aAlignment An enumerated value representing a keyword for
+   *                   "align-self" or "justify-self". The values
+   *                   NS_STYLE_ALIGN_{AUTO,LEFT,RIGHT} must *not* be
+   *                   passed here; this method expects the caller to have
+   *                   already resolved those to 'start', 'end', or 'stretch'.
+   * @param aOverflowSafe Indicates whether we have <overflow-position> = safe.
+   * @param aAxis The container's axis in which we're doing alignment.
+   * @param aSameSide Indicates whether the container's start side in aAxis is
+   *                  the same as the child's start side, in the child's
+   *                  parallel axis.
+   * @param aBaselineAdjust The amount to offset baseline-aligned children.
+   * @param aCBSize The size of the alignment container, in its aAxis.
+   * @param aRI A ReflowInput for the child.
+   * @param aChildSize The child's LogicalSize (in its own writing mode).
+   */
+  static nscoord AlignJustifySelf(uint8_t aAlignment, bool aOverflowSafe,
+                                  LogicalAxis aAxis, bool aSameSide,
+                                  nscoord aBaselineAdjust, nscoord aCBSize,
+                                  const ReflowInput& aRI,
+                                  const LogicalSize& aChildSize);
+};
+
+} // namespace mozilla
+
+#endif // mozilla_CSSAlignUtils_h
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -104,32 +104,34 @@ EXPORTS += [
     'nsTextRunTransformations.h',
     'RubyUtils.h',
     'ScrollbarActivity.h',
     'ScrollSnap.h',
     'Visibility.h',
 ]
 
 EXPORTS.mozilla += [
+    'CSSAlignUtils.h',
     'ReflowInput.h',
     'ReflowOutput.h',
     'WritingModes.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'Selection.h',
 ]
 
 EXPORTS.mozilla.layout += [
     'FrameChildList.h',
 ]
 
 UNIFIED_SOURCES += [
     'AsyncScrollBase.cpp',
     'BlockReflowInput.cpp',
+    'CSSAlignUtils.cpp',
     'DetailsFrame.cpp',
     'FrameChildList.cpp',
     'MathMLTextRunFactory.cpp',
     'nsAbsoluteContainingBlock.cpp',
     'nsBackdropFrame.cpp',
     'nsBlockFrame.cpp',
     'nsBlockReflowContext.cpp',
     'nsBRFrame.cpp',
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -5,16 +5,17 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: grid | inline-grid" */
 
 #include "nsGridContainerFrame.h"
 
 #include <algorithm> // for std::stable_sort
 #include <limits>
+#include "mozilla/CSSAlignUtils.h"
 #include "mozilla/Function.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/PodOperations.h" // for PodZero
 #include "mozilla/Poison.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsAlgorithm.h" // for clamped()
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSFrameConstructor.h"
@@ -2578,148 +2579,35 @@ GetDisplayFlagsForGridItem(nsIFrame* aFr
 {
   const nsStylePosition* pos = aFrame->StylePosition();
   if (pos->mZIndex.GetUnit() == eStyleUnit_Integer) {
     return nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT;
   }
   return nsIFrame::DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT;
 }
 
-static nscoord
-SpaceToFill(WritingMode aWM, const LogicalSize& aSize, nscoord aMargin,
-            LogicalAxis aAxis, nscoord aCBSize)
-{
-  nscoord size = aAxis == eLogicalAxisBlock ? aSize.BSize(aWM)
-                                            : aSize.ISize(aWM);
-  return aCBSize - (size + aMargin);
-}
-
 // Align an item's margin box in its aAxis inside aCBSize.
 static void
 AlignJustifySelf(uint8_t aAlignment, bool aOverflowSafe, LogicalAxis aAxis,
                  bool aSameSide, nscoord aBaselineAdjust, nscoord aCBSize,
                  const ReflowInput& aRI, const LogicalSize& aChildSize,
                  LogicalPoint* aPos)
 {
   MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_AUTO, "unexpected 'auto' "
              "computed value for normal flow grid item");
-  MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_LEFT &&
-             aAlignment != NS_STYLE_ALIGN_RIGHT,
-             "caller should map that to the corresponding START/END");
-
-  // Map some alignment values to 'start' / 'end'.
-  switch (aAlignment) {
-    case NS_STYLE_ALIGN_SELF_START: // align/justify-self: self-start
-      aAlignment = MOZ_LIKELY(aSameSide) ? NS_STYLE_ALIGN_START
-                                         : NS_STYLE_ALIGN_END;
-      break;
-    case NS_STYLE_ALIGN_SELF_END: // align/justify-self: self-end
-      aAlignment = MOZ_LIKELY(aSameSide) ? NS_STYLE_ALIGN_END
-                                         : NS_STYLE_ALIGN_START;
-      break;
-    case NS_STYLE_ALIGN_FLEX_START: // same as 'start' for Grid
-      aAlignment = NS_STYLE_ALIGN_START;
-      break;
-    case NS_STYLE_ALIGN_FLEX_END: // same as 'end' for Grid
-      aAlignment = NS_STYLE_ALIGN_END;
-      break;
-  }
-
-  // XXX try to condense this code a bit by adding the necessary convenience
-  // methods? (bug 1209710)
-
-  // Get the item's margin corresponding to the container's start/end side.
-  const LogicalMargin margin = aRI.ComputedLogicalMargin();
-  WritingMode wm = aRI.GetWritingMode();
-  nscoord marginStart, marginEnd;
-  if (aAxis == eLogicalAxisBlock) {
-    if (MOZ_LIKELY(aSameSide)) {
-      marginStart = margin.BStart(wm);
-      marginEnd = margin.BEnd(wm);
-    } else {
-      marginStart = margin.BEnd(wm);
-      marginEnd = margin.BStart(wm);
-    }
-  } else {
-    if (MOZ_LIKELY(aSameSide)) {
-      marginStart = margin.IStart(wm);
-      marginEnd = margin.IEnd(wm);
-    } else {
-      marginStart = margin.IEnd(wm);
-      marginEnd = margin.IStart(wm);
-    }
-  }
-
-  const auto& styleMargin = aRI.mStyleMargin->mMargin;
-  bool hasAutoMarginStart;
-  bool hasAutoMarginEnd;
-  if (aAxis == eLogicalAxisBlock) {
-    hasAutoMarginStart = styleMargin.GetBStartUnit(wm) == eStyleUnit_Auto;
-    hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
-  } else {
-    hasAutoMarginStart = styleMargin.GetIStartUnit(wm) == eStyleUnit_Auto;
-    hasAutoMarginEnd = styleMargin.GetIEndUnit(wm) == eStyleUnit_Auto;
-  }
-
-  // https://drafts.csswg.org/css-align-3/#overflow-values
-  // This implements <overflow-position> = 'safe'.
-  // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
-  if ((MOZ_UNLIKELY(aOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) ||
-      hasAutoMarginStart || hasAutoMarginEnd) {
-    nscoord space = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
-                                aAxis, aCBSize);
-    // XXX we might want to include == 0 here as an optimization -
-    // I need to see what the baseline/last-baseline code looks like first.
-    if (space < 0) {
-      // "Overflowing elements ignore their auto margins and overflow
-      // in the end directions"
-      aAlignment = NS_STYLE_ALIGN_START;
-    } else if (hasAutoMarginEnd) {
-      aAlignment = hasAutoMarginStart ? NS_STYLE_ALIGN_CENTER
-                                      : (aSameSide ? NS_STYLE_ALIGN_START
-                                                   : NS_STYLE_ALIGN_END);
-    } else if (hasAutoMarginStart) {
-      aAlignment = aSameSide ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
-    }
-  }
+
+  // NOTE: this is the resulting frame offset (border box).
+  nscoord offset =
+    CSSAlignUtils::AlignJustifySelf(aAlignment, aOverflowSafe, aAxis,
+                                    aSameSide, aBaselineAdjust, aCBSize,
+                                    aRI, aChildSize);
 
   // Set the position (aPos) for the requested alignment.
-  nscoord offset = 0; // NOTE: this is the resulting frame offset (border box).
-  switch (aAlignment) {
-    case NS_STYLE_ALIGN_BASELINE:
-    case NS_STYLE_ALIGN_LAST_BASELINE:
-      if (MOZ_LIKELY(aSameSide == (aAlignment == NS_STYLE_ALIGN_BASELINE))) {
-        offset = marginStart + aBaselineAdjust;
-      } else {
-        nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
-                                                  : aChildSize.ISize(wm);
-        offset = aCBSize - (size + marginEnd) - aBaselineAdjust;
-      }
-      break;
-    case NS_STYLE_ALIGN_STRETCH:
-      MOZ_FALLTHROUGH; // ComputeSize() deals with it
-    case NS_STYLE_ALIGN_START:
-      offset = marginStart;
-      break;
-    case NS_STYLE_ALIGN_END: {
-      nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
-                                                : aChildSize.ISize(wm);
-      offset = aCBSize - (size + marginEnd);
-      break;
-    }
-    case NS_STYLE_ALIGN_CENTER: {
-      nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
-                                                : aChildSize.ISize(wm);
-      offset = (aCBSize - size + marginStart - marginEnd) / 2;
-      break;
-    }
-    default:
-      MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
-  }
   if (offset != 0) {
+    WritingMode wm = aRI.GetWritingMode();
     nscoord& pos = aAxis == eLogicalAxisBlock ? aPos->B(wm) : aPos->I(wm);
     pos += MOZ_LIKELY(aSameSide) ? offset : -offset;
   }
 }
 
 static void
 AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
           uint8_t aAlignSelf, nscoord aCBSize, const WritingMode aCBWM,