1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Utility code for performing CSS Box Alignment */
9 #include "CSSAlignUtils.h"
10 #include "ReflowInput.h"
14 static nscoord
SpaceToFill(WritingMode aWM
, const LogicalSize
& aSize
,
15 nscoord aMargin
, LogicalAxis aAxis
,
17 nscoord size
= aSize
.Size(aAxis
, aWM
);
18 return aCBSize
- (size
+ aMargin
);
21 nscoord
CSSAlignUtils::AlignJustifySelf(const StyleAlignFlags
& aAlignment
,
23 AlignJustifyFlags aFlags
,
24 nscoord aBaselineAdjust
,
25 nscoord aCBSize
, const ReflowInput
& aRI
,
26 const LogicalSize
& aChildSize
) {
27 MOZ_ASSERT(aAlignment
!= StyleAlignFlags::AUTO
,
28 "auto values should have resolved already");
29 MOZ_ASSERT(aAlignment
!= StyleAlignFlags::LEFT
&&
30 aAlignment
!= StyleAlignFlags::RIGHT
,
31 "caller should map that to the corresponding START/END");
33 // Promote aFlags to convenience bools:
34 const bool isOverflowSafe
= !!(aFlags
& AlignJustifyFlags::OverflowSafe
);
35 const bool isSameSide
= !!(aFlags
& AlignJustifyFlags::SameSide
);
37 StyleAlignFlags alignment
= aAlignment
;
38 // Map some alignment values to 'start' / 'end'.
39 if (alignment
== StyleAlignFlags::SELF_START
) {
40 // align/justify-self: self-start
42 MOZ_LIKELY(isSameSide
) ? StyleAlignFlags::START
: StyleAlignFlags::END
;
43 } else if (alignment
== StyleAlignFlags::SELF_END
) {
45 MOZ_LIKELY(isSameSide
) ? StyleAlignFlags::END
: StyleAlignFlags::START
;
46 // flex-start/flex-end are the same as start/end, in most contexts.
47 // (They have special behavior in flex containers, so flex containers
48 // should map them to some other value before calling this method.)
49 } else if (alignment
== StyleAlignFlags::FLEX_START
) {
50 alignment
= StyleAlignFlags::START
;
51 } else if (alignment
== StyleAlignFlags::FLEX_END
) {
52 alignment
= StyleAlignFlags::END
;
55 // Get the item's margin corresponding to the container's start/end side.
56 WritingMode wm
= aRI
.GetWritingMode();
57 const LogicalMargin margin
= aRI
.ComputedLogicalMargin(wm
);
58 const auto startSide
= MakeLogicalSide(
59 aAxis
, MOZ_LIKELY(isSameSide
) ? eLogicalEdgeStart
: eLogicalEdgeEnd
);
60 const nscoord marginStart
= margin
.Side(startSide
, wm
);
61 const auto endSide
= GetOppositeSide(startSide
);
62 const nscoord marginEnd
= margin
.Side(endSide
, wm
);
64 const auto& styleMargin
= aRI
.mStyleMargin
->mMargin
;
65 bool hasAutoMarginStart
;
66 bool hasAutoMarginEnd
;
67 if (aFlags
& AlignJustifyFlags::IgnoreAutoMargins
) {
68 // (Note: ReflowInput will have treated "auto" margins as 0, so we
69 // don't need to do anything special to avoid expanding them.)
70 hasAutoMarginStart
= hasAutoMarginEnd
= false;
71 } else if (aAxis
== eLogicalAxisBlock
) {
72 hasAutoMarginStart
= styleMargin
.GetBStart(wm
).IsAuto();
73 hasAutoMarginEnd
= styleMargin
.GetBEnd(wm
).IsAuto();
74 } else { /* aAxis == eLogicalAxisInline */
75 hasAutoMarginStart
= styleMargin
.GetIStart(wm
).IsAuto();
76 hasAutoMarginEnd
= styleMargin
.GetIEnd(wm
).IsAuto();
79 // https://drafts.csswg.org/css-align-3/#overflow-values
80 // This implements <overflow-position> = 'safe'.
81 // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
82 if ((MOZ_UNLIKELY(isOverflowSafe
) && alignment
!= StyleAlignFlags::START
) ||
83 hasAutoMarginStart
|| hasAutoMarginEnd
) {
85 SpaceToFill(wm
, aChildSize
, marginStart
+ marginEnd
, aAxis
, aCBSize
);
86 // XXX we might want to include == 0 here as an optimization -
87 // I need to see what the baseline/last baseline code looks like first.
89 // "Overflowing elements ignore their auto margins and overflow
90 // in the end directions"
91 alignment
= StyleAlignFlags::START
;
92 } else if (hasAutoMarginEnd
) {
93 alignment
= hasAutoMarginStart
? StyleAlignFlags::CENTER
94 : (isSameSide
? StyleAlignFlags::START
95 : StyleAlignFlags::END
);
96 } else if (hasAutoMarginStart
) {
97 alignment
= isSameSide
? StyleAlignFlags::END
: StyleAlignFlags::START
;
101 // Determine the offset for the child frame (its border-box) which will
102 // achieve the requested alignment.
104 if (alignment
== StyleAlignFlags::BASELINE
||
105 alignment
== StyleAlignFlags::LAST_BASELINE
) {
106 if (MOZ_LIKELY(isSameSide
== (alignment
== StyleAlignFlags::BASELINE
))) {
107 offset
= marginStart
+ aBaselineAdjust
;
109 nscoord size
= aChildSize
.Size(aAxis
, wm
);
110 offset
= aCBSize
- (size
+ marginEnd
) - aBaselineAdjust
;
112 } else if (alignment
== StyleAlignFlags::STRETCH
||
113 alignment
== StyleAlignFlags::START
) {
114 // ComputeSize() deals with stretch
115 offset
= marginStart
;
116 } else if (alignment
== StyleAlignFlags::END
) {
117 nscoord size
= aChildSize
.Size(aAxis
, wm
);
118 offset
= aCBSize
- (size
+ marginEnd
);
119 } else if (alignment
== StyleAlignFlags::CENTER
) {
120 nscoord size
= aChildSize
.Size(aAxis
, wm
);
121 offset
= (aCBSize
- size
+ marginStart
- marginEnd
) / 2;
123 MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
129 } // namespace mozilla