summaryrefslogtreecommitdiffstats
path: root/layout/generic/CSSAlignUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/CSSAlignUtils.cpp')
-rw-r--r--layout/generic/CSSAlignUtils.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/layout/generic/CSSAlignUtils.cpp b/layout/generic/CSSAlignUtils.cpp
new file mode 100644
index 000000000..4cbaccd52
--- /dev/null
+++ b/layout/generic/CSSAlignUtils.cpp
@@ -0,0 +1,159 @@
+/* -*- 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, 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.GetBStartUnit(wm) == eStyleUnit_Auto;
+ hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
+ } else { /* aAxis == eLogicalAxisInline */
+ 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(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 = 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