зеркало из https://github.com/mozilla/gecko-dev.git
155 строки
5.9 KiB
C++
155 строки
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::OverflowSafe);
|
|
const bool isSameSide = !!(aFlags & AlignJustifyFlags::SameSide);
|
|
|
|
// 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::IgnoreAutoMargins) {
|
|
// (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:
|
|
[[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
|