gecko-dev/layout/generic/CSSAlignUtils.cpp
Emilio Cobos Álvarez 8101ae2ea8 Bug 1523071 - Use Rust lengths for margin / padding / inset. r=jwatt
Also for the intersection observer root margin, since it was easier to fix it
up and clean it up than not doing it.

This is the first big step to get rid of nscoord. It duplicates a bit of logic
in nsLayoutUtils since for now max/min-width/height are still represented with
nsStyleCoord, but I think I prefer to land this incrementally.

I didn't add helpers for the physical accessors of the style rect sides that
nsStyleSides has (top/bottom/left/right) since I think we generally should
encourage the logical versions, but let me know if you want me to do that.

Differential Revision: https://phabricator.services.mozilla.com/D17739
2019-02-10 04:11:58 +01:00

155 lines
5.9 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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"
#include "ReflowInput.h"
namespace mozilla {
static nscoord SpaceToFill(WritingMode aWM, const LogicalSize& aSize,
nscoord aMargin, LogicalAxis aAxis,
nscoord aCBSize) {
nscoord size = aSize.Size(aAxis, aWM);
return aCBSize - (size + aMargin);
}
nscoord CSSAlignUtils::AlignJustifySelf(uint8_t aAlignment, LogicalAxis aAxis,
AlignJustifyFlags aFlags,
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");
// Promote aFlags to convenience bools:
const bool isOverflowSafe = !!(aFlags & AlignJustifyFlags::eOverflowSafe);
const bool isSameSide = !!(aFlags & AlignJustifyFlags::eSameSide);
// Map some alignment values to 'start' / 'end'.
switch (aAlignment) {
case NS_STYLE_ALIGN_SELF_START: // align/justify-self: self-start
aAlignment =
MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_START : NS_STYLE_ALIGN_END;
break;
case NS_STYLE_ALIGN_SELF_END: // align/justify-self: self-end
aAlignment =
MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
break;
// flex-start/flex-end are the same as start/end, in most contexts.
// (They have special behavior in flex containers, so flex containers
// should map them to some other value before calling this method.)
case NS_STYLE_ALIGN_FLEX_START:
aAlignment = NS_STYLE_ALIGN_START;
break;
case NS_STYLE_ALIGN_FLEX_END:
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(isSameSide)) {
marginStart = margin.BStart(wm);
marginEnd = margin.BEnd(wm);
} else {
marginStart = margin.BEnd(wm);
marginEnd = margin.BStart(wm);
}
} else {
if (MOZ_LIKELY(isSameSide)) {
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 (aFlags & AlignJustifyFlags::eIgnoreAutoMargins) {
// (Note: ReflowInput will have treated "auto" margins as 0, so we
// don't need to do anything special to avoid expanding them.)
hasAutoMarginStart = hasAutoMarginEnd = false;
} else if (aAxis == eLogicalAxisBlock) {
hasAutoMarginStart = styleMargin.GetBStart(wm).IsAuto();
hasAutoMarginEnd = styleMargin.GetBEnd(wm).IsAuto();
} else { /* aAxis == eLogicalAxisInline */
hasAutoMarginStart = styleMargin.GetIStart(wm).IsAuto();
hasAutoMarginEnd = styleMargin.GetIEnd(wm).IsAuto();
}
// 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(isOverflowSafe) && 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
: (isSameSide ? NS_STYLE_ALIGN_START
: NS_STYLE_ALIGN_END);
} else if (hasAutoMarginStart) {
aAlignment = isSameSide ? 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(isSameSide == (aAlignment == NS_STYLE_ALIGN_BASELINE))) {
offset = marginStart + aBaselineAdjust;
} else {
nscoord size = aChildSize.Size(aAxis, 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 = aChildSize.Size(aAxis, wm);
offset = aCBSize - (size + marginEnd);
break;
}
case NS_STYLE_ALIGN_CENTER: {
nscoord size = aChildSize.Size(aAxis, wm);
offset = (aCBSize - size + marginStart - marginEnd) / 2;
break;
}
default:
MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
}
return offset;
}
} // namespace mozilla