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
This commit is contained in:
Daniel Holbert 2016-10-31 08:58:18 -07:00
parent d7a39cb724
commit 2a8bcc81e7
4 changed files with 204 additions and 119 deletions

View File

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

View File

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

View File

@ -109,6 +109,7 @@ EXPORTS += [
]
EXPORTS.mozilla += [
'CSSAlignUtils.h',
'ReflowInput.h',
'ReflowOutput.h',
'WritingModes.h',
@ -125,6 +126,7 @@ EXPORTS.mozilla.layout += [
UNIFIED_SOURCES += [
'AsyncScrollBase.cpp',
'BlockReflowInput.cpp',
'CSSAlignUtils.cpp',
'DetailsFrame.cpp',
'FrameChildList.cpp',
'MathMLTextRunFactory.cpp',

View File

@ -10,6 +10,7 @@
#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
@ -2583,15 +2584,6 @@ GetDisplayFlagsForGridItem(nsIFrame* aFrame)
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,
@ -2601,120 +2593,16 @@ AlignJustifySelf(uint8_t aAlignment, bool aOverflowSafe, LogicalAxis aAxis,
{
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;
}