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
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,