Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* Utility code for performing CSS Box Alignment */
7 :
8 : #include "CSSAlignUtils.h"
9 : #include "ReflowInput.h"
10 :
11 : namespace mozilla {
12 :
13 : static nscoord
14 0 : SpaceToFill(WritingMode aWM, const LogicalSize& aSize, nscoord aMargin,
15 : LogicalAxis aAxis, nscoord aCBSize)
16 : {
17 0 : nscoord size = aAxis == eLogicalAxisBlock ? aSize.BSize(aWM)
18 0 : : aSize.ISize(aWM);
19 0 : return aCBSize - (size + aMargin);
20 : }
21 :
22 : nscoord
23 0 : CSSAlignUtils::AlignJustifySelf(uint8_t aAlignment, LogicalAxis aAxis,
24 : AlignJustifyFlags aFlags,
25 : nscoord aBaselineAdjust, nscoord aCBSize,
26 : const ReflowInput& aRI,
27 : const LogicalSize& aChildSize)
28 : {
29 0 : MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_AUTO,
30 : "auto values should have resolved already");
31 0 : MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_LEFT &&
32 : aAlignment != NS_STYLE_ALIGN_RIGHT,
33 : "caller should map that to the corresponding START/END");
34 :
35 : // Promote aFlags to convenience bools:
36 0 : const bool isOverflowSafe = !!(aFlags & AlignJustifyFlags::eOverflowSafe);
37 0 : const bool isSameSide = !!(aFlags & AlignJustifyFlags::eSameSide);
38 :
39 : // Map some alignment values to 'start' / 'end'.
40 0 : switch (aAlignment) {
41 : case NS_STYLE_ALIGN_SELF_START: // align/justify-self: self-start
42 0 : aAlignment = MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_START
43 0 : : NS_STYLE_ALIGN_END;
44 0 : break;
45 : case NS_STYLE_ALIGN_SELF_END: // align/justify-self: self-end
46 0 : aAlignment = MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_END
47 0 : : NS_STYLE_ALIGN_START;
48 0 : break;
49 : // flex-start/flex-end are the same as start/end, in most contexts.
50 : // (They have special behavior in flex containers, so flex containers
51 : // should map them to some other value before calling this method.)
52 : case NS_STYLE_ALIGN_FLEX_START:
53 0 : aAlignment = NS_STYLE_ALIGN_START;
54 0 : break;
55 : case NS_STYLE_ALIGN_FLEX_END:
56 0 : aAlignment = NS_STYLE_ALIGN_END;
57 0 : break;
58 : }
59 :
60 : // XXX try to condense this code a bit by adding the necessary convenience
61 : // methods? (bug 1209710)
62 :
63 : // Get the item's margin corresponding to the container's start/end side.
64 0 : const LogicalMargin margin = aRI.ComputedLogicalMargin();
65 0 : WritingMode wm = aRI.GetWritingMode();
66 : nscoord marginStart, marginEnd;
67 0 : if (aAxis == eLogicalAxisBlock) {
68 0 : if (MOZ_LIKELY(isSameSide)) {
69 0 : marginStart = margin.BStart(wm);
70 0 : marginEnd = margin.BEnd(wm);
71 : } else {
72 0 : marginStart = margin.BEnd(wm);
73 0 : marginEnd = margin.BStart(wm);
74 : }
75 : } else {
76 0 : if (MOZ_LIKELY(isSameSide)) {
77 0 : marginStart = margin.IStart(wm);
78 0 : marginEnd = margin.IEnd(wm);
79 : } else {
80 0 : marginStart = margin.IEnd(wm);
81 0 : marginEnd = margin.IStart(wm);
82 : }
83 : }
84 :
85 0 : const auto& styleMargin = aRI.mStyleMargin->mMargin;
86 : bool hasAutoMarginStart;
87 : bool hasAutoMarginEnd;
88 0 : if (aFlags & AlignJustifyFlags::eIgnoreAutoMargins) {
89 : // (Note: ReflowInput will have treated "auto" margins as 0, so we
90 : // don't need to do anything special to avoid expanding them.)
91 0 : hasAutoMarginStart = hasAutoMarginEnd = false;
92 0 : } else if (aAxis == eLogicalAxisBlock) {
93 0 : hasAutoMarginStart = styleMargin.GetBStartUnit(wm) == eStyleUnit_Auto;
94 0 : hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
95 : } else { /* aAxis == eLogicalAxisInline */
96 0 : hasAutoMarginStart = styleMargin.GetIStartUnit(wm) == eStyleUnit_Auto;
97 0 : hasAutoMarginEnd = styleMargin.GetIEndUnit(wm) == eStyleUnit_Auto;
98 : }
99 :
100 : // https://drafts.csswg.org/css-align-3/#overflow-values
101 : // This implements <overflow-position> = 'safe'.
102 : // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
103 0 : if ((MOZ_UNLIKELY(isOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) ||
104 0 : hasAutoMarginStart || hasAutoMarginEnd) {
105 0 : nscoord space = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
106 0 : aAxis, aCBSize);
107 : // XXX we might want to include == 0 here as an optimization -
108 : // I need to see what the baseline/last baseline code looks like first.
109 0 : if (space < 0) {
110 : // "Overflowing elements ignore their auto margins and overflow
111 : // in the end directions"
112 0 : aAlignment = NS_STYLE_ALIGN_START;
113 0 : } else if (hasAutoMarginEnd) {
114 0 : aAlignment = hasAutoMarginStart ? NS_STYLE_ALIGN_CENTER
115 : : (isSameSide ? NS_STYLE_ALIGN_START
116 0 : : NS_STYLE_ALIGN_END);
117 0 : } else if (hasAutoMarginStart) {
118 0 : aAlignment = isSameSide ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
119 : }
120 : }
121 :
122 : // Determine the offset for the child frame (its border-box) which will
123 : // achieve the requested alignment.
124 0 : nscoord offset = 0;
125 0 : switch (aAlignment) {
126 : case NS_STYLE_ALIGN_BASELINE:
127 : case NS_STYLE_ALIGN_LAST_BASELINE:
128 0 : if (MOZ_LIKELY(isSameSide == (aAlignment == NS_STYLE_ALIGN_BASELINE))) {
129 0 : offset = marginStart + aBaselineAdjust;
130 : } else {
131 0 : nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
132 0 : : aChildSize.ISize(wm);
133 0 : offset = aCBSize - (size + marginEnd) - aBaselineAdjust;
134 : }
135 0 : break;
136 : case NS_STYLE_ALIGN_STRETCH:
137 : MOZ_FALLTHROUGH; // ComputeSize() deals with it
138 : case NS_STYLE_ALIGN_START:
139 0 : offset = marginStart;
140 0 : break;
141 : case NS_STYLE_ALIGN_END: {
142 0 : nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
143 0 : : aChildSize.ISize(wm);
144 0 : offset = aCBSize - (size + marginEnd);
145 0 : break;
146 : }
147 : case NS_STYLE_ALIGN_CENTER: {
148 0 : nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
149 0 : : aChildSize.ISize(wm);
150 0 : offset = (aCBSize - size + marginStart - marginEnd) / 2;
151 0 : break;
152 : }
153 : default:
154 0 : MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
155 : }
156 :
157 0 : return offset;
158 : }
159 :
160 : } // namespace mozilla
|