Bug 1269046 part 1: Spin out some grid alignment code into a helper method, in a new CSSAlignUtils class. r=mats
☠☠ backed out by 7c24f4455420 ☠ ☠
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 27 Oct 2016 18:58:26 -0700
changeset 319777 539db74e4a889a6dc0605f91ff40ab7e748b996d
parent 319776 f57f9ac1435edc2d581c4645fa818ffd665d68f7
child 319778 eb4b52bf06ec8c1f5b33cfba7255a0d4bb64c168
push id83250
push userdholbert@mozilla.com
push dateFri, 28 Oct 2016 01:59:30 +0000
treeherdermozilla-inbound@16db55b642a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1269046
milestone52.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 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"
@@ -2577,148 +2578,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,