Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic/./../../../layout/generic/nsGridContainerFrame.cpp
Warning:line 6591, column 13
Value stored to 'baselineTrack' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_layout_generic2.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/layout/generic -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/forms -I /root/firefox-clang/layout/painting -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/tables -I /root/firefox-clang/layout/xul -I /root/firefox-clang/docshell/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/html -I /root/firefox-clang/dom/xul -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_layout_generic2.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/* rendering object for CSS "display: grid | inline-grid" */
6
7#include "nsGridContainerFrame.h"
8
9#include <stdlib.h> // for div()
10
11#include <functional>
12#include <type_traits>
13
14#ifdef DEBUG1
15# include "fmt/base.h"
16#endif
17#include "gfxContext.h"
18#include "mozilla/AbsoluteContainingBlock.h"
19#include "mozilla/AutoRestore.h"
20#include "mozilla/Baseline.h"
21#include "mozilla/CSSAlignUtils.h"
22#include "mozilla/ComputedStyle.h"
23#include "mozilla/IntegerRange.h"
24#include "mozilla/Maybe.h"
25#include "mozilla/PodOperations.h" // for PodZero
26#include "mozilla/PresShell.h"
27#include "mozilla/ReflowInput.h"
28#include "mozilla/ScrollContainerFrame.h"
29#include "mozilla/StaticPrefs_layout.h"
30#include "mozilla/dom/Grid.h"
31#include "mozilla/dom/GridBinding.h"
32#include "nsCSSFrameConstructor.h"
33#include "nsDisplayList.h"
34#include "nsFieldSetFrame.h"
35#include "nsHashKeys.h"
36#include "nsIFrameInlines.h" // for nsIFrame::GetLogicalNormalPosition (don't remove)
37#include "nsLayoutUtils.h"
38#include "nsPlaceholderFrame.h"
39#include "nsPresContext.h"
40#include "nsReadableUtils.h"
41#include "nsTableWrapperFrame.h"
42
43using namespace mozilla;
44
45using AlignJustifyFlag = CSSAlignUtils::AlignJustifyFlag;
46using AlignJustifyFlags = CSSAlignUtils::AlignJustifyFlags;
47using GridItemCachedBAxisMeasurement =
48 nsGridContainerFrame::CachedBAxisMeasurement;
49using GridTemplate = StyleGridTemplateComponent;
50using NameList = StyleOwnedSlice<StyleCustomIdent>;
51using SizingConstraint = nsGridContainerFrame::SizingConstraint;
52using TrackListValue =
53 StyleGenericTrackListValue<LengthPercentage, StyleInteger>;
54using TrackRepeat = StyleGenericTrackRepeat<LengthPercentage, StyleInteger>;
55using TrackSize = nsGridContainerFrame::TrackSize;
56
57static mozilla::LazyLogModule gGridContainerLog("GridContainer");
58#define GRID_LOG(...)do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, ...); } } while (0);
\
59 MOZ_LOG(gGridContainerLog, LogLevel::Debug, (__VA_ARGS__))do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, __VA_ARGS__); } } while (0)
;
60
61// These are the limits that we choose to clamp grid line numbers to.
62// http://drafts.csswg.org/css-grid/#overlarge-grids
63static const int32_t kMaxLine = 10000;
64static const int32_t kMinLine = -10000;
65static const int32_t kMaxTrack = kMaxLine - 1;
66
67// The maximum line number, in the zero-based translated grid.
68static const uint32_t kTranslatedMaxLine = uint32_t(kMaxLine - kMinLine);
69static const uint32_t kAutoLine = kTranslatedMaxLine + 3457U;
70
71static const nsFrameState kIsSubgridBits =
72 (NS_STATE_GRID_IS_COL_SUBGRID | NS_STATE_GRID_IS_ROW_SUBGRID);
73
74namespace mozilla {
75
76template <>
77inline Span<const StyleOwnedSlice<StyleCustomIdent>>
78GridTemplate::LineNameLists() const {
79 if (IsTrackList()) {
80 return AsTrackList()->line_names.AsSpan();
81 }
82 MOZ_ASSERT(IsNone() || IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNone() || IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNone() || IsSubgrid()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsNone() || IsSubgrid()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 82); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsNone() || IsSubgrid()" ")"); do { MOZ_CrashSequence
(__null, 82); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
83 return {};
84}
85
86template <>
87inline const StyleTrackBreadth& StyleTrackSize::GetMax() const {
88 if (IsBreadth()) {
89 return AsBreadth();
90 }
91 if (IsMinmax()) {
92 return AsMinmax()._1;
93 }
94 MOZ_ASSERT(IsFitContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFitContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFitContent()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsFitContent()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 94); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFitContent()" ")"); do { MOZ_CrashSequence
(__null, 94); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
95 return AsFitContent();
96}
97
98template <>
99inline const StyleTrackBreadth& StyleTrackSize::GetMin() const {
100 static const StyleTrackBreadth kAuto = StyleTrackBreadth::Auto();
101 if (IsBreadth()) {
102 // <flex> behaves like minmax(auto, <flex>)
103 return AsBreadth().IsFlex() ? kAuto : AsBreadth();
104 }
105 if (IsMinmax()) {
106 return AsMinmax()._0;
107 }
108 MOZ_ASSERT(IsFitContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFitContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFitContent()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsFitContent()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 108);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFitContent()" ")"
); do { MOZ_CrashSequence(__null, 108); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
109 return kAuto;
110}
111
112} // namespace mozilla
113
114static nscoord ClampToCSSMaxBSize(nscoord aSize,
115 const ReflowInput* aReflowInput) {
116 auto maxSize = aReflowInput->ComputedMaxBSize();
117 if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)(__builtin_expect(!!(maxSize != NS_UNCONSTRAINEDSIZE), 0))) {
118 MOZ_ASSERT(aReflowInput->ComputedMinBSize() <= maxSize)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReflowInput->ComputedMinBSize() <= maxSize)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aReflowInput->ComputedMinBSize() <= maxSize)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aReflowInput->ComputedMinBSize() <= maxSize"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 118);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReflowInput->ComputedMinBSize() <= maxSize"
")"); do { MOZ_CrashSequence(__null, 118); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
119 aSize = std::min(aSize, maxSize);
120 }
121 return aSize;
122}
123
124// Same as above and set aStatus INCOMPLETE if aSize wasn't clamped.
125// (If we clamp aSize it means our size is less than the break point,
126// i.e. we're effectively breaking in our overflow, so we should leave
127// aStatus as is (it will likely be set to OVERFLOW_INCOMPLETE later)).
128static nscoord ClampToCSSMaxBSize(nscoord aSize,
129 const ReflowInput* aReflowInput,
130 nsReflowStatus* aStatus) {
131 auto maxSize = aReflowInput->ComputedMaxBSize();
132 if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)(__builtin_expect(!!(maxSize != NS_UNCONSTRAINEDSIZE), 0))) {
133 MOZ_ASSERT(aReflowInput->ComputedMinBSize() <= maxSize)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReflowInput->ComputedMinBSize() <= maxSize)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aReflowInput->ComputedMinBSize() <= maxSize)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aReflowInput->ComputedMinBSize() <= maxSize"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 133);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReflowInput->ComputedMinBSize() <= maxSize"
")"); do { MOZ_CrashSequence(__null, 133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
134 if (aSize < maxSize) {
135 aStatus->SetIncomplete();
136 } else {
137 aSize = maxSize;
138 }
139 } else {
140 aStatus->SetIncomplete();
141 }
142 return aSize;
143}
144
145template <typename Size>
146static bool IsPercentOfIndefiniteSize(const Size& aCoord,
147 nscoord aPercentBasis) {
148 return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
149}
150
151static nscoord ResolveToDefiniteSize(const StyleTrackBreadth& aBreadth,
152 nscoord aPercentBasis) {
153 MOZ_ASSERT(aBreadth.IsBreadth())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBreadth.IsBreadth())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBreadth.IsBreadth()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aBreadth.IsBreadth()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 153);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBreadth.IsBreadth()"
")"); do { MOZ_CrashSequence(__null, 153); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
154 if (::IsPercentOfIndefiniteSize(aBreadth.AsBreadth(), aPercentBasis)) {
155 return nscoord(0);
156 }
157 return std::max(nscoord(0), aBreadth.AsBreadth().Resolve(aPercentBasis));
158}
159
160// Synthesize a baseline from a border box. For an alphabetical baseline
161// this is the end edge of the border box. For a central baseline it's
162// the center of the border box.
163// https://drafts.csswg.org/css-align-3/#synthesize-baseline
164// For a 'first baseline' the measure is from the border-box start edge and
165// for a 'last baseline' the measure is from the border-box end edge.
166//
167// The 'LogicalAxis aAxis' represents the axis (in terms of aWM) that the
168// baseline corresponds to. (Typically, baselines are a measurement in the
169// block axis; e.g. for English horizontal-tb text, a traditional baseline
170// would be a y-axis measurement. But in some cases (e.g. orthogonal WMs), we
171// may need to synthesize a baseline in a child's inline axis, which is when
172// this function might receive an aAxis of LogicalAxis::Inline. In that case, we
173// assume that the writing mode's preference for central vs. alphabetic
174// baselines is irrelevant, since that's a choice about its block-axis
175// baselines, and we just unconditionally use the alphabetic baseline
176// (e.g. border-box bottom edge).
177static nscoord SynthesizeBaselineFromBorderBox(BaselineSharingGroup aGroup,
178 WritingMode aWM,
179 LogicalAxis aAxis,
180 nscoord aBorderBoxSize) {
181 const bool useAlphabeticBaseline =
182 (aAxis == LogicalAxis::Inline) ? true : aWM.IsAlphabeticalBaseline();
183
184 if (aGroup == BaselineSharingGroup::First) {
185 return useAlphabeticBaseline ? aBorderBoxSize : aBorderBoxSize / 2;
186 }
187 MOZ_ASSERT(aGroup == BaselineSharingGroup::Last)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGroup == BaselineSharingGroup::Last)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGroup == BaselineSharingGroup
::Last))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGroup == BaselineSharingGroup::Last", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 187); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGroup == BaselineSharingGroup::Last"
")"); do { MOZ_CrashSequence(__null, 187); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
188 // Round up for central baseline offset, to be consistent with eFirst.
189 return useAlphabeticBaseline ? 0
190 : (aBorderBoxSize / 2) + (aBorderBoxSize % 2);
191}
192
193// The helper struct to hold the box sizing adjustment.
194struct BoxSizingAdjustment {
195 BoxSizingAdjustment() = delete;
196 BoxSizingAdjustment(const WritingMode aWM, const ComputedStyle& aStyle)
197 : mWM(aWM), mStyle(aStyle) {}
198
199 const LogicalSize& EnsureAndGet() {
200 if (mValue) {
201 return mValue.ref();
202 }
203
204 if (mStyle.StylePosition()->mBoxSizing != StyleBoxSizing::BorderBox) {
205 // Use default, (0, 0).
206 mValue.emplace(mWM);
207 return mValue.ref();
208 }
209
210 const auto& padding = mStyle.StylePadding()->mPadding;
211 LogicalMargin border(mWM, mStyle.StyleBorder()->GetComputedBorder());
212 // We can use zero percentage basis since this is only called from
213 // intrinsic sizing code.
214 const nscoord percentageBasis = 0;
215 const nscoord iBP =
216 std::max(padding.GetIStart(mWM).Resolve(percentageBasis), 0) +
217 std::max(padding.GetIEnd(mWM).Resolve(percentageBasis), 0) +
218 border.IStartEnd(mWM);
219 const nscoord bBP =
220 std::max(padding.GetBStart(mWM).Resolve(percentageBasis), 0) +
221 std::max(padding.GetBEnd(mWM).Resolve(percentageBasis), 0) +
222 border.BStartEnd(mWM);
223 mValue.emplace(mWM, iBP, bBP);
224 return mValue.ref();
225 }
226
227 private:
228 const WritingMode mWM;
229 const ComputedStyle& mStyle;
230 // The wrapped value we would like to use for the box sizing adjustment.
231 Maybe<LogicalSize> mValue;
232};
233
234static Maybe<nscoord> GetPercentageBasisForAR(
235 const LogicalAxis aRatioDeterminingAxis, const WritingMode aWM,
236 const Maybe<LogicalSize>& aContainingBlockSize) {
237 if (!aContainingBlockSize) {
238 return Nothing();
239 }
240
241 const nscoord basis = aContainingBlockSize->Size(aRatioDeterminingAxis, aWM);
242 // If the basis is unconstrained (because we are still computing the
243 // containing block size), we should treat it as no basis.
244 return basis == NS_UNCONSTRAINEDSIZE ? Nothing() : Some(basis);
245}
246
247template <typename Type>
248static Maybe<nscoord> ComputeTransferredSize(
249 const Type& aRatioDeterminingSize, const LogicalAxis aAxis,
250 const WritingMode aWM, const AspectRatio& aAspectRatio,
251 BoxSizingAdjustment& aBoxSizingAdjustment,
252 const Maybe<LogicalSize>& aContainingBlockSize) {
253 // Use GetOrthogonalAxis() to get the ratio-determining axis.
254 const Maybe<nscoord> basis = GetPercentageBasisForAR(
255 GetOrthogonalAxis(aAxis), aWM, aContainingBlockSize);
256 nscoord rdSize = 0;
257 if (aRatioDeterminingSize->ConvertsToLength()) {
258 rdSize = aRatioDeterminingSize->ToLength();
259 } else if (aRatioDeterminingSize->HasPercent() && basis) {
260 rdSize = aRatioDeterminingSize->AsLengthPercentage().Resolve(*basis);
261 } else {
262 // Either we are not using LengthPercentage or there is no percentage basis.
263 return Nothing();
264 }
265 return Some(aAspectRatio.ComputeRatioDependentSize(
266 aAxis, aWM, rdSize, aBoxSizingAdjustment.EnsureAndGet()));
267}
268
269struct MeasuringReflowResult {
270 // The border-box and content-box block-size of the child.
271 nscoord mBSize = 0;
272 nscoord mContentBSize = 0;
273};
274
275// A cached result for a grid item's block-axis measuring reflow. This
276// cache prevents us from doing exponential reflows in cases of deeply
277// nested grid frames.
278//
279// We store the cached value in the grid item's frame property table.
280//
281// We cache the following as a "key"
282// - The size of the grid area in the item's inline axis
283// - The item's block axis baseline padding
284// ...and we cache the following as the "value",
285// - The item's border-box and content-box BSize
286class nsGridContainerFrame::CachedBAxisMeasurement final {
287 public:
288 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, CachedBAxisMeasurement)static const mozilla::FramePropertyDescriptor<CachedBAxisMeasurement
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<CachedBAxisMeasurement>::NewWithDestructor<DeleteValue
>(); return &descriptor; }
289
290 CachedBAxisMeasurement(const nsIFrame* aFrame, const LogicalSize& aCBSize,
291 const MeasuringReflowResult& aResult)
292 : mKey(aFrame, aCBSize), mResult(aResult) {}
293
294 bool IsValidFor(const nsIFrame* aFrame, const LogicalSize& aCBSize) const {
295 if (aFrame->IsSubtreeDirty()) {
296 return false;
297 }
298 return mKey == Key(aFrame, aCBSize);
299 }
300
301 const MeasuringReflowResult& Result() const { return mResult; }
302
303 void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize,
304 const MeasuringReflowResult& aResult) {
305 mKey.Update(aFrame, aCBSize);
306 mResult = aResult;
307 }
308
309 private:
310 struct Key final {
311 nscoord mCBSizeInItemInlineAxis;
312 nscoord mBaselinePaddingInItemBlockAxis;
313
314 Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
315 Update(aFrame, aCBSize);
316 }
317
318 void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
319 mCBSizeInItemInlineAxis = aCBSize.ISize(aFrame->GetWritingMode());
320 mBaselinePaddingInItemBlockAxis =
321 aFrame->GetProperty(nsIFrame::BBaselinePadProperty());
322 }
323
324 bool operator==(const Key& aOther) const = default;
325 };
326
327 Key mKey;
328 MeasuringReflowResult mResult;
329};
330
331// The input sizes for calculating the number of repeat(auto-fill/fit) tracks.
332// https://drafts.csswg.org/css-grid-2/#auto-repeat
333struct RepeatTrackSizingInput {
334 explicit RepeatTrackSizingInput(WritingMode aWM)
335 : mMin(aWM, 0, 0),
336 mSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
337 mMax(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) {}
338
339 RepeatTrackSizingInput(const LogicalSize& aMin, const LogicalSize& aSize,
340 const LogicalSize& aMax)
341 : mMin(aMin), mSize(aSize), mMax(aMax) {}
342
343 // This should be used in intrinsic sizing (i.e. when we can't initialize
344 // the sizes directly from ReflowInput values).
345 void InitFromStyle(LogicalAxis aAxis, WritingMode aWM, const nsIFrame* aFrame,
346 const ComputedStyle* aStyle,
347 const AspectRatio& aAspectRatio,
348 const Maybe<LogicalSize>& aContainingBlockSize) {
349 const auto& pos = aStyle->StylePosition();
350 const AnchorPosResolutionParams anchorResolutionParams{
351 aFrame, aStyle->StyleDisplay()->mPosition};
352 BoxSizingAdjustment boxSizingAdjustment(aWM, *aStyle);
353 const nscoord cbSizeInAxis = aContainingBlockSize
354 ? aContainingBlockSize->Size(aAxis, aWM)
355 : NS_UNCONSTRAINEDSIZE;
356
357 auto adjustForBoxSizing = [aWM, aAxis,
358 &boxSizingAdjustment](nscoord aSize) {
359 return std::max(
360 aSize - boxSizingAdjustment.EnsureAndGet().Size(aAxis, aWM), 0);
361 };
362
363 nscoord& min = mMin.Size(aAxis, aWM);
364 const auto styleMinSize = pos->MinSize(aAxis, aWM, anchorResolutionParams);
365 if (styleMinSize->ConvertsToLength()) {
366 min = adjustForBoxSizing(styleMinSize->ToLength());
367 } else if (styleMinSize->HasPercent() &&
368 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
369 min = adjustForBoxSizing(
370 styleMinSize->AsLengthPercentage().Resolve(cbSizeInAxis));
371 } else if (aAspectRatio && styleMinSize->BehavesLikeInitialValue(aAxis)) {
372 // Use GetOrthogonalAxis() to get the ratio-determining axis. Same for max
373 // and size below in this function.
374 const auto styleRDMinSize =
375 pos->MinSize(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
376 if (Maybe<nscoord> resolvedMinSize = ComputeTransferredSize(
377 styleRDMinSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
378 aContainingBlockSize)) {
379 min = *resolvedMinSize;
380 }
381 }
382
383 nscoord& max = mMax.Size(aAxis, aWM);
384 const auto styleMaxSize = pos->MaxSize(aAxis, aWM, anchorResolutionParams);
385 if (styleMaxSize->ConvertsToLength()) {
386 max = std::max(min, adjustForBoxSizing(styleMaxSize->ToLength()));
387 } else if (styleMaxSize->HasPercent() &&
388 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
389 max = std::max(
390 min, adjustForBoxSizing(
391 styleMaxSize->AsLengthPercentage().Resolve(cbSizeInAxis)));
392 } else if (aAspectRatio && styleMaxSize->BehavesLikeInitialValue(aAxis)) {
393 const auto styleRDMaxSize =
394 pos->MaxSize(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
395 if (Maybe<nscoord> resolvedMaxSize = ComputeTransferredSize(
396 styleRDMaxSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
397 aContainingBlockSize)) {
398 max = std::max(min, *resolvedMaxSize);
399 }
400 }
401
402 nscoord& size = mSize.Size(aAxis, aWM);
403 // When computing the intrinsic inline size, disregard the explicit
404 // inline-size property as it should not affect the final result.
405 const auto styleSize = aAxis == LogicalAxis::Inline
406 ? AnchorResolvedSizeHelper::Auto()
407 : pos->BSize(aWM, anchorResolutionParams);
408 if (styleSize->ConvertsToLength()) {
409 size = std::clamp(adjustForBoxSizing(styleSize->ToLength()), min, max);
410 } else if (styleSize->HasPercent() &&
411 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
412 size =
413 std::clamp(adjustForBoxSizing(
414 styleSize->AsLengthPercentage().Resolve(cbSizeInAxis)),
415 min, max);
416 } else if (aAspectRatio && styleSize->BehavesLikeInitialValue(aAxis)) {
417 const auto styleRDSize =
418 pos->Size(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
419 if (Maybe<nscoord> resolvedSize = ComputeTransferredSize(
420 styleRDSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
421 aContainingBlockSize)) {
422 size = std::clamp(*resolvedSize, min, max);
423 }
424 }
425 }
426
427 LogicalSize mMin;
428 LogicalSize mSize;
429 LogicalSize mMax;
430};
431
432enum class GridLineSide {
433 BeforeGridGap,
434 AfterGridGap,
435};
436
437struct nsGridContainerFrame::TrackSize {
438 enum StateBits : uint16_t {
439 eNone = 0,
440 eAutoMinSizing = 1 << 0,
441 eMinContentMinSizing = 1 << 1,
442 eMaxContentMinSizing = 1 << 2,
443 eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
444 eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
445 eModified = 1 << 3,
446 eAutoMaxSizing = 1 << 4,
447 eMinContentMaxSizing = 1 << 5,
448 eMaxContentMaxSizing = 1 << 6,
449 eAutoOrMaxContentMaxSizing = eAutoMaxSizing | eMaxContentMaxSizing,
450 eIntrinsicMaxSizing = eAutoOrMaxContentMaxSizing | eMinContentMaxSizing,
451 eFlexMaxSizing = 1 << 7,
452 eFrozen = 1 << 8,
453 eSkipGrowUnlimited1 = 1 << 9,
454 eSkipGrowUnlimited2 = 1 << 10,
455 eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
456 eBreakBefore = 1 << 11,
457 eApplyFitContentClamping = 1 << 12,
458 eInfinitelyGrowable = 1 << 13,
459
460 // These are only used in the masonry axis. They share the same value
461 // as *MinSizing above, but that's OK because we don't use those in
462 // the masonry axis.
463 //
464 // This track corresponds to an item margin-box size that is stretching.
465 eItemStretchSize = 1 << 0,
466 // This bit says that we should clamp that size to mLimit.
467 eClampToLimit = 1 << 1,
468 // This bit says that the corresponding item has `auto` margin(s).
469 eItemHasAutoMargin = 1 << 2,
470 };
471
472 StateBits Initialize(nscoord aPercentageBasis, const StyleTrackSize&);
473 bool IsFrozen() const { return mState & eFrozen; }
474#ifdef DEBUG1
475 static void DumpStateBits(StateBits aState);
476 void Dump() const;
477#endif
478
479 static bool IsDefiniteMaxSizing(StateBits aStateBits) {
480 return (aStateBits & (eIntrinsicMaxSizing | eFlexMaxSizing)) == 0;
481 }
482
483 // Base size of this track.
484 // https://drafts.csswg.org/css-grid-2/#base-size
485 nscoord mBase;
486
487 // Growth limit of this track.
488 // https://drafts.csswg.org/css-grid-2/#growth-limit
489 nscoord mLimit;
490
491 nscoord mPosition; // zero until we apply 'align/justify-content'
492 // mBaselineSubtreeSize is the size of a baseline-aligned subtree within
493 // this track. One subtree per baseline-sharing group (per track).
494 PerBaseline<nscoord> mBaselineSubtreeSize;
495 StateBits mState;
496};
497
498MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TrackSize::StateBits)inline constexpr mozilla::CastableTypedEnumResult<TrackSize
::StateBits> operator |( TrackSize::StateBits a, TrackSize
::StateBits b) { typedef mozilla::CastableTypedEnumResult<
TrackSize::StateBits> Result; typedef mozilla::detail::UnsignedIntegerTypeForEnum
<TrackSize::StateBits>::Type U; return Result(TrackSize
::StateBits(U(a) | U(b))); } inline TrackSize::StateBits&
operator |=(TrackSize::StateBits & a, TrackSize::StateBits
b) { return a = a | b; } inline constexpr mozilla::CastableTypedEnumResult
<TrackSize::StateBits> operator &( TrackSize::StateBits
a, TrackSize::StateBits b) { typedef mozilla::CastableTypedEnumResult
<TrackSize::StateBits> Result; typedef mozilla::detail::
UnsignedIntegerTypeForEnum<TrackSize::StateBits>::Type U
; return Result(TrackSize::StateBits(U(a) & U(b))); } inline
TrackSize::StateBits& operator &=(TrackSize::StateBits
& a, TrackSize::StateBits b) { return a = a & b; } inline
constexpr mozilla::CastableTypedEnumResult<TrackSize::StateBits
> operator ^( TrackSize::StateBits a, TrackSize::StateBits
b) { typedef mozilla::CastableTypedEnumResult<TrackSize::
StateBits> Result; typedef mozilla::detail::UnsignedIntegerTypeForEnum
<TrackSize::StateBits>::Type U; return Result(TrackSize
::StateBits(U(a) ^ U(b))); } inline TrackSize::StateBits&
operator ^=(TrackSize::StateBits & a, TrackSize::StateBits
b) { return a = a ^ b; } inline constexpr mozilla::CastableTypedEnumResult
<TrackSize::StateBits> operator~(TrackSize::StateBits a
) { typedef mozilla::CastableTypedEnumResult<TrackSize::StateBits
> Result; typedef mozilla::detail::UnsignedIntegerTypeForEnum
<TrackSize::StateBits>::Type U; return Result(TrackSize
::StateBits(~(U(a)))); }
499
500static_assert(std::is_trivially_copyable_v<nsGridContainerFrame::TrackSize>,
501 "Must be trivially copyable");
502static_assert(std::is_trivially_destructible_v<nsGridContainerFrame::TrackSize>,
503 "Must be trivially destructible");
504
505TrackSize::StateBits nsGridContainerFrame::TrackSize::Initialize(
506 nscoord aPercentageBasis, const StyleTrackSize& aSize) {
507 using Tag = StyleTrackBreadth::Tag;
508
509 MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBase == 0 && mLimit == 0 && mState ==
0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mBase == 0 && mLimit == 0 && mState ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBase == 0 && mLimit == 0 && mState == 0" " ("
"track size data is expected to be initialized to zero" ")",
"./../../../layout/generic/nsGridContainerFrame.cpp", 510); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBase == 0 && mLimit == 0 && mState == 0"
") (" "track size data is expected to be initialized to zero"
")"); do { MOZ_CrashSequence(__null, 510); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
510 "track size data is expected to be initialized to zero")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBase == 0 && mLimit == 0 && mState ==
0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mBase == 0 && mLimit == 0 && mState ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBase == 0 && mLimit == 0 && mState == 0" " ("
"track size data is expected to be initialized to zero" ")",
"./../../../layout/generic/nsGridContainerFrame.cpp", 510); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBase == 0 && mLimit == 0 && mState == 0"
") (" "track size data is expected to be initialized to zero"
")"); do { MOZ_CrashSequence(__null, 510); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
511 mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0);
512 mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0);
513
514 auto& min = aSize.GetMin();
515 auto& max = aSize.GetMax();
516
517 Tag minSizeTag = min.tag;
518 Tag maxSizeTag = max.tag;
519 if (aSize.IsFitContent()) {
520 // In layout, fit-content(size) behaves as minmax(auto, max-content), with
521 // 'size' as an additional upper-bound.
522 if (!::IsPercentOfIndefiniteSize(aSize.AsFitContent(), aPercentageBasis)) {
523 mState = eApplyFitContentClamping;
524 }
525 minSizeTag = Tag::Auto;
526 maxSizeTag = Tag::MaxContent;
527 }
528 if (::IsPercentOfIndefiniteSize(min, aPercentageBasis)) {
529 // https://drafts.csswg.org/css-grid-2/#valdef-grid-template-columns-length-percentage-0
530 // "If the inline or block size of the grid container is indefinite,
531 // <percentage> values relative to that size are treated as 'auto'."
532 minSizeTag = Tag::Auto;
533 }
534 if (::IsPercentOfIndefiniteSize(max, aPercentageBasis)) {
535 maxSizeTag = Tag::Auto;
536 }
537
538 // https://drafts.csswg.org/css-grid-2/#algo-init
539 switch (minSizeTag) {
540 case Tag::Auto:
541 mState |= eAutoMinSizing;
542 break;
543 case Tag::MinContent:
544 mState |= eMinContentMinSizing;
545 break;
546 case Tag::MaxContent:
547 mState |= eMaxContentMinSizing;
548 break;
549 default:
550 MOZ_ASSERT(!min.IsFlex(), "<flex> min-sizing is invalid as a track size")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!min.IsFlex())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!min.IsFlex()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!min.IsFlex()" " ("
"<flex> min-sizing is invalid as a track size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 550); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!min.IsFlex()"
") (" "<flex> min-sizing is invalid as a track size" ")"
); do { MOZ_CrashSequence(__null, 550); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
551 mBase = ::ResolveToDefiniteSize(min, aPercentageBasis);
552 }
553 switch (maxSizeTag) {
554 case Tag::Auto:
555 mState |= eAutoMaxSizing;
556 mLimit = NS_UNCONSTRAINEDSIZE;
557 break;
558 case Tag::MinContent:
559 case Tag::MaxContent:
560 mState |= maxSizeTag == Tag::MinContent ? eMinContentMaxSizing
561 : eMaxContentMaxSizing;
562 mLimit = NS_UNCONSTRAINEDSIZE;
563 break;
564 case Tag::Flex:
565 mState |= eFlexMaxSizing;
566 mLimit = NS_UNCONSTRAINEDSIZE;
567 break;
568 default:
569 mLimit = ::ResolveToDefiniteSize(max, aPercentageBasis);
570 if (mLimit < mBase) {
571 mLimit = mBase;
572 }
573 }
574 return mState;
575}
576
577// Indicates if we are in intrinsic sizing step 3 (spanning items not
578// spanning any flex tracks) or step 4 (spanning items that span one or more
579// flex tracks).
580// https://drafts.csswg.org/css-grid-2/#algo-content
581enum class TrackSizingStep {
582 NotFlex, // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
583 Flex, // https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
584};
585
586// Sizing phases, used in intrinsic sizing steps 3 and 4.
587// https://drafts.csswg.org/css-grid-2/#algo-spanning-items
588enum class TrackSizingPhase {
589 IntrinsicMinimums,
590 ContentBasedMinimums,
591 MaxContentMinimums,
592 IntrinsicMaximums,
593 MaxContentMaximums,
594};
595
596// Used for grid items intrinsic size types.
597// See CachedIntrinsicSizes which uses this for content contributions.
598enum class GridIntrinsicSizeType {
599 // MinContribution is the "minimum contribution", defined at
600 // https://drafts.csswg.org/css-grid-2/#min-size-contribution
601 MinContribution,
602 MinContentContribution,
603 MaxContentContribution
604};
605
606static constexpr GridIntrinsicSizeType kAllGridIntrinsicSizeTypes[] = {
607 GridIntrinsicSizeType::MinContribution,
608 GridIntrinsicSizeType::MinContentContribution,
609 GridIntrinsicSizeType::MaxContentContribution};
610
611// Glue to make mozilla::EnumeratedArray work with GridIntrinsicSizeType.
612namespace mozilla {
613template <>
614struct MaxContiguousEnumValue<GridIntrinsicSizeType> {
615 static constexpr GridIntrinsicSizeType value =
616 GridIntrinsicSizeType::MaxContentContribution;
617};
618} // namespace mozilla
619
620// Convert a track sizing phase into which GridIntrinsicSizeType is applicable.
621static GridIntrinsicSizeType SizeTypeForPhase(TrackSizingPhase aPhase) {
622 switch (aPhase) {
623 case TrackSizingPhase::IntrinsicMinimums:
624 return GridIntrinsicSizeType::MinContribution;
625 case TrackSizingPhase::ContentBasedMinimums:
626 case TrackSizingPhase::IntrinsicMaximums:
627 return GridIntrinsicSizeType::MinContentContribution;
628 case TrackSizingPhase::MaxContentMinimums:
629 case TrackSizingPhase::MaxContentMaximums:
630 return GridIntrinsicSizeType::MaxContentContribution;
631 }
632 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase")do { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected phase" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 632); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 632); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); __builtin_unreachable(); } while (false
)
;
633}
634
635class nsGridContainerFrame::TrackPlan {
636 public:
637 TrackPlan() = default;
638
639 explicit TrackPlan(size_t aCapacity) : mTrackSizes(aCapacity) {}
640
641 TrackPlan(const TrackPlan& aOther) = default;
642
643 TrackPlan(TrackPlan&& aOther) : mTrackSizes(std::move(aOther.mTrackSizes)) {}
644
645 ~TrackPlan() = default;
646
647 TrackPlan& operator=(const TrackPlan& aOther) {
648 mTrackSizes.Assign(aOther.mTrackSizes);
649 return *this;
650 }
651 TrackPlan& operator=(TrackPlan&& aOther) {
652 mTrackSizes.Assign(std::move(aOther.mTrackSizes));
653 return *this;
654 }
655
656 size_t Length() const { return mTrackSizes.Length(); }
657
658 void SetLength(size_t aSize) { mTrackSizes.SetLength(aSize); }
659
660 bool IsEmpty() const { return mTrackSizes.IsEmpty(); }
661
662 void Assign(const TrackPlan& aRHS) { mTrackSizes.Assign(aRHS.mTrackSizes); }
663
664 nsGridContainerFrame::TrackSize* AppendElement(
665 nsGridContainerFrame::TrackSize aElement) {
666 return mTrackSizes.AppendElement(aElement);
667 }
668
669 nsGridContainerFrame::TrackSize& LastElement() {
670 return mTrackSizes.LastElement();
671 }
672
673 nsGridContainerFrame::TrackSize& operator[](size_t aIndex) {
674 return mTrackSizes[aIndex];
675 }
676
677 const nsGridContainerFrame::TrackSize& operator[](size_t aIndex) const {
678 return mTrackSizes[aIndex];
679 }
680
681 void ClearAndRetainStorage() { mTrackSizes.ClearAndRetainStorage(); }
682
683 void ZeroInitialize() {
684 PodZero(mTrackSizes.Elements(), mTrackSizes.Length());
685 }
686
687 using iterator = nsTArray<nsGridContainerFrame::TrackSize>::iterator;
688 iterator begin() { return mTrackSizes.begin(); }
689 iterator end() { return mTrackSizes.end(); }
690
691 using const_iterator =
692 nsTArray<nsGridContainerFrame::TrackSize>::const_iterator;
693 const_iterator begin() const { return mTrackSizes.begin(); }
694 const_iterator end() const { return mTrackSizes.end(); }
695
696 void Initialize(TrackSizingPhase aPhase, const Tracks& aTracks);
697
698 // Distribute space to all flex tracks this item spans.
699 // https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
700 nscoord DistributeToFlexTrackSizes(
701 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
702 const TrackSizingFunctions& aFunctions,
703 const nsGridContainerFrame::Tracks& aTracks);
704
705 private:
706 CopyableTArray<nsGridContainerFrame::TrackSize> mTrackSizes;
707};
708
709using TrackPlan = nsGridContainerFrame::TrackPlan;
710
711class nsGridContainerFrame::ItemPlan {
712 public:
713 ItemPlan() = default;
714
715 explicit ItemPlan(size_t aCapacity) : mTrackSizes(aCapacity) {}
716
717 ~ItemPlan() = default;
718
719 void SetLength(size_t aSize) { mTrackSizes.SetLength(aSize); }
720
721 nsGridContainerFrame::TrackSize& operator[](size_t aIndex) {
722 return mTrackSizes[aIndex];
723 }
724
725 void Initialize(TrackSizingPhase aPhase,
726 const nsTArray<uint32_t>& aGrowableTracks,
727 const nsGridContainerFrame::Tracks& aTracks);
728
729 using FitContentClamper =
730 std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
731
732 /**
733 * Grow the planned size for tracks in aGrowableTracks up to their limit
734 * and then freeze them (all aGrowableTracks must be unfrozen on entry).
735 * Subtract the space added from aAvailableSpace and return that.
736 */
737 nscoord GrowTracksToLimit(nscoord aAvailableSpace,
738 const nsTArray<uint32_t>& aGrowableTracks,
739 const FitContentClamper& aFitContentClamper);
740
741 /**
742 * Helper for GrowSelectedTracksUnlimited. For the set of tracks (S) that
743 * match aMinSizingSelector: if a track in S doesn't match aMaxSizingSelector
744 * then mark it with aSkipFlag. If all tracks in S were marked then unmark
745 * them. Return aNumGrowable minus the number of tracks marked. It is
746 * assumed that this plan has no aSkipFlag set for tracks in aGrowableTracks
747 * on entry to this method.
748 */
749 uint32_t MarkExcludedTracks(uint32_t aNumGrowable,
750 const nsTArray<uint32_t>& aGrowableTracks,
751 TrackSize::StateBits aMinSizingSelector,
752 TrackSize::StateBits aMaxSizingSelector,
753 TrackSize::StateBits aSkipFlag);
754
755 /**
756 * Mark all tracks in aGrowableTracks with an eSkipGrowUnlimited bit if
757 * they *shouldn't* grow unlimited in §12.5.1.2.4 "Distribute space beyond
758 * growth limits" https://drafts.csswg.org/css-grid-2/#extra-space
759 * Return the number of tracks that are still growable.
760 */
761 uint32_t MarkExcludedTracks(TrackSizingPhase aPhase,
762 const nsTArray<uint32_t>& aGrowableTracks,
763 SizingConstraint aConstraint);
764
765 /**
766 * Increase the planned size for tracks in aGrowableTracks that aren't
767 * marked with a eSkipGrowUnlimited flag beyond their limit.
768 * This implements the "Distribute space beyond growth limits" step in
769 * https://drafts.csswg.org/css-grid-2/#distribute-extra-space
770 */
771 void GrowSelectedTracksUnlimited(nscoord aAvailableSpace,
772 const nsTArray<uint32_t>& aGrowableTracks,
773 uint32_t aNumGrowable,
774 const FitContentClamper& aFitContentClamper);
775
776 private:
777 nsTArray<nsGridContainerFrame::TrackSize> mTrackSizes;
778};
779
780using ItemPlan = nsGridContainerFrame::ItemPlan;
781
782/**
783 * A LineRange can be definite or auto - when it's definite it represents
784 * a consecutive set of tracks between a starting line and an ending line.
785 * Before it's definite it can also represent an auto position with a span,
786 * where mStart == kAutoLine and mEnd is the (non-zero positive) span.
787 * For normal-flow items, the invariant mStart < mEnd holds when both
788 * lines are definite.
789 *
790 * For abs.pos. grid items, mStart and mEnd may both be kAutoLine, meaning
791 * "attach this side to the grid container containing block edge".
792 * Additionally, mStart <= mEnd holds when both are definite (non-kAutoLine),
793 * i.e. the invariant is slightly relaxed compared to normal flow items.
794 */
795struct nsGridContainerFrame::LineRange {
796 LineRange(int32_t aStart, int32_t aEnd)
797 : mUntranslatedStart(aStart), mUntranslatedEnd(aEnd) {
798#ifdef DEBUG1
799 if (!IsAutoAuto()) {
800 if (IsAuto()) {
801 MOZ_ASSERT(aEnd >= kMinLine && aEnd <= kMaxLine, "invalid span")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEnd >= kMinLine && aEnd <= kMaxLine)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEnd >= kMinLine && aEnd <= kMaxLine))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEnd >= kMinLine && aEnd <= kMaxLine"
" (" "invalid span" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 801); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd >= kMinLine && aEnd <= kMaxLine"
") (" "invalid span" ")"); do { MOZ_CrashSequence(__null, 801
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
802 } else {
803 MOZ_ASSERT(aStart >= kMinLine && aStart <= kMaxLine,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart >= kMinLine && aStart <= kMaxLine
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStart >= kMinLine && aStart <= kMaxLine
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStart >= kMinLine && aStart <= kMaxLine" " ("
"invalid start line" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 804); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart >= kMinLine && aStart <= kMaxLine"
") (" "invalid start line" ")"); do { MOZ_CrashSequence(__null
, 804); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
804 "invalid start line")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart >= kMinLine && aStart <= kMaxLine
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStart >= kMinLine && aStart <= kMaxLine
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStart >= kMinLine && aStart <= kMaxLine" " ("
"invalid start line" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 804); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart >= kMinLine && aStart <= kMaxLine"
") (" "invalid start line" ")"); do { MOZ_CrashSequence(__null
, 804); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
805 MOZ_ASSERT(aEnd == int32_t(kAutoLine) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine &&
aEnd <= kMaxLine))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEnd == int32_t(kAutoLine) ||
(aEnd >= kMinLine && aEnd <= kMaxLine)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
" (" "invalid end line" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 807); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
806 (aEnd >= kMinLine && aEnd <= kMaxLine),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine &&
aEnd <= kMaxLine))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEnd == int32_t(kAutoLine) ||
(aEnd >= kMinLine && aEnd <= kMaxLine)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
" (" "invalid end line" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 807); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
807 "invalid end line")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine &&
aEnd <= kMaxLine))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEnd == int32_t(kAutoLine) ||
(aEnd >= kMinLine && aEnd <= kMaxLine)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
" (" "invalid end line" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 807); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
808 }
809 }
810#endif
811 }
812 bool IsAutoAuto() const { return mStart == kAutoLine && mEnd == kAutoLine; }
813 bool IsAuto() const { return mStart == kAutoLine; }
814 bool IsDefinite() const { return mStart != kAutoLine; }
815 uint32_t Extent() const {
816 MOZ_ASSERT(mEnd != kAutoLine, "Extent is undefined for abs.pos. 'auto'")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mEnd != kAutoLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mEnd != kAutoLine))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mEnd != kAutoLine"
" (" "Extent is undefined for abs.pos. 'auto'" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd != kAutoLine"
") (" "Extent is undefined for abs.pos. 'auto'" ")"); do { MOZ_CrashSequence
(__null, 816); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
817 if (IsAuto()) {
818 MOZ_ASSERT(mEnd >= 1 && mEnd < uint32_t(kMaxLine), "invalid span")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mEnd >= 1 && mEnd < uint32_t(kMaxLine)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mEnd >= 1 && mEnd < uint32_t(kMaxLine)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mEnd >= 1 && mEnd < uint32_t(kMaxLine)" " (" "invalid span"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 818
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd >= 1 && mEnd < uint32_t(kMaxLine)"
") (" "invalid span" ")"); do { MOZ_CrashSequence(__null, 818
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
819 return mEnd;
820 }
821 return mEnd - mStart;
822 }
823
824 /**
825 * Return an object suitable for iterating this range.
826 */
827 auto Range() const { return IntegerRange<uint32_t>(mStart, mEnd); }
828
829 /**
830 * Resolve this auto range to start at aStart, making it definite.
831 * @param aClampMaxLine the maximum allowed line number (zero-based)
832 * Precondition: this range IsAuto()
833 */
834 void ResolveAutoPosition(uint32_t aStart, uint32_t aClampMaxLine) {
835 MOZ_ASSERT(IsAuto(), "Why call me?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsAuto())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsAuto()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsAuto()" " (" "Why call me?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 835
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsAuto()" ") (" "Why call me?"
")"); do { MOZ_CrashSequence(__null, 835); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
836 mStart = aStart;
837 mEnd += aStart;
838 // Clamp to aClampMaxLine, which is where kMaxLine is in the explicit
839 // grid in a non-subgrid axis; this implements clamping per
840 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
841 // In a subgrid axis it's the end of the grid in that axis.
842 if (MOZ_UNLIKELY(mStart >= aClampMaxLine)(__builtin_expect(!!(mStart >= aClampMaxLine), 0))) {
843 mEnd = aClampMaxLine;
844 mStart = mEnd - 1;
845 } else if (MOZ_UNLIKELY(mEnd > aClampMaxLine)(__builtin_expect(!!(mEnd > aClampMaxLine), 0))) {
846 mEnd = aClampMaxLine;
847 }
848 }
849 /**
850 * Translate the lines to account for (empty) removed tracks. This method
851 * is only for grid items and should only be called after placement.
852 * aNumRemovedTracks contains a count for each line in the grid how many
853 * tracks were removed between the start of the grid and that line.
854 */
855 void AdjustForRemovedTracks(const nsTArray<uint32_t>& aNumRemovedTracks) {
856 MOZ_ASSERT(mStart != kAutoLine, "invalid resolved line for a grid item")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart != kAutoLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStart != kAutoLine))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("mStart != kAutoLine"
" (" "invalid resolved line for a grid item" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine"
") (" "invalid resolved line for a grid item" ")"); do { MOZ_CrashSequence
(__null, 856); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
857 MOZ_ASSERT(mEnd != kAutoLine, "invalid resolved line for a grid item")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mEnd != kAutoLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mEnd != kAutoLine))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mEnd != kAutoLine"
" (" "invalid resolved line for a grid item" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd != kAutoLine"
") (" "invalid resolved line for a grid item" ")"); do { MOZ_CrashSequence
(__null, 857); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
858 uint32_t numRemovedTracks = aNumRemovedTracks[mStart];
859 MOZ_ASSERT(numRemovedTracks == aNumRemovedTracks[mEnd],do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numRemovedTracks == aNumRemovedTracks[mEnd])>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(numRemovedTracks == aNumRemovedTracks[mEnd]))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("numRemovedTracks == aNumRemovedTracks[mEnd]"
" (" "tracks that a grid item spans can't be removed" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numRemovedTracks == aNumRemovedTracks[mEnd]"
") (" "tracks that a grid item spans can't be removed" ")");
do { MOZ_CrashSequence(__null, 860); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
860 "tracks that a grid item spans can't be removed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numRemovedTracks == aNumRemovedTracks[mEnd])>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(numRemovedTracks == aNumRemovedTracks[mEnd]))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("numRemovedTracks == aNumRemovedTracks[mEnd]"
" (" "tracks that a grid item spans can't be removed" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numRemovedTracks == aNumRemovedTracks[mEnd]"
") (" "tracks that a grid item spans can't be removed" ")");
do { MOZ_CrashSequence(__null, 860); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
861 mStart -= numRemovedTracks;
862 mEnd -= numRemovedTracks;
863 }
864 /**
865 * Translate the lines to account for (empty) removed tracks. This method
866 * is only for abs.pos. children and should only be called after placement.
867 * Same as for in-flow items, but we don't touch 'auto' lines here and we
868 * also need to adjust areas that span into the removed tracks.
869 */
870 void AdjustAbsPosForRemovedTracks(
871 const nsTArray<uint32_t>& aNumRemovedTracks) {
872 if (mStart != kAutoLine) {
873 mStart -= aNumRemovedTracks[mStart];
874 }
875 if (mEnd != kAutoLine) {
876 MOZ_ASSERT(mStart == kAutoLine || mEnd > mStart, "invalid line range")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart == kAutoLine || mEnd > mStart)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mStart == kAutoLine || mEnd > mStart))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mStart == kAutoLine || mEnd > mStart"
" (" "invalid line range" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart == kAutoLine || mEnd > mStart"
") (" "invalid line range" ")"); do { MOZ_CrashSequence(__null
, 876); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
877 mEnd -= aNumRemovedTracks[mEnd];
878 }
879 }
880
881 /**
882 * Return the contribution of this line range for step 2 in
883 * https://drafts.csswg.org/css-grid-2/#auto-placement-algo
884 */
885 uint32_t HypotheticalEnd() const { return mEnd; }
886
887 /**
888 * Given an array of track sizes, return the starting position and length
889 * of the tracks in this line range.
890 */
891 void ToPositionAndLength(const TrackPlan& aTrackPlan, nscoord* aPos,
892 nscoord* aLength) const;
893
894 /**
895 * Given an array of track sizes, return the length of the tracks in this
896 * line range.
897 */
898 nscoord ToLength(const TrackPlan& aTrackPlan) const;
899
900 /**
901 * Given an array of track sizes and a grid origin coordinate, adjust the
902 * abs.pos. containing block along an axis given by aPos and aLength.
903 * aPos and aLength should already be initialized to the grid container
904 * containing block for this axis before calling this method.
905 */
906 void ToPositionAndLengthForAbsPos(const Tracks& aTracks, nscoord aGridOrigin,
907 nscoord* aPos, nscoord* aLength) const;
908
909 void Translate(int32_t aOffset) {
910 MOZ_ASSERT(IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsDefinite()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsDefinite()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 910); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
911 mStart += aOffset;
912 mEnd += aOffset;
913 }
914
915 /** Swap the start/end sides of this range. */
916 void ReverseDirection(uint32_t aGridEnd) {
917 MOZ_ASSERT(IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsDefinite()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsDefinite()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 917); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
918 MOZ_ASSERT(aGridEnd >= mEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridEnd >= mEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridEnd >= mEnd))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aGridEnd >= mEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 918);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridEnd >= mEnd"
")"); do { MOZ_CrashSequence(__null, 918); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
919 uint32_t newStart = aGridEnd - mEnd;
920 mEnd = aGridEnd - mStart;
921 mStart = newStart;
922 }
923
924 /**
925 * @note We'll use the signed member while resolving definite positions
926 * to line numbers (1-based), which may become negative for implicit lines
927 * to the top/left of the explicit grid. PlaceGridItems() then translates
928 * the whole grid to a 0,0 origin and we'll use the unsigned member from
929 * there on.
930 */
931 union {
932 uint32_t mStart;
933 int32_t mUntranslatedStart;
934 };
935 union {
936 uint32_t mEnd;
937 int32_t mUntranslatedEnd;
938 };
939
940 protected:
941 LineRange() : mStart(0), mEnd(0) {}
942};
943
944/**
945 * Helper class to construct a LineRange from translated lines.
946 * The ctor only accepts translated definite line numbers.
947 */
948struct nsGridContainerFrame::TranslatedLineRange : public LineRange {
949 TranslatedLineRange(uint32_t aStart, uint32_t aEnd) {
950 MOZ_ASSERT(aStart < aEnd && aEnd <= kTranslatedMaxLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart < aEnd && aEnd <= kTranslatedMaxLine
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStart < aEnd && aEnd <= kTranslatedMaxLine
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStart < aEnd && aEnd <= kTranslatedMaxLine", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart < aEnd && aEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 950); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
951 mStart = aStart;
952 mEnd = aEnd;
953 }
954};
955
956/**
957 * A GridArea is the area in the grid for a grid item.
958 * The area is represented by two LineRanges, both of which can be auto
959 * (@see LineRange) in intermediate steps while the item is being placed.
960 * @see PlaceGridItems
961 */
962struct nsGridContainerFrame::GridArea {
963 GridArea(const LineRange& aCols, const LineRange& aRows)
964 : mCols(aCols), mRows(aRows) {}
965 bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
966 LineRange& LineRangeForAxis(LogicalAxis aAxis) {
967 return aAxis == LogicalAxis::Inline ? mCols : mRows;
968 }
969 const LineRange& LineRangeForAxis(LogicalAxis aAxis) const {
970 return aAxis == LogicalAxis::Inline ? mCols : mRows;
971 }
972 LineRange mCols;
973 LineRange mRows;
974};
975
976struct nsGridContainerFrame::GridItemInfo {
977 /**
978 * Item state per axis.
979 */
980 enum StateBits : uint16_t {
981 // Does the item span a flex track?
982 eIsFlexing = 0x1,
983
984 // First or last baseline alignment preference. They are mutually exclusive.
985 // This does *NOT* represent the baseline alignment group. See the member
986 // variable for that.
987 // <https://drafts.csswg.org/css-align-3/#baseline-alignment-preference>
988 eFirstBaseline = 0x2,
989 eLastBaseline = 0x4,
990 eIsBaselineAligned = eFirstBaseline | eLastBaseline,
991
992 // One of e[Self|Content]Baseline is set when eIsBaselineAligned is true
993 eSelfBaseline = 0x8, // is it *-self:[last ]baseline alignment?
994 // Ditto *-content:[last ]baseline. Mutually exclusive w. eSelfBaseline.
995 eContentBaseline = 0x10,
996
997 // The baseline affects the margin or padding on the item's end side when
998 // this bit is set. In a grid-axis it's always set for eLastBaseline and
999 // always unset for eFirstBaseline. In a masonry-axis, it's set for
1000 // baseline groups in the EndStretch set and unset for the StartStretch set.
1001 eEndSideBaseline = 0x20,
1002
1003 // Set when the grid item is in the last baseline sharing group, otherwise
1004 // assume the first baseline sharing group. The baseline sharing group might
1005 // differ from the specified baseline alignment due to baseline alignment
1006 // rules.
1007 eLastBaselineSharingGroup = 0x40,
1008
1009 eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline |
1010 eEndSideBaseline | eLastBaselineSharingGroup,
1011
1012 // Automatic Minimum Size is content based. If not set, automatic minimum
1013 // size is zero.
1014 // https://drafts.csswg.org/css-grid-2/#min-size-auto
1015 // https://drafts.csswg.org/css-grid-2/#content-based-minimum-size
1016 eContentBasedAutoMinSize = 0x80,
1017 // Clamp per https://drafts.csswg.org/css-grid-2/#min-size-auto
1018 eClampMarginBoxMinSize = 0x100,
1019 eIsSubgrid = 0x200,
1020 // set on subgrids and items in subgrids if they are adjacent to the grid
1021 // start/end edge (excluding grid-aligned abs.pos. frames)
1022 eStartEdge = 0x400,
1023 eEndEdge = 0x800,
1024 eEdgeBits = eStartEdge | eEndEdge,
1025 // Set if this item was auto-placed in this axis.
1026 eAutoPlacement = 0x1000,
1027 // Set if this item is the last item in its track (masonry layout only)
1028 eIsLastItemInMasonryTrack = 0x2000,
1029
1030 // Bits set during the track sizing step.
1031 eTrackSizingBits =
1032 eIsFlexing | eContentBasedAutoMinSize | eClampMarginBoxMinSize,
1033 };
1034
1035 GridItemInfo(nsIFrame* aFrame, const GridArea& aArea);
1036
1037 GridItemInfo(const GridItemInfo& aOther)
1038 : mFrame(aOther.mFrame), mArea(aOther.mArea) {
1039 mBaselineOffset = aOther.mBaselineOffset;
1040 mState = aOther.mState;
1041 }
1042
1043 GridItemInfo& operator=(const GridItemInfo&) = delete;
1044
1045 static bool BaselineAlignmentAffectsEndSide(StateBits state) {
1046 return state & StateBits::eEndSideBaseline;
1047 }
1048
1049 /**
1050 * Inhibit subgrid layout unless the item is placed in the first "track" in
1051 * a parent masonry-axis, or has definite placement or spans all tracks in
1052 * the parent grid-axis.
1053 * TODO: this is stricter than what the Masonry proposal currently states
1054 * (bug 1627581)
1055 */
1056 void MaybeInhibitSubgridInMasonry(nsGridContainerFrame* aParent,
1057 uint32_t aGridAxisTrackCount);
1058
1059 /**
1060 * Inhibit subgridding in aAxis for this item.
1061 */
1062 void InhibitSubgrid(nsGridContainerFrame* aParent, LogicalAxis aAxis);
1063
1064 /**
1065 * Return a copy of this item with its row/column data swapped.
1066 */
1067 GridItemInfo Transpose() const {
1068 GridItemInfo info(mFrame, GridArea(mArea.mRows, mArea.mCols));
1069 info.mState[LogicalAxis::Block] = mState[LogicalAxis::Inline];
1070 info.mState[LogicalAxis::Inline] = mState[LogicalAxis::Block];
1071 info.mBaselineOffset[LogicalAxis::Block] =
1072 mBaselineOffset[LogicalAxis::Inline];
1073 info.mBaselineOffset[LogicalAxis::Inline] =
1074 mBaselineOffset[LogicalAxis::Block];
1075 return info;
1076 }
1077
1078 // Reset bits in mState in aAxis that were set during the track sizing step.
1079 void ResetTrackSizingBits(LogicalAxis aAxis);
1080
1081 /** Swap the start/end sides in aAxis. */
1082 inline void ReverseDirection(LogicalAxis aAxis, uint32_t aGridEnd);
1083
1084 // Is this item a subgrid in the given container axis?
1085 bool IsSubgrid(LogicalAxis aAxis) const {
1086 return mState[aAxis] & StateBits::eIsSubgrid;
1087 }
1088
1089 // Is this item a subgrid in either axis?
1090 bool IsSubgrid() const {
1091 return IsSubgrid(LogicalAxis::Inline) || IsSubgrid(LogicalAxis::Block);
1092 }
1093
1094 // Return the (inner) grid container frame associated with this subgrid item.
1095 nsGridContainerFrame* SubgridFrame() const {
1096 MOZ_ASSERT(IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSubgrid()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsSubgrid()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 1096); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1097 nsGridContainerFrame* gridFrame = GetGridContainerFrame(mFrame);
1098 MOZ_ASSERT(gridFrame && gridFrame->IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gridFrame && gridFrame->IsSubgrid())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gridFrame && gridFrame->IsSubgrid()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("gridFrame && gridFrame->IsSubgrid()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1098)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridFrame && gridFrame->IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 1098); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1099 return gridFrame;
1100 }
1101
1102 /**
1103 * Adjust our grid areas to account for removed auto-fit tracks in aAxis.
1104 */
1105 void AdjustForRemovedTracks(LogicalAxis aAxis,
1106 const nsTArray<uint32_t>& aNumRemovedTracks);
1107
1108 /**
1109 * If the item is [align|justify]-self:[last ]baseline aligned in the given
1110 * axis then set aBaselineOffset to the baseline offset and return aAlign.
1111 * Otherwise, return a fallback alignment.
1112 */
1113 StyleAlignFlags GetSelfBaseline(StyleAlignFlags aAlign, LogicalAxis aAxis,
1114 nscoord* aBaselineOffset) const {
1115 MOZ_ASSERT(aAlign == StyleAlignFlags::BASELINE ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags
::LAST_BASELINE)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aAlign == StyleAlignFlags::BASELINE
|| aAlign == StyleAlignFlags::LAST_BASELINE))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1116)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
")"); do { MOZ_CrashSequence(__null, 1116); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1116 aAlign == StyleAlignFlags::LAST_BASELINE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags
::LAST_BASELINE)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aAlign == StyleAlignFlags::BASELINE
|| aAlign == StyleAlignFlags::LAST_BASELINE))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1116)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
")"); do { MOZ_CrashSequence(__null, 1116); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1117 if (!(mState[aAxis] & eSelfBaseline)) {
1118 return aAlign == StyleAlignFlags::BASELINE ? StyleAlignFlags::SELF_START
1119 : StyleAlignFlags::SELF_END;
1120 }
1121 *aBaselineOffset = mBaselineOffset[aAxis];
1122 return aAlign;
1123 }
1124
1125 // Return true if we should use MinContribution on items that do not span
1126 // any flex tracks to determine the minimum contribution, and if we should
1127 // set the eContentBasedAutoMinSize flag on grid items.
1128 //
1129 // In part this is determined by whether or not the minimum contribution
1130 // of the item is content-based.
1131 // https://drafts.csswg.org/css-grid-2/#min-size-auto
1132 //
1133 // @note the caller should also check that the item has a span length of 1,
1134 // and that the item's track has a min track sizing function that is 'auto'.
1135 bool MinContributionDependsOnAutoMinSize(WritingMode aContainerWM,
1136 LogicalAxis aContainerAxis) const {
1137 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mArea.LineRangeForAxis(aContainerAxis).Extent() == 1" " (" "Should not be called with grid items that span multiple tracks."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1139
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1139); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1138 mArea.LineRangeForAxis(aContainerAxis).Extent() == 1,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mArea.LineRangeForAxis(aContainerAxis).Extent() == 1" " (" "Should not be called with grid items that span multiple tracks."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1139
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1139); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1139 "Should not be called with grid items that span multiple tracks.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mArea.LineRangeForAxis(aContainerAxis).Extent() == 1
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mArea.LineRangeForAxis(aContainerAxis).Extent() == 1" " (" "Should not be called with grid items that span multiple tracks."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1139
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1139); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1140 const LogicalAxis itemAxis =
1141 aContainerWM.ConvertAxisTo(aContainerAxis, mFrame->GetWritingMode());
1142 const auto* styleFrame = mFrame->IsTableWrapperFrame()
1143 ? mFrame->PrincipalChildList().FirstChild()
1144 : mFrame;
1145 const auto* pos = styleFrame->StylePosition();
1146 const auto anchorResolutionParams =
1147 AnchorPosResolutionParams::From(styleFrame);
1148 const auto size =
1149 pos->Size(aContainerAxis, aContainerWM, anchorResolutionParams);
1150 // max-content and min-content should behave as initial value in block axis.
1151 // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
1152 // for block size dimension on sizing properties (e.g. height), so we
1153 // treat it as `auto`.
1154 bool isAuto = size->BehavesLikeInitialValue(itemAxis);
1155 // This check for HasPercent is intended to correspond to whether or not
1156 // the item's preferred size depends on the size of its containing block.
1157 //
1158 // TODO alaskanemily: This probably shouldn't be a special case here.
1159 // This is part of how EnsureContributions with the MinSize flag is
1160 // implemented, where this forces ResolveIntrinsicSizeForNonSpanningItems
1161 // to use MinSize instead of Min/MaxContentContribution, which
1162 // EnsureContributions will then translate to/from MinContentContribution
1163 //
1164 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
1165 // Section "For auto minimums"
1166 if (!isAuto && !size->HasPercent()) {
1167 return false;
1168 }
1169 const auto minSize =
1170 pos->MinSize(aContainerAxis, aContainerWM, anchorResolutionParams);
1171 // max-content and min-content should behave as initial value in block axis.
1172 // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
1173 // for block size dimension on sizing properties (e.g. height), so we
1174 // treat it as `auto`.
1175 isAuto = minSize->BehavesLikeInitialValue(itemAxis);
1176 return isAuto && !mFrame->StyleDisplay()->IsScrollableOverflow();
1177 }
1178
1179#ifdef DEBUG1
1180 void Dump() const;
1181#endif
1182
1183 static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b) {
1184 return a->mArea.mRows.mStart < b->mArea.mRows.mStart;
1185 }
1186
1187 // Sorting functions for 'masonry-auto-flow:definite-first'. Similar to
1188 // the above, but here we also sort items with a definite item placement in
1189 // the grid axis in track order before 'auto'-placed items. We also sort all
1190 // continuations first since they use the same placement as their
1191 // first-in-flow (we treat them as "definite" regardless of eAutoPlacement).
1192 static bool RowMasonryDefiniteFirst(const GridItemInfo* a,
1193 const GridItemInfo* b) {
1194 bool isContinuationA = a->mFrame->GetPrevInFlow();
1195 bool isContinuationB = b->mFrame->GetPrevInFlow();
1196 if (isContinuationA != isContinuationB) {
1197 return isContinuationA;
1198 }
1199 auto masonryA = a->mArea.mRows.mStart;
1200 auto gridA = a->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
1201 auto masonryB = b->mArea.mRows.mStart;
1202 auto gridB = b->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
1203 return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
1204 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1205 }
1206 static bool ColMasonryDefiniteFirst(const GridItemInfo* a,
1207 const GridItemInfo* b) {
1208 MOZ_ASSERT(!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!a->mFrame->GetPrevInFlow() && !b->
mFrame->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!a->mFrame->GetPrevInFlow
() && !b->mFrame->GetPrevInFlow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
" (" "fragmentation not supported in inline axis" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
") (" "fragmentation not supported in inline axis" ")"); do {
MOZ_CrashSequence(__null, 1209); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1209 "fragmentation not supported in inline axis")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!a->mFrame->GetPrevInFlow() && !b->
mFrame->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!a->mFrame->GetPrevInFlow
() && !b->mFrame->GetPrevInFlow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
" (" "fragmentation not supported in inline axis" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
") (" "fragmentation not supported in inline axis" ")"); do {
MOZ_CrashSequence(__null, 1209); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1210 auto masonryA = a->mArea.mCols.mStart;
1211 auto gridA = a->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
1212 auto masonryB = b->mArea.mCols.mStart;
1213 auto gridB = b->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
1214 return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
1215 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1216 }
1217
1218 // Return true if this items block size is dependent on the size of the
1219 // container it is in.
1220 bool IsBSizeDependentOnContainerSize(WritingMode aContainerWM) const {
1221 const auto IsDependentOnContainerSize = [](const auto& size) -> bool {
1222 // XXXdholbert The BehavesLikeStretchOnInlineAxis usage seems like
1223 // maybe it should be considering block-axis instead?
1224 return size.HasPercent() || size.BehavesLikeStretchOnInlineAxis();
1225 };
1226
1227 const nsStylePosition* stylePos = mFrame->StylePosition();
1228 const auto anchorResolutionParams = AnchorPosResolutionParams::From(mFrame);
1229 bool isItemAutoSize = IsDependentOnContainerSize(*stylePos->BSize(
1230 aContainerWM, anchorResolutionParams)) ||
1231 IsDependentOnContainerSize(*stylePos->MinBSize(
1232 aContainerWM, anchorResolutionParams)) ||
1233 IsDependentOnContainerSize(*stylePos->MaxBSize(
1234 aContainerWM, anchorResolutionParams));
1235
1236 return isItemAutoSize;
1237 }
1238
1239 nsIFrame* const mFrame;
1240 GridArea mArea;
1241
1242 // Offset from the margin edge to the baseline (LogicalAxis index). It's from
1243 // the start edge for first baseline sharing group, otherwise from the end
1244 // edge.
1245 // It's mutable since we update the value fairly late (just before reflowing
1246 // the item).
1247 mutable PerLogicalAxis<nscoord> mBaselineOffset;
1248
1249 // State bits per axis.
1250 mutable PerLogicalAxis<StateBits> mState;
1251};
1252
1253using GridItemInfo = nsGridContainerFrame::GridItemInfo;
1254using ItemState = GridItemInfo::StateBits;
1255MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ItemState)inline constexpr mozilla::CastableTypedEnumResult<ItemState
> operator |( ItemState a, ItemState b) { typedef mozilla::
CastableTypedEnumResult<ItemState> Result; typedef mozilla
::detail::UnsignedIntegerTypeForEnum<ItemState>::Type U
; return Result(ItemState(U(a) | U(b))); } inline ItemState&
operator |=(ItemState & a, ItemState b) { return a = a |
b; } inline constexpr mozilla::CastableTypedEnumResult<ItemState
> operator &( ItemState a, ItemState b) { typedef mozilla
::CastableTypedEnumResult<ItemState> Result; typedef mozilla
::detail::UnsignedIntegerTypeForEnum<ItemState>::Type U
; return Result(ItemState(U(a) & U(b))); } inline ItemState
& operator &=(ItemState & a, ItemState b) { return
a = a & b; } inline constexpr mozilla::CastableTypedEnumResult
<ItemState> operator ^( ItemState a, ItemState b) { typedef
mozilla::CastableTypedEnumResult<ItemState> Result; typedef
mozilla::detail::UnsignedIntegerTypeForEnum<ItemState>
::Type U; return Result(ItemState(U(a) ^ U(b))); } inline ItemState
& operator ^=(ItemState & a, ItemState b) { return a =
a ^ b; } inline constexpr mozilla::CastableTypedEnumResult<
ItemState> operator~(ItemState a) { typedef mozilla::CastableTypedEnumResult
<ItemState> Result; typedef mozilla::detail::UnsignedIntegerTypeForEnum
<ItemState>::Type U; return Result(ItemState(~(U(a))));
}
1256
1257GridItemInfo::GridItemInfo(nsIFrame* aFrame, const GridArea& aArea)
1258 : mFrame(aFrame), mArea(aArea), mBaselineOffset{0, 0} {
1259 mState[LogicalAxis::Block] =
1260 StateBits(mArea.mRows.mStart == kAutoLine ? eAutoPlacement : 0);
1261 mState[LogicalAxis::Inline] =
1262 StateBits(mArea.mCols.mStart == kAutoLine ? eAutoPlacement : 0);
1263
1264 if (auto* gridFrame = GetGridContainerFrame(mFrame)) {
1265 auto parentWM = aFrame->GetParent()->GetWritingMode();
1266 bool isOrthogonal = parentWM.IsOrthogonalTo(gridFrame->GetWritingMode());
1267 if (gridFrame->IsColSubgrid()) {
1268 mState[isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline] |=
1269 StateBits::eIsSubgrid;
1270 }
1271 if (gridFrame->IsRowSubgrid()) {
1272 mState[isOrthogonal ? LogicalAxis::Inline : LogicalAxis::Block] |=
1273 StateBits::eIsSubgrid;
1274 }
1275 }
1276}
1277
1278void GridItemInfo::ResetTrackSizingBits(LogicalAxis aAxis) {
1279 mState[aAxis] &= ~StateBits::eTrackSizingBits;
1280}
1281
1282void GridItemInfo::ReverseDirection(LogicalAxis aAxis, uint32_t aGridEnd) {
1283 mArea.LineRangeForAxis(aAxis).ReverseDirection(aGridEnd);
1284 ItemState& state = mState[aAxis];
1285 ItemState newState = state & ~ItemState::eEdgeBits;
1286 if (state & ItemState::eStartEdge) {
1287 newState |= ItemState::eEndEdge;
1288 }
1289 if (state & ItemState::eEndEdge) {
1290 newState |= ItemState::eStartEdge;
1291 }
1292 state = newState;
1293}
1294
1295void GridItemInfo::InhibitSubgrid(nsGridContainerFrame* aParent,
1296 LogicalAxis aAxis) {
1297 MOZ_ASSERT(IsSubgrid(aAxis))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSubgrid(aAxis))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSubgrid(aAxis)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsSubgrid(aAxis)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1297)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid(aAxis)" ")"
); do { MOZ_CrashSequence(__null, 1297); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1298 auto bit = NS_STATE_GRID_IS_COL_SUBGRID;
1299 if (aParent->GetWritingMode().IsOrthogonalTo(mFrame->GetWritingMode()) !=
1300 (aAxis == LogicalAxis::Block)) {
1301 bit = NS_STATE_GRID_IS_ROW_SUBGRID;
1302 }
1303 MOZ_ASSERT(SubgridFrame()->HasAnyStateBits(bit))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(SubgridFrame()->HasAnyStateBits(bit))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(SubgridFrame()->HasAnyStateBits(bit)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("SubgridFrame()->HasAnyStateBits(bit)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1303)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "SubgridFrame()->HasAnyStateBits(bit)"
")"); do { MOZ_CrashSequence(__null, 1303); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1304 SubgridFrame()->RemoveStateBits(bit);
1305 mState[aAxis] &= StateBits(~StateBits::eIsSubgrid);
1306}
1307
1308void GridItemInfo::MaybeInhibitSubgridInMasonry(nsGridContainerFrame* aParent,
1309 uint32_t aGridAxisTrackCount) {
1310 if (IsSubgrid(LogicalAxis::Inline) && aParent->IsRowMasonry() &&
1311 mArea.mRows.mStart != 0 && mArea.mCols.Extent() != aGridAxisTrackCount &&
1312 (mState[LogicalAxis::Inline] & eAutoPlacement)) {
1313 InhibitSubgrid(aParent, LogicalAxis::Inline);
1314 return;
1315 }
1316 if (IsSubgrid(LogicalAxis::Block) && aParent->IsColMasonry() &&
1317 mArea.mCols.mStart != 0 && mArea.mRows.Extent() != aGridAxisTrackCount &&
1318 (mState[LogicalAxis::Block] & eAutoPlacement)) {
1319 InhibitSubgrid(aParent, LogicalAxis::Block);
1320 }
1321}
1322
1323// Each subgrid stores this data about its items etc on a frame property.
1324struct nsGridContainerFrame::Subgrid {
1325 Subgrid(const GridArea& aArea, bool aIsOrthogonal, WritingMode aCBWM)
1326 : mArea(aArea),
1327 mGridColEnd(0),
1328 mGridRowEnd(0),
1329 mMarginBorderPadding(aCBWM),
1330 mIsOrthogonal(aIsOrthogonal) {}
1331
1332 // Return the relevant line range for the subgrid column axis.
1333 const LineRange& SubgridCols() const {
1334 return mIsOrthogonal ? mArea.mRows : mArea.mCols;
1335 }
1336 // Return the relevant line range for the subgrid row axis.
1337 const LineRange& SubgridRows() const {
1338 return mIsOrthogonal ? mArea.mCols : mArea.mRows;
1339 }
1340
1341 // The subgrid's items.
1342 nsTArray<GridItemInfo> mGridItems;
1343 // The subgrid's abs.pos. items.
1344 nsTArray<GridItemInfo> mAbsPosItems;
1345 // The subgrid's area as a grid item, i.e. in its parent's grid space.
1346 GridArea mArea;
1347 // The (inner) grid size for the subgrid, zero-based.
1348 uint32_t mGridColEnd;
1349 uint32_t mGridRowEnd;
1350 // The margin+border+padding for the subgrid box in its parent grid's WM.
1351 // (This also includes the size of any scrollbars.)
1352 LogicalMargin mMarginBorderPadding;
1353 // Does the subgrid frame have orthogonal writing-mode to its parent grid
1354 // container?
1355 bool mIsOrthogonal;
1356
1357 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, Subgrid)static const mozilla::FramePropertyDescriptor<Subgrid>*
Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<Subgrid>::NewWithDestructor<DeleteValue>(); return
&descriptor; }
1358};
1359using Subgrid = nsGridContainerFrame::Subgrid;
1360
1361void GridItemInfo::AdjustForRemovedTracks(
1362 LogicalAxis aAxis, const nsTArray<uint32_t>& aNumRemovedTracks) {
1363 const bool abspos = mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1364 auto& lines = mArea.LineRangeForAxis(aAxis);
1365 if (abspos) {
1366 lines.AdjustAbsPosForRemovedTracks(aNumRemovedTracks);
1367 } else {
1368 lines.AdjustForRemovedTracks(aNumRemovedTracks);
1369 }
1370 if (IsSubgrid()) {
1371 auto* subgrid = SubgridFrame()->GetProperty(Subgrid::Prop());
1372 if (subgrid) {
1373 auto& lines = subgrid->mArea.LineRangeForAxis(aAxis);
1374 if (abspos) {
1375 lines.AdjustAbsPosForRemovedTracks(aNumRemovedTracks);
1376 } else {
1377 lines.AdjustForRemovedTracks(aNumRemovedTracks);
1378 }
1379 }
1380 }
1381}
1382
1383/**
1384 * Track size data for use by subgrids (which don't do sizing of their own
1385 * in a subgridded axis). A non-subgrid container stores its resolved sizes,
1386 * but only if it has any subgrid children. A subgrid always stores one.
1387 * In a subgridded axis, we copy the parent's sizes (see CopyUsedTrackSizes).
1388 *
1389 * This struct us stored on a frame property, which may be null before the track
1390 * sizing step for the given container. A null property is semantically
1391 * equivalent to mCanResolveLineRangeSize being false in both axes.
1392 * @note the axis used to access this data is in the grid container's own
1393 * writing-mode, same as in other track-sizing functions.
1394 */
1395struct nsGridContainerFrame::UsedTrackSizes {
1396 UsedTrackSizes() = default;
1397
1398 /**
1399 * Setup mTrackPlans by copying track sizes from aFrame's grid container
1400 * parent when aAxis is subgridded (and recurse if the parent is a subgrid
1401 * that doesn't have sizes yet), or by running the Track Sizing Algo when
1402 * the axis is not subgridded (for a subgrid).
1403 * Set mCanResolveLineRangeSize[aAxis] to true once we have obtained
1404 * sizes for an axis (if it's already true then this method is a NOP).
1405 */
1406 void ResolveTrackSizesForAxis(nsGridContainerFrame* aFrame, LogicalAxis aAxis,
1407 gfxContext& aRC);
1408
1409 /** Helper function for the above method */
1410 void ResolveSubgridTrackSizesForAxis(nsGridContainerFrame* aFrame,
1411 LogicalAxis aAxis, Subgrid* aSubgrid,
1412 gfxContext& aRC,
1413 nscoord aContentBoxSize);
1414
1415 // This only has valid sizes when mCanResolveLineRangeSize is true in
1416 // the same axis. It may have zero tracks (a grid with only abs.pos.
1417 // subgrids/items may have zero tracks).
1418 PerLogicalAxis<TrackPlan> mTrackPlans;
1419 // True if mTrackPlans can be used to resolve line range sizes in an axis.
1420 PerLogicalAxis<bool> mCanResolveLineRangeSize{false, false};
1421
1422 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, UsedTrackSizes)static const mozilla::FramePropertyDescriptor<UsedTrackSizes
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<UsedTrackSizes>::NewWithDestructor<DeleteValue>(
); return &descriptor; }
1423};
1424using UsedTrackSizes = nsGridContainerFrame::UsedTrackSizes;
1425
1426#ifdef DEBUG1
1427void nsGridContainerFrame::GridItemInfo::Dump() const {
1428 auto Dump1 = [this](const char* aMsg, LogicalAxis aAxis) {
1429 auto state = mState[aAxis];
1430 if (!state) {
1431 return;
1432 }
1433 printf("%s", aMsg);
1434 if (state & ItemState::eEdgeBits) {
1435 printf("subgrid-adjacent-edges(");
1436 if (state & ItemState::eStartEdge) {
1437 printf("start ");
1438 }
1439 if (state & ItemState::eEndEdge) {
1440 printf("end");
1441 }
1442 printf(") ");
1443 }
1444 if (state & ItemState::eAutoPlacement) {
1445 printf("masonry-auto ");
1446 }
1447 if (state & ItemState::eIsSubgrid) {
1448 printf("subgrid ");
1449 }
1450 if (state & ItemState::eIsFlexing) {
1451 printf("flexing ");
1452 }
1453 if (state & ItemState::eContentBasedAutoMinSize) {
1454 printf("auto-min-size ");
1455 }
1456 if (state & ItemState::eClampMarginBoxMinSize) {
1457 printf("clamp ");
1458 }
1459 if (state & ItemState::eIsLastItemInMasonryTrack) {
1460 printf("last-in-track ");
1461 }
1462 if (state & ItemState::eFirstBaseline) {
1463 printf("first baseline %s-alignment ",
1464 (state & ItemState::eSelfBaseline) ? "self" : "content");
1465 }
1466 if (state & ItemState::eLastBaseline) {
1467 printf("last baseline %s-alignment ",
1468 (state & ItemState::eSelfBaseline) ? "self" : "content");
1469 }
1470 if (state & ItemState::eIsBaselineAligned) {
1471 printf("%.2fpx", NSAppUnitsToFloatPixels(mBaselineOffset[aAxis],
1472 AppUnitsPerCSSPixel()));
1473 }
1474 printf("\n");
1475 };
1476 printf("grid-row: %d %d\n", mArea.mRows.mStart, mArea.mRows.mEnd);
1477 Dump1(" grid block-axis: ", LogicalAxis::Block);
1478 printf("grid-column: %d %d\n", mArea.mCols.mStart, mArea.mCols.mEnd);
1479 Dump1(" grid inline-axis: ", LogicalAxis::Inline);
1480}
1481#endif
1482
1483/**
1484 * Encapsulates CSS track-sizing functions.
1485 */
1486struct nsGridContainerFrame::TrackSizingFunctions {
1487 private:
1488 TrackSizingFunctions(const GridTemplate& aTemplate,
1489 const StyleImplicitGridTracks& aAutoSizing,
1490 const Maybe<size_t>& aRepeatAutoIndex, bool aIsSubgrid)
1491 : mTemplate(aTemplate),
1492 mTrackListValues(aTemplate.TrackListValues()),
1493 mAutoSizing(aAutoSizing),
1494 mExplicitGridOffset(0),
1495 mRepeatAutoStart(aRepeatAutoIndex.valueOr(0)),
1496 mRepeatAutoEnd(mRepeatAutoStart),
1497 mHasRepeatAuto(aRepeatAutoIndex.isSome()) {
1498 MOZ_ASSERT(!mHasRepeatAuto || !aIsSubgrid,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || !aIsSubgrid)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mHasRepeatAuto || !aIsSubgrid
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mHasRepeatAuto || !aIsSubgrid" " (" "a track-list for a subgrid can't have an <auto-repeat> track"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1499
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || !aIsSubgrid"
") (" "a track-list for a subgrid can't have an <auto-repeat> track"
")"); do { MOZ_CrashSequence(__null, 1499); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1499 "a track-list for a subgrid can't have an <auto-repeat> track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || !aIsSubgrid)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mHasRepeatAuto || !aIsSubgrid
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mHasRepeatAuto || !aIsSubgrid" " (" "a track-list for a subgrid can't have an <auto-repeat> track"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1499
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || !aIsSubgrid"
") (" "a track-list for a subgrid can't have an <auto-repeat> track"
")"); do { MOZ_CrashSequence(__null, 1499); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1500 if (!aIsSubgrid) {
1501 ExpandNonRepeatAutoTracks();
1502 }
1503 if (mHasRepeatAuto) {
1504 if (NumRepeatTracks() == 0) [[unlikely]] {
1505 // We ran out of room before expanding the `repeat(auto-fill/fit)`
1506 // track, so it's outside the clamped grid.
1507 mHasRepeatAuto = false;
1508 } else {
1509 MOZ_ASSERT(mRepeatAutoStart < mExpandedTracks.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRepeatAutoStart < mExpandedTracks.Length())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mRepeatAutoStart < mExpandedTracks.Length()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mRepeatAutoStart < mExpandedTracks.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1509)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRepeatAutoStart < mExpandedTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 1509); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1510 }
1511 }
1512 }
1513
1514 public:
1515 TrackSizingFunctions(const GridTemplate& aGridTemplate,
1516 const StyleImplicitGridTracks& aAutoSizing,
1517 bool aIsSubgrid)
1518 : TrackSizingFunctions(aGridTemplate, aAutoSizing,
1519 aGridTemplate.RepeatAutoIndex(), aIsSubgrid) {}
1520
1521 private:
1522 enum { ForSubgridFallbackTag };
1523 TrackSizingFunctions(const GridTemplate& aGridTemplate,
1524 const StyleImplicitGridTracks& aAutoSizing,
1525 decltype(ForSubgridFallbackTag))
1526 : TrackSizingFunctions(aGridTemplate, aAutoSizing, Nothing(),
1527 /* aIsSubgrid */ true) {}
1528
1529 public:
1530 /**
1531 * This is used in a subgridded axis to resolve sizes before its parent's
1532 * sizes are known for intrinsic sizing purposes. It copies the slice of
1533 * the nearest non-subgridded axis' track sizing functions spanned by
1534 * the subgrid.
1535 *
1536 * FIXME: this was written before there was a spec... the spec now says:
1537 * "If calculating the layout of a grid item in this step depends on
1538 * the available space in the block axis, assume the available space
1539 * that it would have if any row with a definite max track sizing
1540 * function had that size and all other rows were infinite."
1541 * https://drafts.csswg.org/css-grid-2/#subgrid-sizing
1542 */
1543 static TrackSizingFunctions ForSubgridFallback(
1544 nsGridContainerFrame* aSubgridFrame, const Subgrid* aSubgrid,
1545 nsGridContainerFrame* aParentGridContainer, LogicalAxis aParentAxis) {
1546 MOZ_ASSERT(aSubgrid)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgrid)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubgrid))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aSubgrid", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgrid" ")"
); do { MOZ_CrashSequence(__null, 1546); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1547 MOZ_ASSERT(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonaldo { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal
? GetOrthogonalAxis(aParentAxis) : aParentAxis))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis
(aParentAxis) : aParentAxis)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1549)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1549); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1548 ? GetOrthogonalAxis(aParentAxis)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal
? GetOrthogonalAxis(aParentAxis) : aParentAxis))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis
(aParentAxis) : aParentAxis)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1549)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1549); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1549 : aParentAxis))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal
? GetOrthogonalAxis(aParentAxis) : aParentAxis))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis
(aParentAxis) : aParentAxis)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1549)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1549); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1550 nsGridContainerFrame* parent = aParentGridContainer;
1551 auto parentAxis = aParentAxis;
1552 LineRange range = aSubgrid->mArea.LineRangeForAxis(parentAxis);
1553 // Find our nearest non-subgridded axis and use its track sizing functions.
1554 while (parent->IsSubgrid(parentAxis)) {
1555 const auto* parentSubgrid = parent->GetProperty(Subgrid::Prop());
1556 auto* grandParent = parent->ParentGridContainerForSubgrid();
1557 auto grandParentWM = grandParent->GetWritingMode();
1558 bool isSameDirInAxis =
1559 parent->GetWritingMode().ParallelAxisStartsOnSameSide(parentAxis,
1560 grandParentWM);
1561 if (MOZ_UNLIKELY(!isSameDirInAxis)(__builtin_expect(!!(!isSameDirInAxis), 0))) {
1562 auto end = parentAxis == LogicalAxis::Block
1563 ? parentSubgrid->mGridRowEnd
1564 : parentSubgrid->mGridColEnd;
1565 range.ReverseDirection(end);
1566 // range is now in the same direction as the grand-parent's axis
1567 }
1568 auto grandParentAxis = parentSubgrid->mIsOrthogonal
1569 ? GetOrthogonalAxis(parentAxis)
1570 : parentAxis;
1571 const auto& parentRange =
1572 parentSubgrid->mArea.LineRangeForAxis(grandParentAxis);
1573 range.Translate(parentRange.mStart);
1574 // range is now in the grand-parent's coordinates
1575 parentAxis = grandParentAxis;
1576 parent = grandParent;
1577 }
1578 const auto* pos = parent->StylePosition();
1579 const auto isInlineAxis = parentAxis == LogicalAxis::Inline;
1580 const auto& szf =
1581 isInlineAxis ? pos->mGridTemplateRows : pos->mGridTemplateColumns;
1582 const auto& autoSizing =
1583 isInlineAxis ? pos->mGridAutoColumns : pos->mGridAutoRows;
1584 return TrackSizingFunctions(szf, autoSizing, ForSubgridFallbackTag);
1585 }
1586
1587 /**
1588 * Initialize the number of auto-fill/fit tracks to use.
1589 * This can be zero if no auto-fill/fit track was specified, or if the repeat
1590 * begins after the maximum allowed track.
1591 */
1592 void InitRepeatTracks(const NonNegativeLengthPercentageOrNormal& aGridGap,
1593 nscoord aMinSize, nscoord aSize, nscoord aMaxSize) {
1594 // Check for a repeat after the maximum allowed track.
1595 if (MOZ_UNLIKELY(mRepeatAutoStart >= kMaxTrack)(__builtin_expect(!!(mRepeatAutoStart >= kMaxTrack), 0))) {
1596 mHasRepeatAuto = false;
1597 mRepeatAutoStart = 0;
1598 mRepeatAutoEnd = 0;
1599 return;
1600 }
1601 uint32_t repeatTracks =
1602 CalculateRepeatFillCount(aGridGap, aMinSize, aSize, aMaxSize) *
1603 NumRepeatTracks();
1604 // Clamp the number of repeat tracks to the maximum possible track.
1605 repeatTracks = std::min(repeatTracks, kMaxTrack - mRepeatAutoStart);
1606 SetNumRepeatTracks(repeatTracks);
1607 // Blank out the removed flags for each of these tracks.
1608 mRemovedRepeatTracks.SetLength(repeatTracks);
1609 for (auto& track : mRemovedRepeatTracks) {
1610 track = false;
1611 }
1612 }
1613
1614 uint32_t CalculateRepeatFillCount(
1615 const NonNegativeLengthPercentageOrNormal& aGridGap, nscoord aMinSize,
1616 nscoord aSize, nscoord aMaxSize) const {
1617 if (!mHasRepeatAuto) {
1618 return 0;
1619 }
1620 // At this point no tracks will have been collapsed, so the RepeatEndDelta
1621 // should not be negative.
1622 MOZ_ASSERT(RepeatEndDelta() >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(RepeatEndDelta() >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(RepeatEndDelta() >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("RepeatEndDelta() >= 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1622)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "RepeatEndDelta() >= 0"
")"); do { MOZ_CrashSequence(__null, 1622); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1623 // Note that this uses NumRepeatTracks and mRepeatAutoStart/End, although
1624 // the result of this method is used to change those values to a fully
1625 // expanded value. Spec quotes are from
1626 // https://drafts.csswg.org/css-grid-2/#repeat-notation
1627 const uint32_t numTracks = mExpandedTracks.Length() + RepeatEndDelta();
1628 MOZ_ASSERT(numTracks >= 1, "expected at least the repeat() track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numTracks >= 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(numTracks >= 1))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("numTracks >= 1"
" (" "expected at least the repeat() track" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numTracks >= 1"
") (" "expected at least the repeat() track" ")"); do { MOZ_CrashSequence
(__null, 1628); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1629 if (MOZ_UNLIKELY(numTracks >= kMaxLine)(__builtin_expect(!!(numTracks >= kMaxLine), 0))) {
1630 // The fixed tracks plus an entire repetition is either larger or as
1631 // large as the maximum track, so we do not need to measure how many
1632 // repetitions will fit. This also avoids needing to check for if
1633 // kMaxLine - numTracks would underflow at the end where we clamp the
1634 // result.
1635 return 1;
1636 }
1637 nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize;
1638 if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) {
1639 // "Otherwise, the specified track list repeats only once."
1640 return 1;
1641 }
1642 nscoord repeatTrackSum = 0;
1643 // Note that one repeat() track size is included in |sum| in this loop.
1644 nscoord sum = 0;
1645 const nscoord percentBasis = aSize;
1646 for (uint32_t i = 0; i < numTracks; ++i) {
1647 // "treating each track as its max track sizing function if that is
1648 // definite or as its minimum track sizing function otherwise"
1649 // https://drafts.csswg.org/css-grid-2/#valdef-repeat-auto-fill
1650 nscoord trackSize;
1651 {
1652 const auto& sizingFunction = SizingFor(i);
1653 const auto& maxCoord = sizingFunction.GetMax();
1654 const auto& minCoord = sizingFunction.GetMin();
1655 if (maxCoord.IsBreadth() && minCoord.IsBreadth()) {
1656 // If the max is less than the min, then the max will be floored by
1657 // the min (essentially yielding minmax(min, min))
1658 // https://drafts.csswg.org/css-grid-2/#funcdef-grid-template-columns-minmax
1659 const nscoord minSize =
1660 ::ResolveToDefiniteSize(minCoord, percentBasis);
1661 const nscoord maxSize =
1662 ::ResolveToDefiniteSize(maxCoord, percentBasis);
1663 trackSize = std::max(maxSize, minSize);
1664 } else {
1665 const auto* coord = &maxCoord;
1666 if (!coord->IsBreadth()) {
1667 coord = &minCoord;
1668 if (!coord->IsBreadth()) {
1669 return 1;
1670 }
1671 }
1672 trackSize = ::ResolveToDefiniteSize(*coord, percentBasis);
1673 }
1674 }
1675
1676 if (i >= mRepeatAutoStart && i < mRepeatAutoEnd) {
1677 // Use a minimum 1px for the repeat() track-size.
1678 if (trackSize < AppUnitsPerCSSPixel()) {
1679 trackSize = AppUnitsPerCSSPixel();
1680 }
1681 repeatTrackSum += trackSize;
1682 }
1683 sum += trackSize;
1684 }
1685 nscoord gridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aSize);
1686 if (numTracks > 1) {
1687 // Add grid-gaps for all the tracks including the repeat() track.
1688 sum += gridGap * (numTracks - 1);
1689 }
1690 // Calculate the max number of tracks that fits without overflow.
1691 nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize;
1692 nscoord spaceToFill = available - sum;
1693 if (spaceToFill <= 0) {
1694 // "if any number of repetitions would overflow, then 1 repetition"
1695 return 1;
1696 }
1697 // Calculate the max number of tracks that fits without overflow.
1698 // Since we already have one repetition in sum, we can simply add one grid
1699 // gap for each element in the repeat.
1700 div_t q = div(spaceToFill, repeatTrackSum + gridGap * NumRepeatTracks());
1701 // The +1 here is for the one repeat track we already accounted for above.
1702 uint32_t numRepeatTracks = q.quot + 1;
1703 if (q.rem != 0 && maxFill == NS_UNCONSTRAINEDSIZE) {
1704 // "Otherwise, if the grid container has a definite min size in
1705 // the relevant axis, the number of repetitions is the largest possible
1706 // positive integer that fulfills that minimum requirement."
1707 ++numRepeatTracks; // one more to ensure the grid is at least min-size
1708 }
1709 // Clamp the number of repeat tracks so that the last line <= kMaxLine.
1710 // (note that |numTracks| already includes one repeat() track)
1711 MOZ_ASSERT(numTracks >= NumRepeatTracks())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numTracks >= NumRepeatTracks())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(numTracks >= NumRepeatTracks
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("numTracks >= NumRepeatTracks()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numTracks >= NumRepeatTracks()"
")"); do { MOZ_CrashSequence(__null, 1711); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1712 const uint32_t maxRepeatTrackCount = kMaxLine - numTracks;
1713 const uint32_t maxRepetitions = maxRepeatTrackCount / NumRepeatTracks();
1714 return std::min(numRepeatTracks, maxRepetitions);
1715 }
1716
1717 /**
1718 * Compute the explicit grid end line number (in a zero-based grid).
1719 * @param aGridTemplateAreasEnd 'grid-template-areas' end line in this axis
1720 */
1721 uint32_t ComputeExplicitGridEnd(uint32_t aGridTemplateAreasEnd) {
1722 uint32_t end = NumExplicitTracks() + 1;
1723 end = std::max(end, aGridTemplateAreasEnd);
1724 end = std::min(end, uint32_t(kMaxLine));
1725 return end;
1726 }
1727 const StyleTrackSize& SizingFor(uint32_t aTrackIndex) const {
1728 static const StyleTrackSize kAutoTrackSize =
1729 StyleTrackSize::Breadth(StyleTrackBreadth::Auto());
1730 // |aIndex| is the relative index to mAutoSizing. A negative value means it
1731 // is the last Nth element.
1732 auto getImplicitSize = [this](int32_t aIndex) -> const StyleTrackSize& {
1733 MOZ_ASSERT(!(mAutoSizing.Length() == 1 &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan
()[0] == kAutoTrackSize))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(mAutoSizing.Length() == 1 &&
mAutoSizing.AsSpan()[0] == kAutoTrackSize)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
" (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
") (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")"); do { MOZ_CrashSequence
(__null, 1736); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1734 mAutoSizing.AsSpan()[0] == kAutoTrackSize),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan
()[0] == kAutoTrackSize))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(mAutoSizing.Length() == 1 &&
mAutoSizing.AsSpan()[0] == kAutoTrackSize)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
" (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
") (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")"); do { MOZ_CrashSequence
(__null, 1736); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1735 "It's impossible to have one track with auto value because we "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan
()[0] == kAutoTrackSize))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(mAutoSizing.Length() == 1 &&
mAutoSizing.AsSpan()[0] == kAutoTrackSize)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
" (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
") (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")"); do { MOZ_CrashSequence
(__null, 1736); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1736 "filter out this case during parsing")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan
()[0] == kAutoTrackSize))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(mAutoSizing.Length() == 1 &&
mAutoSizing.AsSpan()[0] == kAutoTrackSize)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
" (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 1736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mAutoSizing.Length() == 1 && mAutoSizing.AsSpan()[0] == kAutoTrackSize)"
") (" "It's impossible to have one track with auto value because we "
"filter out this case during parsing" ")"); do { MOZ_CrashSequence
(__null, 1736); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1737
1738 if (mAutoSizing.IsEmpty()) {
1739 return kAutoTrackSize;
1740 }
1741
1742 // If multiple track sizes are given, the pattern is repeated as necessary
1743 // to find the size of the implicit tracks.
1744 int32_t i = aIndex % int32_t(mAutoSizing.Length());
1745 if (i < 0) {
1746 i += mAutoSizing.Length();
1747 }
1748 return mAutoSizing.AsSpan()[i];
1749 };
1750
1751 if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)(__builtin_expect(!!(aTrackIndex < mExplicitGridOffset), 0
))
) {
1752 // The last implicit grid track before the explicit grid receives the
1753 // last specified size, and so on backwards. Therefore we pass the
1754 // negative relative index to imply that we should get the implicit size
1755 // from the last Nth specified grid auto size.
1756 return getImplicitSize(int32_t(aTrackIndex) -
1757 int32_t(mExplicitGridOffset));
1758 }
1759 uint32_t index = aTrackIndex - mExplicitGridOffset;
1760 MOZ_ASSERT(mRepeatAutoStart <= mRepeatAutoEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRepeatAutoStart <= mRepeatAutoEnd)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mRepeatAutoStart <= mRepeatAutoEnd))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mRepeatAutoStart <= mRepeatAutoEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1760)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRepeatAutoStart <= mRepeatAutoEnd"
")"); do { MOZ_CrashSequence(__null, 1760); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1761
1762 if (index >= mRepeatAutoStart) {
1763 if (index < mRepeatAutoEnd) {
1764 // Expand the repeat tracks.
1765 const auto& indices = mExpandedTracks[mRepeatAutoStart];
1766 const TrackListValue& value = mTrackListValues[indices.first];
1767
1768 // We expect the default to be used for all track repeats.
1769 MOZ_ASSERT(indices.second == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(indices.second == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(indices.second == 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("indices.second == 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1769)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "indices.second == 0"
")"); do { MOZ_CrashSequence(__null, 1769); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1770
1771 const auto& repeatTracks = value.AsTrackRepeat().track_sizes.AsSpan();
1772
1773 // Find the repeat track to use, skipping over any collapsed tracks.
1774 const uint32_t finalRepeatIndex = (index - mRepeatAutoStart);
1775 uint32_t repeatWithCollapsed = 0;
1776 // NOTE: We need SizingFor before the final collapsed tracks are known.
1777 // We know that it's invalid to have empty mRemovedRepeatTracks when
1778 // there are any repeat tracks, so we can detect that situation here.
1779 if (mRemovedRepeatTracks.IsEmpty()) {
1780 repeatWithCollapsed = finalRepeatIndex;
1781 } else {
1782 // Count up through the repeat tracks, until we have seen
1783 // finalRepeatIndex number of non-collapsed tracks.
1784 for (uint32_t repeatNoCollapsed = 0;
1785 repeatNoCollapsed < finalRepeatIndex; repeatWithCollapsed++) {
1786 if (!mRemovedRepeatTracks[repeatWithCollapsed]) {
1787 repeatNoCollapsed++;
1788 }
1789 }
1790 // If we stopped iterating on a collapsed track, continue to the next
1791 // non-collapsed track.
1792 while (mRemovedRepeatTracks[repeatWithCollapsed]) {
1793 repeatWithCollapsed++;
1794 }
1795 }
1796 return repeatTracks[repeatWithCollapsed % repeatTracks.Length()];
1797 } else {
1798 // The index is after the repeat auto range, adjust it to skip over the
1799 // repeat value. This will have no effect if there is no auto repeat,
1800 // since then RepeatEndDelta will return zero.
1801 index -= RepeatEndDelta();
1802 }
1803 }
1804 if (index >= mExpandedTracks.Length()) {
1805 return getImplicitSize(index - mExpandedTracks.Length());
1806 }
1807 auto& indices = mExpandedTracks[index];
1808 const TrackListValue& value = mTrackListValues[indices.first];
1809 if (value.IsTrackSize()) {
1810 MOZ_ASSERT(indices.second == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(indices.second == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(indices.second == 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("indices.second == 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1810)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "indices.second == 0"
")"); do { MOZ_CrashSequence(__null, 1810); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1811 return value.AsTrackSize();
1812 }
1813 return value.AsTrackRepeat().track_sizes.AsSpan()[indices.second];
1814 }
1815 const StyleTrackBreadth& MaxSizingFor(uint32_t aTrackIndex) const {
1816 return SizingFor(aTrackIndex).GetMax();
1817 }
1818 const StyleTrackBreadth& MinSizingFor(uint32_t aTrackIndex) const {
1819 return SizingFor(aTrackIndex).GetMin();
1820 }
1821 uint32_t NumExplicitTracks() const {
1822 return mExpandedTracks.Length() + RepeatEndDelta();
1823 }
1824 uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; }
1825 // The difference between mExplicitGridEnd and mSizingFunctions.Length().
1826 int32_t RepeatEndDelta() const {
1827 return mHasRepeatAuto ? int32_t(NumRepeatTracks()) - 1 : 0;
1828 }
1829 void SetNumRepeatTracks(uint32_t aNumRepeatTracks) {
1830 MOZ_ASSERT(mHasRepeatAuto || aNumRepeatTracks == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mHasRepeatAuto || aNumRepeatTracks == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mHasRepeatAuto || aNumRepeatTracks == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mHasRepeatAuto || aNumRepeatTracks == 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1830)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mHasRepeatAuto || aNumRepeatTracks == 0"
")"); do { MOZ_CrashSequence(__null, 1830); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1831 mRepeatAutoEnd = mRepeatAutoStart + aNumRepeatTracks;
1832 }
1833
1834 [[nodiscard]] bool EmplaceExpandedTrack(size_t aTrackListValueIndex,
1835 size_t aRepeatIndex) {
1836 MOZ_ASSERT(mExpandedTracks.Length() < kMaxLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mExpandedTracks.Length() < kMaxLine)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mExpandedTracks.Length() < kMaxLine))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mExpandedTracks.Length() < kMaxLine"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1836)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mExpandedTracks.Length() < kMaxLine"
")"); do { MOZ_CrashSequence(__null, 1836); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1837 if (mExpandedTracks.Length() == kMaxTrack) {
1838 return false;
1839 }
1840 return mExpandedTracks.EmplaceBack(fallible, aTrackListValueIndex,
1841 aRepeatIndex);
1842 }
1843
1844 // Store mTrackListValues into mExpandedTracks with `repeat(INTEGER, ...)`
1845 // tracks expanded.
1846 void ExpandNonRepeatAutoTracks() {
1847 MOZ_ASSERT(mExpandedTracks.Length() <= kMaxTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mExpandedTracks.Length() <= kMaxTrack)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mExpandedTracks.Length() <= kMaxTrack))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mExpandedTracks.Length() <= kMaxTrack"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1847)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mExpandedTracks.Length() <= kMaxTrack"
")"); do { MOZ_CrashSequence(__null, 1847); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1848 for (size_t i = 0; i < mTrackListValues.Length(); ++i) {
1849 auto& value = mTrackListValues[i];
1850 if (value.IsTrackSize()) {
1851 if (!EmplaceExpandedTrack(i, 0)) {
1852 return;
1853 }
1854 continue;
1855 }
1856 auto& repeat = value.AsTrackRepeat();
1857 if (!repeat.count.IsNumber()) {
1858 MOZ_ASSERT(i == mRepeatAutoStart)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(i == mRepeatAutoStart)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(i == mRepeatAutoStart))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("i == mRepeatAutoStart"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1858)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "i == mRepeatAutoStart"
")"); do { MOZ_CrashSequence(__null, 1858); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1859 const auto repeatAutoStart = mExpandedTracks.Length();
1860 if (!EmplaceExpandedTrack(i, 0)) {
1861 return;
1862 }
1863 mRepeatAutoStart = repeatAutoStart;
1864 mRepeatAutoEnd = repeatAutoStart + repeat.track_sizes.Length();
1865 continue;
1866 }
1867 for (auto j : IntegerRange(repeat.count.AsNumber())) {
1868 (void)j;
1869 size_t trackSizesCount = repeat.track_sizes.Length();
1870 for (auto k : IntegerRange(trackSizesCount)) {
1871 if (!EmplaceExpandedTrack(i, k)) {
1872 return;
1873 }
1874 }
1875 }
1876 }
1877 }
1878
1879 // Some style data references, for easy access.
1880 const GridTemplate& mTemplate;
1881 const Span<const TrackListValue> mTrackListValues;
1882 const StyleImplicitGridTracks& mAutoSizing;
1883 // An array from expanded track sizes (without expanding auto-repeat, which is
1884 // included just once at `mRepeatAutoStart`).
1885 //
1886 // Each entry contains two indices, the first into mTrackListValues, and a
1887 // second one inside mTrackListValues' repeat value, if any, or zero
1888 // otherwise.
1889 nsTArray<std::pair<size_t, size_t>> mExpandedTracks;
1890 // Offset from the start of the implicit grid to the first explicit track.
1891 uint32_t mExplicitGridOffset;
1892 // The index of the repeat(auto-fill/fit) track, or zero if there is none.
1893 // Relative to mExplicitGridOffset (repeat tracks are explicit by definition).
1894 uint32_t mRepeatAutoStart;
1895 // The (hypothetical) index of the last such repeat() track.
1896 uint32_t mRepeatAutoEnd;
1897 // True if there is a specified repeat(auto-fill/fit) track.
1898 bool mHasRepeatAuto;
1899 // True if this track (relative to mRepeatAutoStart) is a removed auto-fit.
1900 // Indexed relative to mExplicitGridOffset + mRepeatAutoStart.
1901 nsTArray<bool> mRemovedRepeatTracks;
1902};
1903
1904/**
1905 * Utility class to find line names. It provides an interface to lookup line
1906 * names with a dynamic number of repeat(auto-fill/fit) tracks taken into
1907 * account.
1908 */
1909class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap {
1910 public:
1911 /**
1912 * Create a LineNameMap.
1913 * @param aStylePosition the style for the grid container
1914 * @param aImplicitNamedAreas the implicit areas for the grid container
1915 * @param aGridTemplate is the grid-template-rows/columns data for this axis
1916 * @param aParentLineNameMap the parent grid's map parallel to this map, or
1917 * null if this map isn't for a subgrid
1918 * @param aRange the subgrid's range in the parent grid, or null
1919 * @param aIsSameDirection true if our axis progresses in the same direction
1920 * in the subgrid and parent
1921 * @param aIsOrthogonal true if the subgrid and parent have orthongonal
1922 * writing modes
1923 */
1924 LineNameMap(const nsStylePosition* aStylePosition,
1925 const ImplicitNamedAreas* aImplicitNamedAreas,
1926 const TrackSizingFunctions& aTracks,
1927 const LineNameMap* aParentLineNameMap, const LineRange* aRange,
1928 bool aIsSameDirection = true, bool aIsOrthogonal = false)
1929 : mStylePosition(aStylePosition),
1930 mAreas(aImplicitNamedAreas),
1931 mRepeatAutoStart(aTracks.mRepeatAutoStart),
1932 mRepeatAutoEnd(aTracks.mRepeatAutoEnd),
1933 mRepeatEndDelta(aTracks.RepeatEndDelta()),
1934 mParentLineNameMap(aParentLineNameMap),
1935 mRange(aRange),
1936 mIsSameDirection(aIsSameDirection),
1937 mIsOrthogonal(aIsOrthogonal),
1938 mHasRepeatAuto(aTracks.mHasRepeatAuto) {
1939 if (MOZ_UNLIKELY(aRange)(__builtin_expect(!!(aRange), 0))) { // subgrid case
1940 mClampMinLine = 1;
1941 mClampMaxLine = 1 + aRange->Extent();
1942 MOZ_ASSERT(aTracks.mTemplate.IsSubgrid(), "Should be subgrid type")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTracks.mTemplate.IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTracks.mTemplate.IsSubgrid(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aTracks.mTemplate.IsSubgrid()" " (" "Should be subgrid type"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 1942
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mTemplate.IsSubgrid()"
") (" "Should be subgrid type" ")"); do { MOZ_CrashSequence(
__null, 1942); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
1943 ExpandRepeatLineNamesForSubgrid(*aTracks.mTemplate.AsSubgrid());
1944 // we've expanded all subgrid auto-fill lines in
1945 // ExpandRepeatLineNamesForSubgrid()
1946 mRepeatAutoStart = 0;
1947 mRepeatAutoEnd = mRepeatAutoStart;
1948 mHasRepeatAuto = false;
1949 } else {
1950 mClampMinLine = kMinLine;
1951 mClampMaxLine = kMaxLine;
1952 if (mHasRepeatAuto) {
1953 mTrackAutoRepeatLineNames =
1954 aTracks.mTemplate.GetRepeatAutoValue()->line_names.AsSpan();
1955 }
1956 ExpandRepeatLineNames(aTracks);
1957 }
1958 if (mHasRepeatAuto) {
1959 // We need mTemplateLinesEnd to be after all line names.
1960 // mExpandedLineNames has one repetition of the repeat(auto-fit/fill)
1961 // track name lists already, so we must subtract the number of repeat
1962 // track name lists to get to the number of non-repeat tracks, minus 2
1963 // because the first and last line name lists are shared with the
1964 // preceding and following non-repeat line name lists. We then add
1965 // mRepeatEndDelta to include the interior line name lists from repeat
1966 // tracks.
1967 mTemplateLinesEnd = mExpandedLineNames.Length() -
1968 (mTrackAutoRepeatLineNames.Length() - 2) +
1969 mRepeatEndDelta;
1970 } else {
1971 mTemplateLinesEnd = mExpandedLineNames.Length();
1972 }
1973 MOZ_ASSERT(mHasRepeatAuto || mRepeatEndDelta <= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mHasRepeatAuto || mRepeatEndDelta <= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mHasRepeatAuto || mRepeatEndDelta <= 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mHasRepeatAuto || mRepeatEndDelta <= 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1973)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mHasRepeatAuto || mRepeatEndDelta <= 0"
")"); do { MOZ_CrashSequence(__null, 1973); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1974 MOZ_ASSERT(!mHasRepeatAuto || aRange ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || aRange || (mExpandedLineNames.Length
() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length()))>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(!mHasRepeatAuto || aRange || (mExpandedLineNames
.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1976)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1976); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1975 (mExpandedLineNames.Length() >= 2 &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || aRange || (mExpandedLineNames.Length
() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length()))>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(!mHasRepeatAuto || aRange || (mExpandedLineNames
.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1976)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1976); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1976 mRepeatAutoStart <= mExpandedLineNames.Length()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || aRange || (mExpandedLineNames.Length
() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length()))>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(!mHasRepeatAuto || aRange || (mExpandedLineNames
.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames
.Length())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 1976)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1976); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1977 }
1978
1979 // Store line names into mExpandedLineNames with `repeat(INTEGER, ...)`
1980 // expanded for non-subgrid.
1981 void ExpandRepeatLineNames(const TrackSizingFunctions& aTracks) {
1982 auto lineNameLists = aTracks.mTemplate.LineNameLists();
1983
1984 const auto& trackListValues = aTracks.mTrackListValues;
1985 const NameList* nameListToMerge = nullptr;
1986 // NOTE(emilio): We rely on std::move clearing out the array.
1987 SmallPointerArray<const NameList> names;
1988 const uint32_t end =
1989 std::min<uint32_t>(lineNameLists.Length(), mClampMaxLine + 1);
1990 auto AppendExpandedNames = [&]() -> bool {
1991 if (mExpandedLineNames.Length() == size_t(mClampMaxLine)) {
1992 return false;
1993 }
1994 return mExpandedLineNames.AppendElement(std::move(names), fallible);
1995 };
1996 for (uint32_t i = 0; i < end; ++i) {
1997 if (nameListToMerge) {
1998 names.AppendElement(nameListToMerge);
1999 nameListToMerge = nullptr;
2000 }
2001 names.AppendElement(&lineNameLists[i]);
2002 if (i >= trackListValues.Length()) {
2003 if (!AppendExpandedNames()) {
2004 return;
2005 }
2006 continue;
2007 }
2008 const auto& value = trackListValues[i];
2009 if (value.IsTrackSize()) {
2010 if (!AppendExpandedNames()) {
2011 return;
2012 }
2013 continue;
2014 }
2015 const auto& repeat = value.AsTrackRepeat();
2016 if (!repeat.count.IsNumber()) {
2017 const auto repeatNames = repeat.line_names.AsSpan();
2018 // If the repeat was truncated due to more than kMaxLine tracks, then
2019 // the repeat will no longer be set on mRepeatAutoStart).
2020 MOZ_ASSERT(!mHasRepeatAuto ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames
.Length())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(!mHasRepeatAuto || mRepeatAutoStart
== mExpandedLineNames.Length()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2021)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
")"); do { MOZ_CrashSequence(__null, 2021); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2021 mRepeatAutoStart == mExpandedLineNames.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames
.Length())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(!mHasRepeatAuto || mRepeatAutoStart
== mExpandedLineNames.Length()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2021)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
")"); do { MOZ_CrashSequence(__null, 2021); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2022 MOZ_ASSERT(repeatNames.Length() >= 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeatNames.Length() >= 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(repeatNames.Length() >= 2
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"repeatNames.Length() >= 2", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatNames.Length() >= 2"
")"); do { MOZ_CrashSequence(__null, 2022); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2023 for (const auto j : IntegerRange(repeatNames.Length() - 1)) {
2024 names.AppendElement(&repeatNames[j]);
2025 if (!AppendExpandedNames()) {
2026 return;
2027 }
2028 }
2029 nameListToMerge = &repeatNames[repeatNames.Length() - 1];
2030 continue;
2031 }
2032 for (auto j : IntegerRange(repeat.count.AsNumber())) {
2033 (void)j;
2034 if (nameListToMerge) {
2035 names.AppendElement(nameListToMerge);
2036 nameListToMerge = nullptr;
2037 }
2038 size_t trackSizesCount = repeat.track_sizes.Length();
2039 auto repeatLineNames = repeat.line_names.AsSpan();
2040 MOZ_ASSERT(repeatLineNames.Length() == trackSizesCount ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeatLineNames.Length() == trackSizesCount || repeatLineNames
.Length() == trackSizesCount + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(repeatLineNames.Length() == trackSizesCount
|| repeatLineNames.Length() == trackSizesCount + 1))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2041)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
")"); do { MOZ_CrashSequence(__null, 2041); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2041 repeatLineNames.Length() == trackSizesCount + 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeatLineNames.Length() == trackSizesCount || repeatLineNames
.Length() == trackSizesCount + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(repeatLineNames.Length() == trackSizesCount
|| repeatLineNames.Length() == trackSizesCount + 1))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2041)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
")"); do { MOZ_CrashSequence(__null, 2041); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2042 for (auto k : IntegerRange(trackSizesCount)) {
2043 names.AppendElement(&repeatLineNames[k]);
2044 if (!AppendExpandedNames()) {
2045 return;
2046 }
2047 }
2048 if (repeatLineNames.Length() == trackSizesCount + 1) {
2049 nameListToMerge = &repeatLineNames[trackSizesCount];
2050 }
2051 }
2052 }
2053 }
2054
2055 // Store line names into mExpandedLineNames with `repeat(INTEGER, ...)`
2056 // expanded, and all `repeat(...)` expanded for subgrid.
2057 // https://drafts.csswg.org/css-grid-2/#resolved-track-list-subgrid
2058 void ExpandRepeatLineNamesForSubgrid(
2059 const StyleGenericLineNameList<StyleInteger>& aStyleLineNameList) {
2060 const auto& lineNameList = aStyleLineNameList.line_names.AsSpan();
2061 SmallPointerArray<const NameList> names;
2062 auto AppendExpandedNames = [&]() -> bool {
2063 if (mExpandedLineNames.Length() == size_t(mClampMaxLine)) {
2064 return false;
2065 }
2066 return mExpandedLineNames.AppendElement(std::move(names), fallible);
2067 };
2068 for (const auto& item : lineNameList) {
2069 if (item.IsLineNames()) {
2070 // <line-names> case. Just copy it.
2071 names.AppendElement(&item.AsLineNames());
2072 if (!AppendExpandedNames()) {
2073 return;
2074 }
2075 continue;
2076 }
2077
2078 MOZ_ASSERT(item.IsRepeat())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item.IsRepeat())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(item.IsRepeat()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("item.IsRepeat()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2078)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.IsRepeat()" ")"
); do { MOZ_CrashSequence(__null, 2078); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2079 const auto& repeat = item.AsRepeat();
2080 const auto repeatLineNames = repeat.line_names.AsSpan();
2081
2082 if (repeat.count.IsNumber()) {
2083 // Clone all <line-names>+ (repeated by N) into
2084 // |mExpandedLineNames|.
2085 for (uint32_t repeatCount = 0;
2086 repeatCount < (uint32_t)repeat.count.AsNumber(); ++repeatCount) {
2087 for (const NameList& lineNames : repeatLineNames) {
2088 names.AppendElement(&lineNames);
2089 if (!AppendExpandedNames()) {
2090 return;
2091 }
2092 }
2093 }
2094 continue;
2095 }
2096
2097 MOZ_ASSERT(repeat.count.IsAutoFill(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeat.count.IsAutoFill())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(repeat.count.IsAutoFill())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("repeat.count.IsAutoFill()"
" (" "RepeatCount of subgrid is number or auto-fill" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeat.count.IsAutoFill()"
") (" "RepeatCount of subgrid is number or auto-fill" ")"); do
{ MOZ_CrashSequence(__null, 2098); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2098 "RepeatCount of subgrid is number or auto-fill")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeat.count.IsAutoFill())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(repeat.count.IsAutoFill())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("repeat.count.IsAutoFill()"
" (" "RepeatCount of subgrid is number or auto-fill" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeat.count.IsAutoFill()"
") (" "RepeatCount of subgrid is number or auto-fill" ")"); do
{ MOZ_CrashSequence(__null, 2098); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2099
2100 const size_t fillLen = repeatLineNames.Length();
2101 const int32_t extraAutoFillLineCount =
2102 mClampMaxLine -
2103 (int32_t)aStyleLineNameList.expanded_line_names_length;
2104 // Maximum possible number of repeat name lists.
2105 // Note: |expanded_line_names_length| doesn't include auto repeat.
2106 const uint32_t possibleRepeatLength =
2107 std::max<int32_t>(0, extraAutoFillLineCount);
2108 const uint32_t repeatRemainder = possibleRepeatLength % fillLen;
2109
2110 // Note: Expand 'auto-fill' names for subgrid for now since
2111 // HasNameAt() only deals with auto-repeat **tracks** currently.
2112 const size_t len = possibleRepeatLength - repeatRemainder;
2113 for (size_t j = 0; j < len; ++j) {
2114 names.AppendElement(&repeatLineNames[j % fillLen]);
2115 if (!AppendExpandedNames()) {
2116 return;
2117 }
2118 }
2119 }
2120 }
2121
2122 /**
2123 * Find the aNth occurrence of aName, searching forward if aNth is positive,
2124 * and in reverse if aNth is negative (aNth == 0 is invalid), starting from
2125 * aFromIndex (not inclusive), and return a 1-based line number.
2126 * Also take into account there is an unconditional match at the lines in
2127 * aImplicitLines.
2128 * Return zero if aNth occurrences can't be found. In that case, aNth has
2129 * been decremented with the number of occurrences that were found (if any).
2130 *
2131 * E.g. to search for "A 2" forward from the start of the grid: aName is "A"
2132 * aNth is 2 and aFromIndex is zero. To search for "A -2", aNth is -2 and
2133 * aFromIndex is ExplicitGridEnd + 1 (which is the line "before" the last
2134 * line when we're searching in reverse). For "span A 2", aNth is 2 when
2135 * used on a grid-[row|column]-end property and -2 for a *-start property,
2136 * and aFromIndex is the line (which we should skip) on the opposite property.
2137 */
2138 uint32_t FindNamedLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2139 const nsTArray<uint32_t>& aImplicitLines) const {
2140 MOZ_ASSERT(aName)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aName)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aName))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aName", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aName" ")")
; do { MOZ_CrashSequence(__null, 2140); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2141 MOZ_ASSERT(!aName->IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aName->IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aName->IsEmpty()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aName->IsEmpty()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2141)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aName->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 2141); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2142 MOZ_ASSERT(aNth && *aNth != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNth && *aNth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNth && *aNth != 0))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aNth && *aNth != 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2142)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth != 0"
")"); do { MOZ_CrashSequence(__null, 2142); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2143 if (*aNth > 0) {
2144 return FindLine(aName, aNth, aFromIndex, aImplicitLines);
2145 }
2146 int32_t nth = -*aNth;
2147 int32_t line = RFindLine(aName, &nth, aFromIndex, aImplicitLines);
2148 *aNth = -nth;
2149 return line;
2150 }
2151
2152 /**
2153 * Return a set of lines in aImplicitLines which matches the area name aName
2154 * on aSide. For example, for aName "a" and aSide being an end side, it
2155 * returns the line numbers which would match "a-end" in the relevant axis.
2156 * For subgrids it includes searching the relevant axis in all ancestor
2157 * grids too (within this subgrid's spanned area). If an ancestor has
2158 * opposite direction, we switch aSide to the opposite logical side so we
2159 * match on the same physical side as the original subgrid we're resolving
2160 * the name for.
2161 */
2162 void FindNamedAreas(nsAtom* aName, LogicalSide aSide,
2163 nsTArray<uint32_t>& aImplicitLines) const {
2164 // True if we're currently in a map that has the same direction as 'this'.
2165 bool sameDirectionAsThis = true;
2166 uint32_t min = !mParentLineNameMap ? 1 : mClampMinLine;
2167 uint32_t max = mClampMaxLine;
2168 for (auto* map = this; true;) {
2169 uint32_t line = map->FindNamedArea(aName, aSide, min, max);
2170 if (line > 0) {
2171 if (MOZ_LIKELY(sameDirectionAsThis)(__builtin_expect(!!(sameDirectionAsThis), 1))) {
2172 line -= min - 1;
2173 } else {
2174 line = max - line + 1;
2175 }
2176 aImplicitLines.AppendElement(line);
2177 }
2178 auto* parent = map->mParentLineNameMap;
2179 if (!parent) {
2180 if (MOZ_UNLIKELY(aImplicitLines.Length() > 1)(__builtin_expect(!!(aImplicitLines.Length() > 1), 0))) {
2181 // Remove duplicates and sort in ascending order.
2182 aImplicitLines.Sort();
2183 for (size_t i = 0; i < aImplicitLines.Length(); ++i) {
2184 uint32_t prev = aImplicitLines[i];
2185 auto j = i + 1;
2186 const auto start = j;
2187 while (j < aImplicitLines.Length() && aImplicitLines[j] == prev) {
2188 ++j;
2189 }
2190 if (j != start) {
2191 aImplicitLines.RemoveElementsAt(start, j - start);
2192 }
2193 }
2194 }
2195 return;
2196 }
2197 if (MOZ_UNLIKELY(!map->mIsSameDirection)(__builtin_expect(!!(!map->mIsSameDirection), 0))) {
2198 aSide = GetOppositeSide(aSide);
2199 sameDirectionAsThis = !sameDirectionAsThis;
2200 }
2201 if (MOZ_UNLIKELY(map->mIsOrthogonal)(__builtin_expect(!!(map->mIsOrthogonal), 0))) {
2202 aSide =
2203 MakeLogicalSide(GetOrthogonalAxis(GetAxis(aSide)), GetEdge(aSide));
2204 }
2205 min = map->TranslateToParentMap(min);
2206 max = map->TranslateToParentMap(max);
2207 if (min > max) {
2208 MOZ_ASSERT(!map->mIsSameDirection)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!map->mIsSameDirection)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!map->mIsSameDirection)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!map->mIsSameDirection"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2208)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!map->mIsSameDirection"
")"); do { MOZ_CrashSequence(__null, 2208); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2209 std::swap(min, max);
2210 }
2211 map = parent;
2212 }
2213 }
2214
2215 /**
2216 * Return true if any implicit named areas match aName, in this map or
2217 * in any of our ancestor maps.
2218 */
2219 bool HasImplicitNamedArea(nsAtom* aName) const {
2220 const auto* map = this;
2221 do {
2222 if (map->mAreas && map->mAreas->has(aName)) {
2223 return true;
2224 }
2225 map = map->mParentLineNameMap;
2226 } while (map);
2227 return false;
2228 }
2229
2230 // For generating line name data for devtools.
2231 nsTArray<nsTArray<StyleCustomIdent>>
2232 GetResolvedLineNamesForComputedGridTrackInfo() const {
2233 nsTArray<nsTArray<StyleCustomIdent>> result;
2234 for (auto& expandedLine : mExpandedLineNames) {
2235 nsTArray<StyleCustomIdent> line;
2236 for (auto* chunk : expandedLine) {
2237 for (auto& name : chunk->AsSpan()) {
2238 line.AppendElement(name);
2239 }
2240 }
2241 result.AppendElement(std::move(line));
2242 }
2243 return result;
2244 }
2245
2246 nsTArray<RefPtr<nsAtom>> GetExplicitLineNamesAtIndex(uint32_t aIndex) const {
2247 nsTArray<RefPtr<nsAtom>> lineNames;
2248 if (aIndex < mTemplateLinesEnd) {
2249 const auto nameLists = GetLineNamesAt(aIndex);
2250 for (const NameList* nameList : nameLists) {
2251 for (const auto& name : nameList->AsSpan()) {
2252 lineNames.AppendElement(name.AsAtom());
2253 }
2254 }
2255 }
2256 return lineNames;
2257 }
2258
2259 const nsTArray<SmallPointerArray<const NameList>>& ExpandedLineNames() const {
2260 return mExpandedLineNames;
2261 }
2262 const Span<const StyleOwnedSlice<StyleCustomIdent>>&
2263 TrackAutoRepeatLineNames() const {
2264 return mTrackAutoRepeatLineNames;
2265 }
2266 bool HasRepeatAuto() const { return mHasRepeatAuto; }
2267 uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; }
2268 uint32_t RepeatAutoStart() const { return mRepeatAutoStart; }
2269
2270 // The min/max line number (1-based) for clamping.
2271 int32_t mClampMinLine;
2272 int32_t mClampMaxLine;
2273
2274 private:
2275 // Return true if this map represents a subgridded axis.
2276 bool IsSubgridded() const { return mParentLineNameMap != nullptr; }
2277
2278 /**
2279 * @see FindNamedLine, this function searches forward.
2280 */
2281 uint32_t FindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2282 const nsTArray<uint32_t>& aImplicitLines) const {
2283 MOZ_ASSERT(aNth && *aNth > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNth && *aNth > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNth && *aNth > 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aNth && *aNth > 0", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth > 0"
")"); do { MOZ_CrashSequence(__null, 2283); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2284 int32_t nth = *aNth;
2285 // For a subgrid we need to search to the end of the grid rather than
2286 // the end of the local name list, since ancestors might match.
2287 const uint32_t end = IsSubgridded() ? mClampMaxLine : mTemplateLinesEnd;
2288 uint32_t line;
2289 uint32_t i = aFromIndex;
2290 for (; i < end; i = line) {
2291 line = i + 1;
2292 if (Contains(i, aName) || aImplicitLines.Contains(line)) {
2293 if (--nth == 0) {
2294 return line;
2295 }
2296 }
2297 }
2298 for (auto implicitLine : aImplicitLines) {
2299 if (implicitLine > i) {
2300 // implicitLine is after the lines we searched above so it's last.
2301 // (grid-template-areas has more tracks than
2302 // grid-template-[rows|columns])
2303 if (--nth == 0) {
2304 return implicitLine;
2305 }
2306 }
2307 }
2308 MOZ_ASSERT(nth > 0, "should have returned a valid line above already")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nth > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nth > 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nth > 0" " (" "should have returned a valid line above already"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 2308
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nth > 0" ") ("
"should have returned a valid line above already" ")"); do {
MOZ_CrashSequence(__null, 2308); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2309 *aNth = nth;
2310 return 0;
2311 }
2312
2313 /**
2314 * @see FindNamedLine, this function searches in reverse.
2315 */
2316 uint32_t RFindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2317 const nsTArray<uint32_t>& aImplicitLines) const {
2318 MOZ_ASSERT(aNth && *aNth > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNth && *aNth > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNth && *aNth > 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aNth && *aNth > 0", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth > 0"
")"); do { MOZ_CrashSequence(__null, 2318); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2319 if (MOZ_UNLIKELY(aFromIndex == 0)(__builtin_expect(!!(aFromIndex == 0), 0))) {
2320 return 0; // There are no named lines beyond the start of the explicit
2321 // grid.
2322 }
2323 --aFromIndex; // (shift aFromIndex so we can treat it as inclusive)
2324 int32_t nth = *aNth;
2325 // Implicit lines may be beyond the explicit grid so we match those
2326 // first if it's within the mTemplateLinesEnd..aFromIndex range.
2327 // aImplicitLines is presumed sorted.
2328 // For a subgrid we need to search to the end of the grid rather than
2329 // the end of the local name list, since ancestors might match.
2330 const uint32_t end = IsSubgridded() ? mClampMaxLine : mTemplateLinesEnd;
2331 for (auto implicitLine : Reversed(aImplicitLines)) {
2332 if (implicitLine <= end) {
2333 break;
2334 }
2335 if (implicitLine < aFromIndex) {
2336 if (--nth == 0) {
2337 return implicitLine;
2338 }
2339 }
2340 }
2341 for (uint32_t i = std::min(aFromIndex, end); i; --i) {
2342 if (Contains(i - 1, aName) || aImplicitLines.Contains(i)) {
2343 if (--nth == 0) {
2344 return i;
2345 }
2346 }
2347 }
2348 MOZ_ASSERT(nth > 0, "should have returned a valid line above already")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nth > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nth > 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nth > 0" " (" "should have returned a valid line above already"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 2348
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nth > 0" ") ("
"should have returned a valid line above already" ")"); do {
MOZ_CrashSequence(__null, 2348); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2349 *aNth = nth;
2350 return 0;
2351 }
2352
2353 // Return true if aName exists at aIndex in this map or any parent map.
2354 bool Contains(uint32_t aIndex, nsAtom* aName) const {
2355 const auto* map = this;
2356 while (true) {
2357 if (aIndex < map->mTemplateLinesEnd && map->HasNameAt(aIndex, aName)) {
2358 return true;
2359 }
2360 auto* parent = map->mParentLineNameMap;
2361 if (!parent) {
2362 return false;
2363 }
2364 uint32_t line = map->TranslateToParentMap(aIndex + 1);
2365 MOZ_ASSERT(line >= 1, "expected a 1-based line number")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(line >= 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(line >= 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("line >= 1" " ("
"expected a 1-based line number" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "line >= 1"
") (" "expected a 1-based line number" ")"); do { MOZ_CrashSequence
(__null, 2365); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2366 aIndex = line - 1;
2367 map = parent;
2368 }
2369 MOZ_ASSERT_UNREACHABLE("we always return from inside the loop above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"we always return from inside the loop above" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2369); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "we always return from inside the loop above"
")"); do { MOZ_CrashSequence(__null, 2369); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2370 }
2371
2372 static bool Contains(Span<const StyleCustomIdent> aNames, nsAtom* aName) {
2373 for (auto& name : aNames) {
2374 if (name.AsAtom() == aName) {
2375 return true;
2376 }
2377 }
2378 return false;
2379 }
2380
2381 // Return true if aName exists at aIndex in this map.
2382 bool HasNameAt(const uint32_t aIndex, nsAtom* const aName) const {
2383 const auto nameLists = GetLineNamesAt(aIndex);
2384 for (const NameList* nameList : nameLists) {
2385 if (Contains(nameList->AsSpan(), aName)) {
2386 return true;
2387 }
2388 }
2389 return false;
2390 }
2391
2392 // Get the line names at an index.
2393 // This accounts for auto repeat. The results may be spread over multiple name
2394 // lists returned in the array, which is done to avoid unneccessarily copying
2395 // the arrays to concatenate them.
2396 SmallPointerArray<const NameList> GetLineNamesAt(
2397 const uint32_t aIndex) const {
2398 SmallPointerArray<const NameList> names;
2399 // The index into mExpandedLineNames to use, if aIndex doesn't point to a
2400 // name inside of a auto repeat.
2401 uint32_t repeatAdjustedIndex = aIndex;
2402 // Note: For subgrid, |mHasRepeatAuto| is always false because we have
2403 // expanded it in the constructor of LineNameMap.
2404 if (mHasRepeatAuto) {
2405 // If the index is inside of the auto repeat, use the repeat line
2406 // names. Otherwise, if the index is past the end of the repeat it must
2407 // be adjusted to acount for the repeat tracks.
2408 // mExpandedLineNames has the first and last line name lists from the
2409 // repeat in it already, so we can just ignore aIndex == mRepeatAutoStart
2410 // and treat when aIndex == mRepeatAutoEnd the same as any line after the
2411 // the repeat.
2412 const uint32_t maxRepeatLine = mTrackAutoRepeatLineNames.Length() - 1;
2413 if (aIndex > mRepeatAutoStart && aIndex < mRepeatAutoEnd) {
2414 // The index is inside the auto repeat. Calculate the lines to use,
2415 // including the previous repetitions final names when we roll over
2416 // from one repetition to the next.
2417 const uint32_t repeatIndex =
2418 (aIndex - mRepeatAutoStart) % maxRepeatLine;
2419 if (repeatIndex == 0) {
2420 // The index is at the start of a new repetition. The start of the
2421 // first repetition is intentionally ignored above, so this will
2422 // consider both the end of the previous repetition and the start
2423 // the one that contains aIndex.
2424 names.AppendElement(&mTrackAutoRepeatLineNames[maxRepeatLine]);
2425 }
2426 names.AppendElement(&mTrackAutoRepeatLineNames[repeatIndex]);
2427 return names;
2428 }
2429 if (aIndex != mRepeatAutoStart && aIndex >= mRepeatAutoEnd) {
2430 // Adjust the index to account for the line names of the repeat.
2431 repeatAdjustedIndex -= mRepeatEndDelta;
2432 repeatAdjustedIndex += mTrackAutoRepeatLineNames.Length() - 2;
2433 }
2434 }
2435 MOZ_ASSERT(repeatAdjustedIndex < mExpandedLineNames.Length(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeatAdjustedIndex < mExpandedLineNames.Length()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(repeatAdjustedIndex < mExpandedLineNames.Length()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"repeatAdjustedIndex < mExpandedLineNames.Length()" " (" "Incorrect repeatedAdjustedIndex"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 2436
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatAdjustedIndex < mExpandedLineNames.Length()"
") (" "Incorrect repeatedAdjustedIndex" ")"); do { MOZ_CrashSequence
(__null, 2436); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2436 "Incorrect repeatedAdjustedIndex")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(repeatAdjustedIndex < mExpandedLineNames.Length()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(repeatAdjustedIndex < mExpandedLineNames.Length()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"repeatAdjustedIndex < mExpandedLineNames.Length()" " (" "Incorrect repeatedAdjustedIndex"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 2436
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatAdjustedIndex < mExpandedLineNames.Length()"
") (" "Incorrect repeatedAdjustedIndex" ")"); do { MOZ_CrashSequence
(__null, 2436); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2437 MOZ_ASSERT(names.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(names.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(names.IsEmpty()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("names.IsEmpty()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2437)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "names.IsEmpty()" ")"
); do { MOZ_CrashSequence(__null, 2437); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2438 // The index is not inside the repeat tracks, or no repeat tracks exist.
2439 const auto& nameLists = mExpandedLineNames[repeatAdjustedIndex];
2440 for (const NameList* nameList : nameLists) {
2441 names.AppendElement(nameList);
2442 }
2443 return names;
2444 }
2445
2446 // Translate a subgrid line (1-based) to a parent line (1-based).
2447 uint32_t TranslateToParentMap(uint32_t aLine) const {
2448 if (MOZ_LIKELY(mIsSameDirection)(__builtin_expect(!!(mIsSameDirection), 1))) {
2449 return aLine + mRange->mStart;
2450 }
2451 MOZ_ASSERT(mRange->mEnd + 1 >= aLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRange->mEnd + 1 >= aLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRange->mEnd + 1 >= aLine
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mRange->mEnd + 1 >= aLine", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRange->mEnd + 1 >= aLine"
")"); do { MOZ_CrashSequence(__null, 2451); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2452 return mRange->mEnd - (aLine - 1) + 1;
2453 }
2454
2455 /**
2456 * Return the 1-based line that match aName in 'grid-template-areas'
2457 * on the side aSide. Clamp the result to aMin..aMax but require
2458 * that some part of the area is inside for it to match.
2459 * Return zero if there is no match.
2460 */
2461 uint32_t FindNamedArea(nsAtom* aName, LogicalSide aSide, int32_t aMin,
2462 int32_t aMax) const {
2463 if (const NamedArea* area = FindNamedArea(aName)) {
2464 int32_t start = IsBlock(aSide) ? area->rows.start : area->columns.start;
2465 int32_t end = IsBlock(aSide) ? area->rows.end : area->columns.end;
2466 if (IsStart(aSide)) {
2467 if (start >= aMin) {
2468 if (start <= aMax) {
2469 return start;
2470 }
2471 } else if (end >= aMin) {
2472 return aMin;
2473 }
2474 } else {
2475 if (end <= aMax) {
2476 if (end >= aMin) {
2477 return end;
2478 }
2479 } else if (start <= aMax) {
2480 return aMax;
2481 }
2482 }
2483 }
2484 return 0; // no match
2485 }
2486
2487 /**
2488 * A convenience method to lookup a name in 'grid-template-areas'.
2489 * @return null if not found
2490 */
2491 const NamedArea* FindNamedArea(nsAtom* aName) const {
2492 if (mStylePosition->mGridTemplateAreas.IsNone()) {
2493 return nullptr;
2494 }
2495 const auto areas = mStylePosition->mGridTemplateAreas.AsAreas();
2496 for (const NamedArea& area : areas->areas.AsSpan()) {
2497 if (area.name.AsAtom() == aName) {
2498 return &area;
2499 }
2500 }
2501 return nullptr;
2502 }
2503
2504 // Some style data references, for easy access.
2505 const nsStylePosition* mStylePosition;
2506 const ImplicitNamedAreas* mAreas;
2507 // The expanded list of line-names. Each entry is usually a single NameList,
2508 // but can be multiple in the case where repeat() expands to something that
2509 // has a line name list at the end.
2510 nsTArray<SmallPointerArray<const NameList>> mExpandedLineNames;
2511 // The repeat(auto-fill/fit) track value, if any. (always empty for subgrid)
2512 Span<const StyleOwnedSlice<StyleCustomIdent>> mTrackAutoRepeatLineNames;
2513 // The index of the repeat(auto-fill/fit) track, or zero if there is none.
2514 uint32_t mRepeatAutoStart;
2515 // The index one past the end of the repeat(auto-fill/fit) tracks. Equal to
2516 // mRepeatAutoStart if there are no repeat(auto-fill/fit) tracks.
2517 uint32_t mRepeatAutoEnd;
2518 // The total number of repeat tracks minus 1.
2519 int32_t mRepeatEndDelta;
2520 // The end of the line name lists with repeat(auto-fill/fit) tracks accounted
2521 // for.
2522 uint32_t mTemplateLinesEnd;
2523
2524 // The parent line map, or null if this map isn't for a subgrid.
2525 const LineNameMap* mParentLineNameMap;
2526 // The subgrid's range, or null if this map isn't for a subgrid.
2527 const LineRange* mRange;
2528 // True if the subgrid/parent axes progresses in the same direction.
2529 const bool mIsSameDirection;
2530 // True if the subgrid and parent have orthogonal writing modes.
2531 const bool mIsOrthogonal;
2532
2533 // True if there is a specified repeat(auto-fill/fit) track.
2534 bool mHasRepeatAuto;
2535};
2536
2537struct CachedIntrinsicSizes;
2538
2539/**
2540 * State for the tracks in one dimension.
2541 */
2542struct nsGridContainerFrame::Tracks {
2543 explicit Tracks(LogicalAxis aAxis)
2544 : mContentBoxSize(NS_UNCONSTRAINEDSIZE),
2545 mGridGap(NS_UNCONSTRAINEDSIZE),
2546 mStateUnion(TrackSize::StateBits::eNone),
2547 mAxis(aAxis),
2548 mCanResolveLineRangeSize(false),
2549 mIsMasonry(false) {
2550 mBaselineSubtreeAlign[BaselineSharingGroup::First] = StyleAlignFlags::AUTO;
2551 mBaselineSubtreeAlign[BaselineSharingGroup::Last] = StyleAlignFlags::AUTO;
2552 }
2553
2554 void Initialize(const TrackSizingFunctions& aFunctions,
2555 const NonNegativeLengthPercentageOrNormal& aGridGap,
2556 uint32_t aNumTracks, nscoord aContentBoxSize);
2557
2558 /**
2559 * Return the union of the state bits for the tracks in aRange.
2560 */
2561 TrackSize::StateBits StateBitsForRange(const LineRange& aRange) const;
2562
2563 // Some data we collect for aligning baseline-aligned items.
2564 struct ItemBaselineData {
2565 uint32_t mBaselineTrack;
2566 nscoord mBaseline;
2567 nscoord mSize;
2568 GridItemInfo* mGridItem;
2569 static bool IsBaselineTrackLessThan(const ItemBaselineData& a,
2570 const ItemBaselineData& b) {
2571 return a.mBaselineTrack < b.mBaselineTrack;
2572 }
2573 };
2574
2575 /**
2576 * Calculate baseline offsets for the given set of items.
2577 * Helper for InitialzeItemBaselines.
2578 */
2579 void CalculateItemBaselines(nsTArray<ItemBaselineData>& aBaselineItems,
2580 BaselineSharingGroup aBaselineGroup);
2581
2582 /**
2583 * Initialize grid item baseline state and offsets.
2584 */
2585 void InitializeItemBaselines(GridReflowInput& aGridRI,
2586 nsTArray<GridItemInfo>& aGridItems);
2587
2588 /**
2589 * A masonry axis has four baseline alignment sets and each set can have
2590 * a first- and last-baseline alignment group, for a total of eight possible
2591 * baseline alignment groups, as follows:
2592 * set 1: the first item in each `start` or `stretch` grid track
2593 * set 2: the last item in each `start` grid track
2594 * set 3: the last item in each `end` or `stretch` grid track
2595 * set 4: the first item in each `end` grid track
2596 * (`start`/`end`/`stretch` refers to the relevant `align/justify-tracks`
2597 * value of the (grid-axis) start track for the item) Baseline-alignment for
2598 * set 1 and 2 always adjusts the item's padding or margin on the start side,
2599 * and set 3 and 4 on the end side, for both first- and last-baseline groups
2600 * in the set. (This is similar to regular grid which always adjusts
2601 * first-baseline groups on the start side and last-baseline groups on the
2602 * end-side. The crux is that those groups are always aligned to the track's
2603 * start/end side respectively.)
2604 */
2605 struct BaselineAlignmentSet {
2606 bool MatchTrackAlignment(StyleAlignFlags aTrackAlignment) const {
2607 if (mTrackAlignmentSet == BaselineAlignmentSet::StartStretch) {
2608 return aTrackAlignment == StyleAlignFlags::START ||
2609 (aTrackAlignment == StyleAlignFlags::STRETCH &&
2610 mItemSet == BaselineAlignmentSet::FirstItems);
2611 }
2612 return aTrackAlignment == StyleAlignFlags::END ||
2613 (aTrackAlignment == StyleAlignFlags::STRETCH &&
2614 mItemSet == BaselineAlignmentSet::LastItems);
2615 }
2616
2617 enum ItemSet { FirstItems, LastItems };
2618 ItemSet mItemSet = FirstItems;
2619 enum TrackAlignmentSet { StartStretch, EndStretch };
2620 TrackAlignmentSet mTrackAlignmentSet = StartStretch;
2621 };
2622 void InitializeItemBaselinesInMasonryAxis(
2623 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
2624 BaselineAlignmentSet aSet, const nsSize& aContainerSize,
2625 nsTArray<nscoord>& aTrackSizes,
2626 nsTArray<ItemBaselineData>& aFirstBaselineItems,
2627 nsTArray<ItemBaselineData>& aLastBaselineItems);
2628
2629 /**
2630 * Apply the additional alignment needed to align the baseline-aligned subtree
2631 * the item belongs to within its baseline track.
2632 */
2633 void AlignBaselineSubtree(const GridItemInfo& aGridItem) const;
2634
2635 static TrackSize::StateBits SelectorForPhase(TrackSizingPhase aPhase,
2636 SizingConstraint aConstraint) {
2637 switch (aPhase) {
2638 case TrackSizingPhase::IntrinsicMinimums:
2639 return TrackSize::eIntrinsicMinSizing;
2640 case TrackSizingPhase::ContentBasedMinimums:
2641 return aConstraint == SizingConstraint::MinContent
2642 ? TrackSize::eIntrinsicMinSizing
2643 : TrackSize::eMinOrMaxContentMinSizing;
2644 case TrackSizingPhase::MaxContentMinimums:
2645 return aConstraint == SizingConstraint::MaxContent
2646 ? (TrackSize::eMaxContentMinSizing |
2647 TrackSize::eAutoMinSizing)
2648 : TrackSize::eMaxContentMinSizing;
2649 case TrackSizingPhase::IntrinsicMaximums:
2650 return TrackSize::eIntrinsicMaxSizing;
2651 case TrackSizingPhase::MaxContentMaximums:
2652 return TrackSize::eAutoOrMaxContentMaxSizing;
2653 }
2654 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase")do { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected phase" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2654); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 2654); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); __builtin_unreachable(); } while (
false)
;
2655 }
2656
2657 // Some data we collect on each item that spans more than one track for step 3
2658 // and 4 of the Track Sizing Algorithm in ResolveIntrinsicSize below.
2659 // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
2660 struct SpanningItemData final {
2661 uint32_t mSpan;
2662 TrackSize::StateBits mState;
2663 LineRange mLineRange;
2664 EnumeratedArray<GridIntrinsicSizeType, nscoord> mSizes;
2665 nsIFrame* mFrame;
2666
2667 static bool IsSpanLessThan(const SpanningItemData& a,
2668 const SpanningItemData& b) {
2669 return a.mSpan < b.mSpan;
2670 }
2671
2672 nscoord SizeContributionForPhase(TrackSizingPhase aPhase) const {
2673 return mSizes[SizeTypeForPhase(aPhase)];
2674 }
2675
2676#ifdef DEBUG1
2677 void Dump() const {
2678 printf(
2679 "SpanningItemData { mSpan: %d, mState: %d, mLineRange: (%d, %d), "
2680 "mSizes: {MinContribution: %d, MinContentContribution: %d, "
2681 "MaxContentContribution: %d}, mFrame: %p\n",
2682 mSpan, mState, mLineRange.mStart, mLineRange.mEnd,
2683 mSizes[GridIntrinsicSizeType::MinContribution],
2684 mSizes[GridIntrinsicSizeType::MinContentContribution],
2685 mSizes[GridIntrinsicSizeType::MaxContentContribution], mFrame);
2686 }
2687#endif
2688 };
2689
2690 using FitContentClamper =
2691 std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
2692
2693 // Helper method for ResolveIntrinsicSize.
2694 bool GrowSizeForSpanningItems(
2695 TrackSizingStep aStep, TrackSizingPhase aPhase,
2696 nsTArray<SpanningItemData>::iterator aIter,
2697 nsTArray<SpanningItemData>::iterator aIterEnd,
2698 nsTArray<uint32_t>& aTracks, TrackPlan& aTrackPlan, ItemPlan& aItemPlan,
2699 SizingConstraint aConstraint, bool aIsGridIntrinsicSizing,
2700 const TrackSizingFunctions& aFunctions,
2701 const FitContentClamper& aFitContentClamper = nullptr,
2702 bool aNeedInfinitelyGrowableFlag = false);
2703
2704 // Helper method for calculating CachedIntrinsicSizes.mMinSizeClamp.
2705 //
2706 // The caller should set ItemState::eClampMarginBoxMinSize on the
2707 // corresponding grid item if this returns something.
2708 Maybe<nscoord> ComputeMinSizeClamp(const TrackSizingFunctions& aFunctions,
2709 nscoord aPercentageBasis,
2710 const LineRange& aLineRange) const {
2711 return ComputeMinSizeClamp(aFunctions, aPercentageBasis, aLineRange,
2712 StateBitsForRange(aLineRange));
2713 }
2714
2715 // More efficient version of ComputeMinSizeClamp if the caller has already
2716 // computed the state bits for this line range.
2717 Maybe<nscoord> ComputeMinSizeClamp(const TrackSizingFunctions& aFunctions,
2718 nscoord aPercentageBasis,
2719 const LineRange& aLineRange,
2720 const TrackSize::StateBits aState) const;
2721
2722 /**
2723 * Resolve Intrinsic Track Sizes.
2724 * https://drafts.csswg.org/css-grid-2/#algo-content
2725 */
2726 void ResolveIntrinsicSize(GridReflowInput& aGridRI,
2727 nsTArray<GridItemInfo>& aGridItems,
2728 const TrackSizingFunctions& aFunctions,
2729 LineRange GridArea::* aRange,
2730 nscoord aPercentageBasis,
2731 SizingConstraint aConstraint);
2732
2733 /**
2734 * Helper for ResolveIntrinsicSize. It implements "Resolve Intrinsic Track
2735 * Sizes" step 2: "Size tracks to fit non-spanning items" in the spec.
2736 * https://drafts.csswg.org/css-grid-2/#algo-single-span-items
2737 */
2738 void ResolveIntrinsicSizeForNonSpanningItems(
2739 GridReflowInput& aGridRI, const TrackSizingFunctions& aFunctions,
2740 nscoord aPercentageBasis, SizingConstraint aConstraint,
2741 const LineRange& aRange, const GridItemInfo& aGridItem);
2742
2743 // Helper method that returns the track size to use in §12.5.1.2
2744 // https://drafts.csswg.org/css-grid-2/#extra-space
2745 static nscoord StartSizeInDistribution(TrackSizingPhase aPhase,
2746 const TrackSize& aSize) {
2747 switch (aPhase) {
2748 case TrackSizingPhase::IntrinsicMinimums:
2749 case TrackSizingPhase::ContentBasedMinimums:
2750 case TrackSizingPhase::MaxContentMinimums:
2751 return aSize.mBase;
2752 case TrackSizingPhase::IntrinsicMaximums:
2753 case TrackSizingPhase::MaxContentMaximums:
2754 if (aSize.mLimit == NS_UNCONSTRAINEDSIZE) {
2755 return aSize.mBase;
2756 }
2757 return aSize.mLimit;
2758 }
2759 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase")do { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected phase" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 2759); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); __builtin_unreachable(); } while (
false)
;
2760 }
2761
2762 /**
2763 * Collect the tracks which are growable (matching the sizing step/phase
2764 * and sizing constraint) into aGrowableTracks, and return the amount of
2765 * space that can be used to grow those tracks. This method implements
2766 * CSS Grid 2 §12.5.1.2.
2767 * https://drafts.csswg.org/css-grid-2/#extra-space
2768 */
2769 nscoord CollectGrowable(TrackSizingStep aStep, TrackSizingPhase aPhase,
2770 nscoord aAvailableSpace, const LineRange& aRange,
2771 SizingConstraint aConstraint,
2772 nsTArray<uint32_t>& aGrowableTracks) const {
2773 MOZ_ASSERT(aAvailableSpace > 0, "why call me?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAvailableSpace > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAvailableSpace > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aAvailableSpace > 0"
" (" "why call me?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2773); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0"
") (" "why call me?" ")"); do { MOZ_CrashSequence(__null, 2773
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2774 nscoord space = aAvailableSpace - mGridGap * (aRange.Extent() - 1);
2775 const TrackSize::StateBits selector = SelectorForPhase(aPhase, aConstraint);
2776 for (auto i : aRange.Range()) {
2777 const TrackSize& sz = mSizes[i];
2778 space -= StartSizeInDistribution(aPhase, sz);
2779 if (space <= 0) {
2780 return 0;
2781 }
2782 // Only flex tracks can be modified during step 4.
2783 if (aStep == TrackSizingStep::Flex &&
2784 !(sz.mState & TrackSize::eFlexMaxSizing)) {
2785 continue;
2786 }
2787 if (sz.mState & selector) {
2788 aGrowableTracks.AppendElement(i);
2789 }
2790 }
2791 return aGrowableTracks.IsEmpty() ? 0 : space;
2792 }
2793
2794 void CopyPlanToSize(TrackSizingPhase aPhase, const TrackPlan& aTrackPlan,
2795 bool aNeedInfinitelyGrowableFlag) {
2796 MOZ_ASSERT(aTrackPlan.Length() == mSizes.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrackPlan.Length() == mSizes.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aTrackPlan.Length() == mSizes.Length()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTrackPlan.Length() == mSizes.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2796)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrackPlan.Length() == mSizes.Length()"
")"); do { MOZ_CrashSequence(__null, 2796); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2797 auto plan = aTrackPlan.begin();
2798 auto sz = mSizes.begin();
2799 for (; plan != aTrackPlan.end() && sz != mSizes.end(); plan++, sz++) {
2800 MOZ_ASSERT(plan->mBase >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(plan->mBase >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(plan->mBase >= 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("plan->mBase >= 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2800)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "plan->mBase >= 0"
")"); do { MOZ_CrashSequence(__null, 2800); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2801 switch (aPhase) {
2802 case TrackSizingPhase::IntrinsicMinimums:
2803 case TrackSizingPhase::ContentBasedMinimums:
2804 case TrackSizingPhase::MaxContentMinimums:
2805 sz->mBase = plan->mBase;
2806 break;
2807 case TrackSizingPhase::IntrinsicMaximums:
2808 if (plan->mState & TrackSize::eModified) {
2809 if (sz->mLimit == NS_UNCONSTRAINEDSIZE &&
2810 aNeedInfinitelyGrowableFlag) {
2811 sz->mState |= TrackSize::eInfinitelyGrowable;
2812 }
2813 sz->mLimit = plan->mBase;
2814 }
2815 break;
2816 case TrackSizingPhase::MaxContentMaximums:
2817 if (plan->mState & TrackSize::eModified) {
2818 sz->mLimit = plan->mBase;
2819 }
2820 sz->mState &= ~TrackSize::eInfinitelyGrowable;
2821 break;
2822 }
2823 }
2824 }
2825
2826 /**
2827 * Distribute aAvailableSpace to the planned base size for aGrowableTracks
2828 * up to their limits, then distribute the remaining space beyond the limits.
2829 */
2830 void DistributeToTrackSizes(
2831 TrackSizingStep aStep, TrackSizingPhase aPhase, nscoord aAvailableSpace,
2832 TrackPlan& aTrackPlan, ItemPlan& aItemPlan,
2833 const nsTArray<uint32_t>& aGrowableTracks, SizingConstraint aConstraint,
2834 const TrackSizingFunctions& aFunctions,
2835 const FitContentClamper& aFitContentClamper) const {
2836 aItemPlan.Initialize(aPhase, aGrowableTracks, *this);
2837 nscoord space = aAvailableSpace;
2838 if (aStep == TrackSizingStep::Flex) {
2839 space = aTrackPlan.DistributeToFlexTrackSizes(space, aGrowableTracks,
2840 aFunctions, *this);
2841 } else {
2842 space = aItemPlan.GrowTracksToLimit(space, aGrowableTracks,
2843 aFitContentClamper);
2844 }
2845
2846 if (space > 0) {
2847 uint32_t numGrowable =
2848 aItemPlan.MarkExcludedTracks(aPhase, aGrowableTracks, aConstraint);
2849 aItemPlan.GrowSelectedTracksUnlimited(space, aGrowableTracks, numGrowable,
2850 aFitContentClamper);
2851 }
2852
2853 for (uint32_t track : aGrowableTracks) {
2854 nscoord& plannedSize = aTrackPlan[track].mBase;
2855 nscoord itemIncurredSize = aItemPlan[track].mBase;
2856 if (plannedSize < itemIncurredSize) {
2857 plannedSize = itemIncurredSize;
2858 }
2859 }
2860 }
2861
2862 /**
2863 * Distribute aAvailableSize to the tracks. This implements 12.6 at:
2864 * https://drafts.csswg.org/css-grid-2/#algo-grow-tracks
2865 */
2866 void DistributeFreeSpace(nscoord aAvailableSize) {
2867 const uint32_t numTracks = mSizes.Length();
2868 if (MOZ_UNLIKELY(numTracks == 0 || aAvailableSize <= 0)(__builtin_expect(!!(numTracks == 0 || aAvailableSize <= 0
), 0))
) {
2869 return;
2870 }
2871 if (aAvailableSize == NS_UNCONSTRAINEDSIZE) {
2872 for (TrackSize& sz : mSizes) {
2873 sz.mBase = sz.mLimit;
2874 }
2875 } else {
2876 // Compute free space and count growable tracks.
2877 nscoord space = aAvailableSize;
2878 uint32_t numGrowable = numTracks;
2879 for (const TrackSize& sz : mSizes) {
2880 space -= sz.mBase;
2881 MOZ_ASSERT(sz.mBase <= sz.mLimit)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sz.mBase <= sz.mLimit)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sz.mBase <= sz.mLimit))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("sz.mBase <= sz.mLimit"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 2881)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.mBase <= sz.mLimit"
")"); do { MOZ_CrashSequence(__null, 2881); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2882 if (sz.mBase == sz.mLimit) {
2883 --numGrowable;
2884 }
2885 }
2886 // Distribute the free space evenly to the growable tracks. If not exactly
2887 // divisable the remainder is added to the leading tracks.
2888 while (space > 0 && numGrowable) {
2889 nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
2890 for (TrackSize& sz : mSizes) {
2891 if (sz.mBase == sz.mLimit) {
2892 continue;
2893 }
2894 nscoord newBase = sz.mBase + spacePerTrack;
2895 if (newBase >= sz.mLimit) {
2896 space -= sz.mLimit - sz.mBase;
2897 sz.mBase = sz.mLimit;
2898 --numGrowable;
2899 } else {
2900 space -= spacePerTrack;
2901 sz.mBase = newBase;
2902 }
2903 if (space <= 0) {
2904 break;
2905 }
2906 }
2907 }
2908 }
2909 }
2910
2911 /**
2912 * Implements "12.7.1. Find the Size of an 'fr'".
2913 * https://drafts.csswg.org/css-grid-2/#algo-find-fr-size
2914 * (The returned value is a 'nscoord' divided by a factor - a floating type
2915 * is used to avoid intermediary rounding errors.)
2916 */
2917 float FindFrUnitSize(const LineRange& aRange,
2918 const nsTArray<uint32_t>& aFlexTracks,
2919 const TrackSizingFunctions& aFunctions,
2920 nscoord aSpaceToFill) const;
2921
2922 /**
2923 * Implements the "find the used flex fraction" part of StretchFlexibleTracks.
2924 * (The returned value is a 'nscoord' divided by a factor - a floating type
2925 * is used to avoid intermediary rounding errors.)
2926 */
2927 float FindUsedFlexFraction(GridReflowInput& aGridRI,
2928 const nsTArray<GridItemInfo>& aGridItems,
2929 const nsTArray<uint32_t>& aFlexTracks,
2930 const TrackSizingFunctions& aFunctions,
2931 nscoord aAvailableSize) const;
2932
2933 /**
2934 * Implements "12.7. Expand Flexible Tracks"
2935 * https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
2936 */
2937 void StretchFlexibleTracks(GridReflowInput& aGridRI,
2938 const nsTArray<GridItemInfo>& aGridItems,
2939 const TrackSizingFunctions& aFunctions,
2940 nscoord aAvailableSize);
2941
2942 /**
2943 * Implements "12.3. Track Sizing Algorithm"
2944 * https://drafts.csswg.org/css-grid-2/#algo-track-sizing
2945 */
2946 void CalculateSizes(GridReflowInput& aGridRI,
2947 nsTArray<GridItemInfo>& aGridItems,
2948 const TrackSizingFunctions& aFunctions,
2949 nscoord aContentBoxSize, LineRange GridArea::* aRange,
2950 SizingConstraint aConstraint);
2951
2952 /**
2953 * Apply 'align/justify-content', whichever is relevant for this axis.
2954 * https://drafts.csswg.org/css-align-3/#propdef-align-content
2955 */
2956 void AlignJustifyContent(const nsStylePosition* aStyle,
2957 StyleContentDistribution aAligmentStyleValue,
2958 WritingMode aWM, nscoord aContentBoxSize,
2959 bool aIsSubgridded);
2960
2961 /**
2962 * Return the sum of the resolved track and gap sizes (without any packing
2963 * space introduced by align-content or justify-content.
2964 */
2965 nscoord TotalTrackSizeWithoutAlignment(
2966 const nsGridContainerFrame* aGridContainerFrame) const;
2967
2968 nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const {
2969 if (MOZ_UNLIKELY(mSizes.IsEmpty())(__builtin_expect(!!(mSizes.IsEmpty()), 0))) {
2970 // https://drafts.csswg.org/css-grid-2/#grid-definition
2971 // "... the explicit grid still contains one grid line in each axis."
2972 MOZ_ASSERT(aLine == 0, "We should only resolve line 1 in an empty grid")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLine == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLine == 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aLine == 0" " (" "We should only resolve line 1 in an empty grid"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 2972
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLine == 0" ") ("
"We should only resolve line 1 in an empty grid" ")"); do { MOZ_CrashSequence
(__null, 2972); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2973 return nscoord(0);
2974 }
2975 MOZ_ASSERT(aLine <= mSizes.Length(), "mSizes is too small")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLine <= mSizes.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLine <= mSizes.Length())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aLine <= mSizes.Length()"
" (" "mSizes is too small" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 2975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLine <= mSizes.Length()"
") (" "mSizes is too small" ")"); do { MOZ_CrashSequence(__null
, 2975); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2976 if (aSide == GridLineSide::BeforeGridGap) {
2977 if (aLine == 0) {
2978 return nscoord(0);
2979 }
2980 const TrackSize& sz = mSizes[aLine - 1];
2981 return sz.mPosition + sz.mBase;
2982 }
2983 if (aLine == mSizes.Length()) {
2984 return mContentBoxSize;
2985 }
2986 return mSizes[aLine].mPosition;
2987 }
2988
2989 nscoord SumOfGridTracksAndGaps() const {
2990 return SumOfGridTracks() + SumOfGridGaps();
2991 }
2992
2993 nscoord SumOfGridTracks() const {
2994 nscoord result = 0;
2995 for (const TrackSize& size : mSizes) {
2996 result += size.mBase;
2997 }
2998 return result;
2999 }
3000
3001 nscoord SumOfGridGaps() const {
3002 auto len = mSizes.Length();
3003 return MOZ_LIKELY(len > 1)(__builtin_expect(!!(len > 1), 1)) ? (len - 1) * mGridGap : 0;
3004 }
3005
3006 /**
3007 * Break before aRow, i.e. set the eBreakBefore flag on aRow and set the grid
3008 * gap before aRow to zero (and shift all rows after it by the removed gap).
3009 */
3010 void BreakBeforeRow(uint32_t aRow) {
3011 MOZ_ASSERT(mAxis == LogicalAxis::Block,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAxis == LogicalAxis::Block)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAxis == LogicalAxis::Block)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mAxis == LogicalAxis::Block"
" (" "Should only be fragmenting in the block axis (between rows)"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3012
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3012); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3012 "Should only be fragmenting in the block axis (between rows)")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAxis == LogicalAxis::Block)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAxis == LogicalAxis::Block)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mAxis == LogicalAxis::Block"
" (" "Should only be fragmenting in the block axis (between rows)"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3012
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3012); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3013 nscoord prevRowEndPos = 0;
3014 if (aRow != 0) {
3015 auto& prevSz = mSizes[aRow - 1];
3016 prevRowEndPos = prevSz.mPosition + prevSz.mBase;
3017 }
3018 auto& sz = mSizes[aRow];
3019 const nscoord gap = sz.mPosition - prevRowEndPos;
3020 sz.mState |= TrackSize::eBreakBefore;
3021 if (gap != 0) {
3022 for (uint32_t i = aRow, len = mSizes.Length(); i < len; ++i) {
3023 mSizes[i].mPosition -= gap;
3024 }
3025 }
3026 }
3027
3028 /**
3029 * Set the size of aRow to aSize and adjust the position of all rows after it.
3030 */
3031 void ResizeRow(uint32_t aRow, nscoord aNewSize) {
3032 MOZ_ASSERT(mAxis == LogicalAxis::Block,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAxis == LogicalAxis::Block)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAxis == LogicalAxis::Block)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mAxis == LogicalAxis::Block"
" (" "Should only be fragmenting in the block axis (between rows)"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3033 "Should only be fragmenting in the block axis (between rows)")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAxis == LogicalAxis::Block)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAxis == LogicalAxis::Block)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mAxis == LogicalAxis::Block"
" (" "Should only be fragmenting in the block axis (between rows)"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3034 MOZ_ASSERT(aNewSize >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewSize >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewSize >= 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aNewSize >= 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3034)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewSize >= 0" ")"
); do { MOZ_CrashSequence(__null, 3034); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3035 auto& sz = mSizes[aRow];
3036 nscoord delta = aNewSize - sz.mBase;
3037 NS_WARNING_ASSERTION(delta != nscoord(0), "Useless call to ResizeRow")do { if (!(delta != nscoord(0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "Useless call to ResizeRow", "delta != nscoord(0)", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3037); } } while (false)
;
3038 sz.mBase = aNewSize;
3039 const uint32_t numRows = mSizes.Length();
3040 for (uint32_t r = aRow + 1; r < numRows; ++r) {
3041 mSizes[r].mPosition += delta;
3042 }
3043 }
3044
3045 nscoord ResolveSize(const LineRange& aRange) const {
3046 MOZ_ASSERT(mCanResolveLineRangeSize)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanResolveLineRangeSize)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCanResolveLineRangeSize))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mCanResolveLineRangeSize"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3046)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCanResolveLineRangeSize"
")"); do { MOZ_CrashSequence(__null, 3046); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3047 MOZ_ASSERT(aRange.Extent() > 0, "grid items cover at least one track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRange.Extent() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRange.Extent() > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aRange.Extent() > 0"
" (" "grid items cover at least one track" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRange.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 3047); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3048 return aRange.ToLength(mSizes);
3049 }
3050
3051 // Returns the offset for the given track and baseline sharing group, or the
3052 // opposite group in the same track if unavailable.
3053 // Returns `Nothing()` if neither is set.
3054 Maybe<nscoord> GetBaseline(uint32_t aTrack,
3055 BaselineSharingGroup aBaselineSharingGroup) const {
3056 if (aTrack >= mBaselines.Length()) {
3057 return {};
3058 }
3059
3060 const auto& trackBaselines = mBaselines[aTrack];
3061 if (auto b = trackBaselines[aBaselineSharingGroup]) {
3062 return b;
3063 }
3064 if (auto b = trackBaselines[GetOppositeBaselineSharingGroup(
3065 aBaselineSharingGroup)]) {
3066 // First and last baseline offsets are from the start or end edges
3067 // respectively and requesting the opposite baseline requires adjusting
3068 // the offset to the opposite side.
3069 return Some(mSizes[aTrack].mBase - *b);
3070 }
3071
3072 return {};
3073 }
3074
3075#ifdef DEBUG1
3076 void Dump() const;
3077#endif
3078
3079 TrackPlan mSizes;
3080 nscoord mContentBoxSize;
3081 nscoord mGridGap;
3082
3083 // Stores per-track baselines for grid baseline calculations.
3084 CopyableTArray<PerBaseline<Maybe<nscoord>>> mBaselines;
3085
3086 // The union of the track min/max-sizing state bits in this axis.
3087 TrackSize::StateBits mStateUnion;
3088 LogicalAxis mAxis;
3089 // Used for aligning a baseline-aligned subtree of items. The only possible
3090 // values are StyleAlignFlags::{START,END,CENTER,AUTO}. AUTO means there are
3091 // no baseline-aligned items in any track in that axis.
3092 // There is one alignment value for each BaselineSharingGroup.
3093 PerBaseline<StyleAlignFlags> mBaselineSubtreeAlign;
3094 // True if track positions and sizes are final in this axis.
3095 bool mCanResolveLineRangeSize;
3096 // True if this axis has masonry layout.
3097 bool mIsMasonry;
3098};
3099
3100#ifdef DEBUG1
3101void nsGridContainerFrame::Tracks::Dump() const {
3102 const size_t numTracks = mSizes.Length();
3103 const char* trackName = mAxis == LogicalAxis::Inline ? "column" : "row";
3104
3105 auto BaselineToStr = [](Maybe<nscoord> aBaseline) {
3106 if (!aBaseline) {
3107 return std::string("not set");
3108 }
3109
3110 return std::to_string(*aBaseline);
3111 };
3112
3113 auto CoordToStr = [](nscoord aCoord) {
3114 return aCoord == NS_UNCONSTRAINEDSIZE ? std::string("unconstrained")
3115 : std::to_string(aCoord);
3116 };
3117
3118 fmt::print("{} {} {}{}, track union bits: ", numTracks,
3119 mIsMasonry ? "masonry" : "grid", trackName,
3120 numTracks > 1 ? "s" : "");
3121 TrackSize::DumpStateBits(mStateUnion);
3122 printf("\n");
3123
3124 for (uint32_t i = 0; i < numTracks; ++i) {
3125 fmt::print(" {} {}: ", trackName, i);
3126 mSizes[i].Dump();
3127 printf("\n");
3128 }
3129
3130 fmt::println(" first baseline: {}, last baseline: {}",
3131 BaselineToStr(GetBaseline(0, BaselineSharingGroup::First)),
3132 BaselineToStr(GetBaseline(mBaselines.Length() - 1,
3133 BaselineSharingGroup::Last)));
3134 fmt::println(" {} gap: {}, content-box {}-size: {}", trackName,
3135 CoordToStr(mGridGap),
3136 mAxis == LogicalAxis::Inline ? "inline" : "block",
3137 CoordToStr(mContentBoxSize));
3138}
3139#endif
3140
3141/**
3142 * Grid data shared by all continuations, owned by the first-in-flow.
3143 * The data is initialized from the first-in-flow's GridReflowInput at
3144 * the end of its reflow. Fragmentation will modify mRows.mSizes -
3145 * the mPosition to remove the row gap at the break boundary, the mState
3146 * by setting the eBreakBefore flag, and mBase is modified when we decide
3147 * to grow a row. mOriginalRowData is setup by the first-in-flow and
3148 * not modified after that. It's used for undoing the changes to mRows.
3149 * mCols, mGridItems, mAbsPosItems are used for initializing the grid
3150 * reflow input for continuations, see GridReflowInput::Initialize below.
3151 */
3152struct nsGridContainerFrame::SharedGridData {
3153 SharedGridData()
3154 : mCols(LogicalAxis::Inline),
3155 mRows(LogicalAxis::Block),
3156 mGenerateComputedGridInfo(false) {}
3157 Tracks mCols;
3158 Tracks mRows;
3159 struct RowData {
3160 nscoord mBase; // the original track size
3161 nscoord mGap; // the original gap before a track
3162 };
3163 nsTArray<RowData> mOriginalRowData;
3164 nsTArray<GridItemInfo> mGridItems;
3165 nsTArray<GridItemInfo> mAbsPosItems;
3166 bool mGenerateComputedGridInfo;
3167
3168 /**
3169 * Only set on the first-in-flow. Continuations will Initialize() their
3170 * GridReflowInput from it.
3171 */
3172 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, SharedGridData)static const mozilla::FramePropertyDescriptor<SharedGridData
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<SharedGridData>::NewWithDestructor<DeleteValue>(
); return &descriptor; }
3173};
3174
3175struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
3176 GridReflowInput(nsGridContainerFrame* aFrame, const ReflowInput& aRI)
3177 : GridReflowInput(aFrame, *aRI.mRenderingContext, &aRI,
3178 aRI.mStylePosition, aRI.GetWritingMode()) {}
3179 GridReflowInput(nsGridContainerFrame* aFrame, gfxContext& aRC)
3180 : GridReflowInput(aFrame, aRC, nullptr, aFrame->StylePosition(),
3181 aFrame->GetWritingMode()) {}
3182
3183 /**
3184 * Initialize our track sizes and grid item info using the shared
3185 * state from aGridContainerFrame first-in-flow.
3186 */
3187 void InitializeForContinuation(nsGridContainerFrame* aGridContainerFrame,
3188 nscoord aConsumedBSize) {
3189 MOZ_ASSERT(aGridContainerFrame->GetPrevInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridContainerFrame->GetPrevInFlow())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridContainerFrame->GetPrevInFlow()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGridContainerFrame->GetPrevInFlow()"
" (" "don't call this on the first-in-flow" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridContainerFrame->GetPrevInFlow()"
") (" "don't call this on the first-in-flow" ")"); do { MOZ_CrashSequence
(__null, 3190); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3190 "don't call this on the first-in-flow")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridContainerFrame->GetPrevInFlow())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridContainerFrame->GetPrevInFlow()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGridContainerFrame->GetPrevInFlow()"
" (" "don't call this on the first-in-flow" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridContainerFrame->GetPrevInFlow()"
") (" "don't call this on the first-in-flow" ")"); do { MOZ_CrashSequence
(__null, 3190); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3191 MOZ_ASSERT(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()" " ("
"shouldn't have any item data yet" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()"
") (" "shouldn't have any item data yet" ")"); do { MOZ_CrashSequence
(__null, 3192); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3192 "shouldn't have any item data yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()" " ("
"shouldn't have any item data yet" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()"
") (" "shouldn't have any item data yet" ")"); do { MOZ_CrashSequence
(__null, 3192); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3193
3194 // Get the SharedGridData from the first-in-flow. Also calculate the number
3195 // of fragments before this so that we can figure out our start row below.
3196 uint32_t fragment = 0;
3197 nsIFrame* firstInFlow = aGridContainerFrame;
3198 for (auto pif = aGridContainerFrame->GetPrevInFlow(); pif;
3199 pif = pif->GetPrevInFlow()) {
3200 ++fragment;
3201 firstInFlow = pif;
3202 }
3203 mSharedGridData = firstInFlow->GetProperty(SharedGridData::Prop());
3204 MOZ_ASSERT(mSharedGridData, "first-in-flow must have SharedGridData")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSharedGridData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSharedGridData))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mSharedGridData"
" (" "first-in-flow must have SharedGridData" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSharedGridData"
") (" "first-in-flow must have SharedGridData" ")"); do { MOZ_CrashSequence
(__null, 3204); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3205
3206 // Find the start row for this fragment and undo breaks after that row
3207 // since the breaks might be different from the last reflow.
3208 auto& rowSizes = mSharedGridData->mRows.mSizes;
3209 const uint32_t numRows = rowSizes.Length();
3210 mStartRow = numRows;
3211 for (uint32_t row = 0, breakCount = 0; row < numRows; ++row) {
3212 if (rowSizes[row].mState & TrackSize::eBreakBefore) {
3213 if (fragment == ++breakCount) {
3214 mStartRow = row;
3215 mFragBStart = rowSizes[row].mPosition;
3216 // Restore the original size for |row| and grid gaps / state after it.
3217 const auto& origRowData = mSharedGridData->mOriginalRowData;
3218 rowSizes[row].mBase = origRowData[row].mBase;
3219 nscoord prevEndPos = rowSizes[row].mPosition + rowSizes[row].mBase;
3220 while (++row < numRows) {
3221 auto& sz = rowSizes[row];
3222 const auto& orig = origRowData[row];
3223 sz.mPosition = prevEndPos + orig.mGap;
3224 sz.mBase = orig.mBase;
3225 sz.mState &= ~TrackSize::eBreakBefore;
3226 prevEndPos = sz.mPosition + sz.mBase;
3227 }
3228 break;
3229 }
3230 }
3231 }
3232 if (mStartRow == numRows || aGridContainerFrame->IsRowMasonry()) {
3233 // All of the grid's rows fit inside of previous grid-container fragments,
3234 // or it's a masonry axis.
3235 mFragBStart = aConsumedBSize;
3236 }
3237
3238 // Copy the shared track state.
3239 // XXX consider temporarily swapping the array elements instead and swapping
3240 // XXX them back after we're done reflowing, for better performance.
3241 // XXX (bug 1252002)
3242 mCols = mSharedGridData->mCols;
3243 mRows = mSharedGridData->mRows;
3244
3245 if (firstInFlow->GetProperty(UsedTrackSizes::Prop())) {
3246 auto* prop = aGridContainerFrame->GetOrCreateDeletableProperty(
3247 UsedTrackSizes::Prop());
3248 prop->mCanResolveLineRangeSize = {true, true};
3249 prop->mTrackPlans[LogicalAxis::Inline].Assign(mCols.mSizes);
3250 prop->mTrackPlans[LogicalAxis::Block].Assign(mRows.mSizes);
3251 }
3252
3253 // Copy item data from each child's first-in-flow data in mSharedGridData.
3254 // XXX NOTE: This is O(n^2) in the number of items. (bug 1252186)
3255 mIter.Reset();
3256 for (; !mIter.AtEnd(); mIter.Next()) {
3257 nsIFrame* child = *mIter;
3258 nsIFrame* childFirstInFlow = child->FirstInFlow();
3259 DebugOnly<size_t> len = mGridItems.Length();
3260 for (auto& itemInfo : mSharedGridData->mGridItems) {
3261 if (itemInfo.mFrame == childFirstInFlow) {
3262 auto item =
3263 mGridItems.AppendElement(GridItemInfo(child, itemInfo.mArea));
3264 // Copy the item's baseline data so that the item's last fragment can
3265 // do 'last baseline' alignment if necessary.
3266 item->mState[LogicalAxis::Block] |=
3267 itemInfo.mState[LogicalAxis::Block] & ItemState::eAllBaselineBits;
3268 item->mState[LogicalAxis::Inline] |=
3269 itemInfo.mState[LogicalAxis::Inline] &
3270 ItemState::eAllBaselineBits;
3271 item->mBaselineOffset[LogicalAxis::Block] =
3272 itemInfo.mBaselineOffset[LogicalAxis::Block];
3273 item->mBaselineOffset[LogicalAxis::Inline] =
3274 itemInfo.mBaselineOffset[LogicalAxis::Inline];
3275 item->mState[LogicalAxis::Block] |=
3276 itemInfo.mState[LogicalAxis::Block] & ItemState::eAutoPlacement;
3277 item->mState[LogicalAxis::Inline] |=
3278 itemInfo.mState[LogicalAxis::Inline] & ItemState::eAutoPlacement;
3279 break;
3280 }
3281 }
3282 MOZ_ASSERT(mGridItems.Length() == len + 1, "can't find GridItemInfo")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGridItems.Length() == len + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGridItems.Length() == len +
1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGridItems.Length() == len + 1" " (" "can't find GridItemInfo"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3282
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.Length() == len + 1"
") (" "can't find GridItemInfo" ")"); do { MOZ_CrashSequence
(__null, 3282); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3283 }
3284
3285 if (auto* absCB = aGridContainerFrame->GetAbsoluteContainingBlock()) {
3286 // Prepare absolute frames before constructing GridItemInfo.
3287 absCB->PrepareAbsoluteFrames(aGridContainerFrame);
3288 }
3289 // XXX NOTE: This is O(n^2) in the number of abs.pos. items. (bug 1252186)
3290 const nsFrameList& absPosChildren =
3291 aGridContainerFrame->GetChildList(FrameChildListID::Absolute);
3292 for (auto f : absPosChildren) {
3293 nsIFrame* childFirstInFlow = f->FirstInFlow();
3294 DebugOnly<size_t> len = mAbsPosItems.Length();
3295 for (auto& itemInfo : mSharedGridData->mAbsPosItems) {
3296 if (itemInfo.mFrame == childFirstInFlow) {
3297 mAbsPosItems.AppendElement(GridItemInfo(f, itemInfo.mArea));
3298 break;
3299 }
3300 }
3301 MOZ_ASSERT(mAbsPosItems.Length() == len + 1, "can't find GridItemInfo")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAbsPosItems.Length() == len + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAbsPosItems.Length() == len
+ 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mAbsPosItems.Length() == len + 1" " (" "can't find GridItemInfo"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3301
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAbsPosItems.Length() == len + 1"
") (" "can't find GridItemInfo" ")"); do { MOZ_CrashSequence
(__null, 3301); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3302 }
3303
3304 // Copy in the computed grid info state bit
3305 if (mSharedGridData->mGenerateComputedGridInfo) {
3306 aGridContainerFrame->AddStateBits(NS_STATE_GRID_COMPUTED_INFO);
3307 }
3308 }
3309
3310 /**
3311 * Calculate our track sizes in the given axis.
3312 */
3313 void CalculateTrackSizesForAxis(LogicalAxis aAxis, const Grid& aGrid,
3314 nscoord aCBSize,
3315 SizingConstraint aConstraint);
3316
3317 /**
3318 * Invalidate track sizes for the given axis by clearing track sizing bits for
3319 * all grid items and mark the track sizes and positions as needing recompute.
3320 *
3321 * This helper must be called before invoking CalculateTrackSizesForAxis()
3322 * again in aAxis; otherwise, assertions will fire.
3323 */
3324 void InvalidateTrackSizesForAxis(LogicalAxis aAxis);
3325
3326 /**
3327 * Return the percentage basis for a grid item in its writing-mode based on
3328 * track sizes and the grid area occupied by the grid item.
3329 *
3330 * @param aAxis the axis we're currently calculating track sizes for
3331 */
3332 LogicalSize PercentageBasisFor(LogicalAxis aAxis,
3333 const GridItemInfo& aGridItem) const;
3334
3335 /**
3336 * Return the containing block for a grid item occupying aArea.
3337 */
3338 LogicalRect ContainingBlockFor(const GridArea& aArea) const;
3339
3340 /**
3341 * Return the containing block for an abs.pos. grid item occupying aArea.
3342 * Any 'auto' lines in the grid area will be aligned with grid container
3343 * containing block on that side.
3344 * @param aGridOrigin the origin of the grid
3345 * @param aGridCB the grid container containing block (its padding area)
3346 */
3347 LogicalRect ContainingBlockForAbsPos(const GridArea& aArea,
3348 const LogicalPoint& aGridOrigin,
3349 const LogicalRect& aGridCB) const;
3350
3351 /**
3352 * Apply `align/justify-content` alignment in our masonry axis.
3353 * This aligns the "masonry box" within our content box size.
3354 */
3355 void AlignJustifyContentInMasonryAxis(nscoord aMasonryBoxSize,
3356 nscoord aContentBoxSize);
3357 /**
3358 * Apply `align/justify-tracks` alignment in our masonry axis.
3359 */
3360 void AlignJustifyTracksInMasonryAxis(const LogicalSize& aContentSize,
3361 const nsSize& aContainerSize);
3362
3363 // Recursive helper for CollectSubgridItemsForAxis().
3364 static void CollectSubgridItemsForAxisHelper(
3365 LogicalAxis aAxis, WritingMode aContainerWM,
3366 const LineRange& aRangeInAxis, const LineRange& aRangeInOppositeAxis,
3367 const GridItemInfo& aItem, const nsTArray<GridItemInfo>& aItems,
3368 nsTArray<GridItemInfo>& aResult) {
3369 const auto oppositeAxis = GetOrthogonalAxis(aAxis);
3370 bool itemIsSubgridInOppositeAxis = aItem.IsSubgrid(oppositeAxis);
3371 auto subgridWM = aItem.mFrame->GetWritingMode();
3372 bool isOrthogonal = subgridWM.IsOrthogonalTo(aContainerWM);
3373 bool isSameDirInAxis =
3374 subgridWM.ParallelAxisStartsOnSameSide(aAxis, aContainerWM);
3375 bool isSameDirInOppositeAxis =
3376 subgridWM.ParallelAxisStartsOnSameSide(oppositeAxis, aContainerWM);
3377 if (isOrthogonal) {
3378 // We'll Transpose the area below so these needs to be transposed as well.
3379 std::swap(isSameDirInAxis, isSameDirInOppositeAxis);
3380 }
3381 uint32_t offsetInAxis = aRangeInAxis.mStart;
3382 uint32_t gridEndInAxis = aRangeInAxis.Extent();
3383 uint32_t offsetInOppositeAxis = aRangeInOppositeAxis.mStart;
3384 uint32_t gridEndInOppositeAxis = aRangeInOppositeAxis.Extent();
3385 for (const auto& subgridItem : aItems) {
3386 auto newItem = aResult.AppendElement(
3387 isOrthogonal ? subgridItem.Transpose() : subgridItem);
3388 if (MOZ_UNLIKELY(!isSameDirInAxis)(__builtin_expect(!!(!isSameDirInAxis), 0))) {
3389 newItem->ReverseDirection(aAxis, gridEndInAxis);
3390 }
3391 newItem->mArea.LineRangeForAxis(aAxis).Translate(offsetInAxis);
3392 if (itemIsSubgridInOppositeAxis) {
3393 if (MOZ_UNLIKELY(!isSameDirInOppositeAxis)(__builtin_expect(!!(!isSameDirInOppositeAxis), 0))) {
3394 newItem->ReverseDirection(oppositeAxis, gridEndInOppositeAxis);
3395 }
3396 LineRange& range = newItem->mArea.LineRangeForAxis(oppositeAxis);
3397 range.Translate(offsetInOppositeAxis);
3398 }
3399 if (newItem->IsSubgrid(aAxis)) {
3400 auto* subgrid =
3401 subgridItem.SubgridFrame()->GetProperty(Subgrid::Prop());
3402 CollectSubgridItemsForAxisHelper(
3403 aAxis, aContainerWM, newItem->mArea.LineRangeForAxis(aAxis),
3404 newItem->mArea.LineRangeForAxis(oppositeAxis), *newItem,
3405 subgrid->mGridItems, aResult);
3406 }
3407 }
3408 }
3409
3410 // Copy all descendant items from all our subgrid children that are subgridded
3411 // in aAxis recursively into aResult. All item grid area's and state are
3412 // translated to our coordinates.
3413 void CollectSubgridItemsForAxis(LogicalAxis aAxis,
3414 nsTArray<GridItemInfo>& aResult) const {
3415 for (const auto& item : mGridItems) {
3416 if (item.IsSubgrid(aAxis)) {
3417 const auto oppositeAxis = GetOrthogonalAxis(aAxis);
3418 auto* subgrid = item.SubgridFrame()->GetProperty(Subgrid::Prop());
3419 CollectSubgridItemsForAxisHelper(
3420 aAxis, mWM, item.mArea.LineRangeForAxis(aAxis),
3421 item.mArea.LineRangeForAxis(oppositeAxis), item,
3422 subgrid->mGridItems, aResult);
3423 }
3424 }
3425 }
3426
3427 /**
3428 * Recursive helper for CopyBaselineMetricsToSubgridItems().
3429 *
3430 * @param aAxis The LogicalAxis for the axis whose baseline metrics we're
3431 * copying here (with respect to the outermost parent grid's
3432 * writing mode).
3433 * @param aContainerWM The writing mode of that outermost parent grid.
3434 * @param aSubgridFrame The subgrid whose subgrid-items we're considering
3435 * in this recursive traversal (whose items we're copying over
3436 * baseline-alignment metrics for).
3437 * @param aContainerGridItems The outermost parent grid's array of
3438 * GridItemInfo objects. (The final portion of this array is
3439 * all for subgrid items, and that's the portion that we're
3440 * recursively iterating over.)
3441 * @param aContainerGridItemsIdx [in/out] The index for the item that we're
3442 * currently considering in aContainerGridItemsIdx. When
3443 * this function returns, this will be the index just beyond the
3444 * last item that we handled here, i.e. the index of the next
3445 * item to be handled.
3446 */
3447 static void CopyBaselineMetricsToSubgridItemsHelper(
3448 LogicalAxis aAxis, WritingMode aContainerWM, nsIFrame* aSubgridFrame,
3449 const nsTArray<GridItemInfo>& aContainerGridItems,
3450 size_t& aContainerGridItemsIdx) {
3451 // Get the canonical GridItemInfo structs for the grid items that live
3452 // inside of aSubgridFrame:
3453 Subgrid* subgridProp = aSubgridFrame->GetProperty(Subgrid::Prop());
3454 nsTArray<GridItemInfo>& subgridItems = subgridProp->mGridItems;
3455
3456 // Use aSubgridFrame's writing-mode to determine subgridAxis.
3457 // Grids & subgrids store various data on a per-LogicalAxis basis, with
3458 // respect to their own WritingMode. Here, subgridAxis is aSubgridFrame's
3459 // axis that maps to the same physical axis that aAxis does for the
3460 // outermost parent grid.
3461 auto subgridWM = aSubgridFrame->GetWritingMode();
3462 bool isOrthogonal = subgridWM.IsOrthogonalTo(aContainerWM);
3463 LogicalAxis subgridAxis = isOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
3464
3465 // Do a parallel walk through (1) subgridItems and (2) the portion of
3466 // aContainerGridItems that starts at offset aContainerGridItems,
3467 // descending to traverse child subgrids own items as we encounter them in
3468 // subgridItems. We expect to have an exact correspondence, because this
3469 // is precisely how we built up this portion of aContainerGridItems in
3470 // CollectSubgridItemsForAxis. (But if we happen to overstep the end of an
3471 // array, or find a GridItemInfo for a frame that we don't expect, we
3472 // gracefully bail out.)
3473 for (auto& subgridItem : subgridItems) {
3474 if (MOZ_UNLIKELY(aContainerGridItemsIdx >=(__builtin_expect(!!(aContainerGridItemsIdx >= aContainerGridItems
.Length()), 0))
3475 aContainerGridItems.Length())(__builtin_expect(!!(aContainerGridItemsIdx >= aContainerGridItems
.Length()), 0))
) {
3476 // We failed to make the same traversal as CollectSubgridItemsForAxis;
3477 // whoops! This shouldn't happen; but if it does, we gracefully bail
3478 // out, instead of crashing.
3479 MOZ_ASSERT_UNREACHABLE("Out-of-bounds aContainerGridItemsIdx")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Out-of-bounds aContainerGridItemsIdx" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3479); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Out-of-bounds aContainerGridItemsIdx"
")"); do { MOZ_CrashSequence(__null, 3479); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3480 return;
3481 }
3482 const auto& itemFromContainer =
3483 aContainerGridItems[aContainerGridItemsIdx];
3484 aContainerGridItemsIdx++;
3485
3486 if (MOZ_UNLIKELY(subgridItem.mFrame != itemFromContainer.mFrame)(__builtin_expect(!!(subgridItem.mFrame != itemFromContainer.
mFrame), 0))
) {
3487 // We failed to make the same traversal as CollectSubgridItemsForAxis;
3488 // whoops! This shouldn't happen; but if it does, we gracefully bail
3489 // out, instead of copying baseline-alignment data for the wrong frame.
3490 MOZ_ASSERT_UNREACHABLE("Found unexpected frame during traversal")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Found unexpected frame during traversal" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Found unexpected frame during traversal"
")"); do { MOZ_CrashSequence(__null, 3490); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3491 return;
3492 }
3493
3494 // This pattern of bits will be truthy if the item is baseline-aligned in
3495 // this axis (in which case the exact pattern of bits will have some
3496 // additional significance that doesn't matter here, but we do need to
3497 // copy it over).
3498 const auto baselineStateBits =
3499 itemFromContainer.mState[aAxis] & ItemState::eAllBaselineBits;
3500
3501 if (subgridItem.IsSubgrid(subgridAxis)) {
3502 // This item is in fact a nested subgrid. It shouldn't itself be
3503 // baseline-aligned, but we need to make a recursive call to copy
3504 // baseline metrics to its items.
3505 MOZ_ASSERT(!baselineStateBits,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!baselineStateBits)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!baselineStateBits))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!baselineStateBits"
" (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3507
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!baselineStateBits"
") (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")"); do { MOZ_CrashSequence(__null, 3507); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3506 "subgrids themselves can't be baseline-aligned "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!baselineStateBits)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!baselineStateBits))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!baselineStateBits"
" (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3507
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!baselineStateBits"
") (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")"); do { MOZ_CrashSequence(__null, 3507); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3507 "(or self-aligned in any way) in their subgrid axis")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!baselineStateBits)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!baselineStateBits))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!baselineStateBits"
" (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 3507
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!baselineStateBits"
") (" "subgrids themselves can't be baseline-aligned " "(or self-aligned in any way) in their subgrid axis"
")"); do { MOZ_CrashSequence(__null, 3507); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3508 CopyBaselineMetricsToSubgridItemsHelper(
3509 aAxis, aContainerWM, subgridItem.SubgridFrame(),
3510 aContainerGridItems, aContainerGridItemsIdx);
3511 } else if (baselineStateBits) {
3512 // This item is a baseline-aligned grid item (in the subgrid that we're
3513 // traversing). Copy over its baseline metrics.
3514 subgridItem.mState[subgridAxis] |= baselineStateBits;
3515 subgridItem.mBaselineOffset[subgridAxis] =
3516 itemFromContainer.mBaselineOffset[aAxis];
3517 }
3518 }
3519 }
3520
3521 /**
3522 * This function here is responsible for propagating baseline-alignment
3523 * metrics for subgrid-items from mGridItems over to the "canonical"
3524 * GridItemInfo structs for those grid items (which live on the subgrid that
3525 * owns them). The outermost parent grid *computes* those metrics as part of
3526 * doing track sizing, but it does this using *temporary* GridItemInfo
3527 * objects for any grid items that live in subgrids (aka subgrid items). So
3528 * that's why we need to rescue this baseline-alignment information before
3529 * those temporary objects are discarded.
3530 *
3531 * (The temporary subgrid-items all live at the end of mGridItems; they were
3532 * appended there by CollectSubgridItemsForAxis(). So, it's important that
3533 * we perform the exact same traversal that CollectSubgridItemsForAxis() did,
3534 * in order to properly match up the temporary & canonical GridItemInfo
3535 * objects for these subgrid items.)
3536 */
3537 // traversal that CollectSubgridItemsForAxis (and its recursive helper) does.
3538 void CopyBaselineMetricsToSubgridItems(LogicalAxis aAxis,
3539 size_t aOriginalLength) {
3540 MOZ_ASSERT(aOriginalLength <= mGridItems.Length(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOriginalLength <= mGridItems.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aOriginalLength <= mGridItems.Length()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOriginalLength <= mGridItems.Length()"
" (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOriginalLength <= mGridItems.Length()"
") (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")"); do
{ MOZ_CrashSequence(__null, 3543); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3541 "aOriginalLength is the length that mGridItems had *before* we "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOriginalLength <= mGridItems.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aOriginalLength <= mGridItems.Length()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOriginalLength <= mGridItems.Length()"
" (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOriginalLength <= mGridItems.Length()"
") (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")"); do
{ MOZ_CrashSequence(__null, 3543); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3542 "appended temporary copies of subgrid items to it, so it's not "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOriginalLength <= mGridItems.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aOriginalLength <= mGridItems.Length()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOriginalLength <= mGridItems.Length()"
" (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOriginalLength <= mGridItems.Length()"
") (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")"); do
{ MOZ_CrashSequence(__null, 3543); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3543 "possible for it to be more than the current length")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOriginalLength <= mGridItems.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aOriginalLength <= mGridItems.Length()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOriginalLength <= mGridItems.Length()"
" (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOriginalLength <= mGridItems.Length()"
") (" "aOriginalLength is the length that mGridItems had *before* we "
"appended temporary copies of subgrid items to it, so it's not "
"possible for it to be more than the current length" ")"); do
{ MOZ_CrashSequence(__null, 3543); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3544
3545 // This index 'subgridItemIdx' traverses the final portion of mGridItems,
3546 // the portion that currently has temporary GridItemInfo structs that we
3547 // built for the items that live in our subgrids. (Our caller is about to
3548 // discard this temporary portion of mGridItems, and we're trying to
3549 // transfer some baseline-alignment data to the canonical GridItemInfo
3550 // structs before that happens.)
3551 //
3552 // Our recursive helper updates subgridItemIdx internally. When this index
3553 // reaches mGridItems.Length(), we can stop looping; that means we've
3554 // finished copying out all the data from these temporary structs.
3555 size_t subgridItemIdx = aOriginalLength;
3556
3557 for (size_t i = 0;
3558 (i < aOriginalLength && subgridItemIdx < mGridItems.Length()); i++) {
3559 const auto& item = mGridItems[i];
3560 if (item.IsSubgrid(aAxis)) {
3561 CopyBaselineMetricsToSubgridItemsHelper(aAxis, mWM, item.SubgridFrame(),
3562 mGridItems, subgridItemIdx);
3563 }
3564 }
3565 }
3566
3567 Tracks& TracksFor(LogicalAxis aAxis) {
3568 return aAxis == LogicalAxis::Block ? mRows : mCols;
3569 }
3570 const Tracks& TracksFor(LogicalAxis aAxis) const {
3571 return aAxis == LogicalAxis::Block ? mRows : mCols;
3572 }
3573
3574 CSSOrderAwareFrameIterator mIter;
3575 const nsStylePosition* const mGridStyle;
3576 Tracks mCols;
3577 Tracks mRows;
3578 TrackSizingFunctions mColFunctions;
3579 TrackSizingFunctions mRowFunctions;
3580 /**
3581 * Info about each (normal flow) grid item.
3582 */
3583 nsTArray<GridItemInfo> mGridItems;
3584 /**
3585 * Info about each grid-aligned abs.pos. child.
3586 */
3587 nsTArray<GridItemInfo> mAbsPosItems;
3588
3589 /**
3590 * @note mReflowInput may be null when using the 2nd ctor above. In this case
3591 * we'll construct a dummy parent reflow input if we need it to calculate
3592 * min/max-content contributions when sizing tracks.
3593 */
3594 const ReflowInput* const mReflowInput;
3595 gfxContext& mRenderingContext;
3596 nsGridContainerFrame* const mFrame;
3597 /** [weak] owned by mFrame's first-in-flow. */
3598 SharedGridData* mSharedGridData = nullptr;
3599 /** Computed border+padding with mSkipSides applied. */
3600 LogicalMargin mBorderPadding;
3601 /**
3602 * BStart of this fragment in "grid space" (i.e. the concatenation of content
3603 * areas of all fragments). Equal to mRows.mSizes[mStartRow].mPosition,
3604 * or, if this fragment starts after the last row, the ConsumedBSize().
3605 */
3606 nscoord mFragBStart = 0;
3607 /** The start row for this fragment. */
3608 uint32_t mStartRow = 0;
3609 /**
3610 * The start row for the next fragment, if any. If mNextFragmentStartRow ==
3611 * mStartRow then there are no rows in this fragment.
3612 */
3613 uint32_t mNextFragmentStartRow = 0;
3614 /** Our tentative ApplySkipSides bits. */
3615 LogicalSides mSkipSides;
3616 const WritingMode mWM;
3617 /** Initialized lazily, when we find the fragmentainer. */
3618 bool mInFragmentainer = false;
3619 /** Set when the grid itself is having its intrinsic size measured. */
3620 bool mIsGridIntrinsicSizing = false;
3621
3622 private:
3623 GridReflowInput(nsGridContainerFrame* aFrame, gfxContext& aRenderingContext,
3624 const ReflowInput* aReflowInput,
3625 const nsStylePosition* aGridStyle, const WritingMode& aWM)
3626 : mIter(aFrame, FrameChildListID::Principal),
3627 mGridStyle(aGridStyle),
3628 mCols(LogicalAxis::Inline),
3629 mRows(LogicalAxis::Block),
3630 mColFunctions(mGridStyle->mGridTemplateColumns,
3631 mGridStyle->mGridAutoColumns, aFrame->IsColSubgrid()),
3632 mRowFunctions(mGridStyle->mGridTemplateRows, mGridStyle->mGridAutoRows,
3633 aFrame->IsRowSubgrid()),
3634 mReflowInput(aReflowInput),
3635 mRenderingContext(aRenderingContext),
3636 mFrame(aFrame),
3637 mBorderPadding(aWM),
3638 mSkipSides(aFrame->GetWritingMode()),
3639 mWM(aWM) {
3640 MOZ_ASSERT(!aReflowInput || aReflowInput->mFrame == mFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aReflowInput || aReflowInput->mFrame == mFrame)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aReflowInput || aReflowInput->mFrame == mFrame))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aReflowInput || aReflowInput->mFrame == mFrame"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3640)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aReflowInput || aReflowInput->mFrame == mFrame"
")"); do { MOZ_CrashSequence(__null, 3640); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3641 if (aReflowInput) {
3642 mBorderPadding = aReflowInput->ComputedLogicalBorderPadding(mWM);
3643 mSkipSides = aFrame->PreReflowBlockLevelLogicalSkipSides();
3644 mBorderPadding.ApplySkipSides(mSkipSides);
3645 }
3646 mCols.mIsMasonry = aFrame->IsColMasonry();
3647 mRows.mIsMasonry = aFrame->IsRowMasonry();
3648 MOZ_ASSERT(!(mCols.mIsMasonry && mRows.mIsMasonry),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mCols.mIsMasonry && mRows.mIsMasonry))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(mCols.mIsMasonry && mRows.mIsMasonry)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!(mCols.mIsMasonry && mRows.mIsMasonry)"
" (" "can't have masonry layout in both axes" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mCols.mIsMasonry && mRows.mIsMasonry)"
") (" "can't have masonry layout in both axes" ")"); do { MOZ_CrashSequence
(__null, 3649); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3649 "can't have masonry layout in both axes")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(mCols.mIsMasonry && mRows.mIsMasonry))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(mCols.mIsMasonry && mRows.mIsMasonry)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!(mCols.mIsMasonry && mRows.mIsMasonry)"
" (" "can't have masonry layout in both axes" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 3649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mCols.mIsMasonry && mRows.mIsMasonry)"
") (" "can't have masonry layout in both axes" ")"); do { MOZ_CrashSequence
(__null, 3649); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3650 }
3651};
3652
3653using GridReflowInput = nsGridContainerFrame::GridReflowInput;
3654
3655/**
3656 * The Grid implements grid item placement and the state of the grid -
3657 * the size of the explicit/implicit grid, which cells are occupied etc.
3658 */
3659struct MOZ_STACK_CLASS nsGridContainerFrame::Grid {
3660 explicit Grid(const Grid* aParentGrid = nullptr) : mParentGrid(aParentGrid) {}
3661
3662 /**
3663 * Place all child frames into the grid and expand the (implicit) grid as
3664 * needed. The allocated GridAreas are stored in the GridAreaProperty
3665 * frame property on the child frame.
3666 * @param aRepeatSizing the container's [min-|max-]*size - used to determine
3667 * the number of repeat(auto-fill/fit) tracks.
3668 */
3669 void PlaceGridItems(GridReflowInput& aGridRI,
3670 const RepeatTrackSizingInput& aRepeatSizing);
3671
3672 void SubgridPlaceGridItems(GridReflowInput& aParentGridRI, Grid* aParentGrid,
3673 const GridItemInfo& aGridItem);
3674
3675 /**
3676 * As above but for an abs.pos. child. Any 'auto' lines will be represented
3677 * by kAutoLine in the LineRange result.
3678 * @param aGridStart the first line in the final, but untranslated grid
3679 * @param aGridEnd the last line in the final, but untranslated grid
3680 */
3681 LineRange ResolveAbsPosLineRange(const StyleGridLine& aStart,
3682 const StyleGridLine& aEnd,
3683 const LineNameMap& aNameMap,
3684 LogicalAxis aAxis, uint32_t aExplicitGridEnd,
3685 int32_t aGridStart, int32_t aGridEnd,
3686 const nsStylePosition* aStyle);
3687
3688 /**
3689 * Return a GridArea for abs.pos. item with non-auto lines placed at
3690 * a definite line (1-based) with placement errors resolved. One or both
3691 * positions may still be 'auto'.
3692 * @param aChild the abs.pos. grid item to place
3693 * @param aStyle the StylePosition() for the grid container
3694 */
3695 GridArea PlaceAbsPos(nsIFrame* aChild, const LineNameMap& aColLineNameMap,
3696 const LineNameMap& aRowLineNameMap,
3697 const nsStylePosition* aStyle);
3698
3699 /**
3700 * Find the first column in row aLockedRow starting at aStartCol where aArea
3701 * could be placed without overlapping other items. The returned column may
3702 * cause aArea to overflow the current implicit grid bounds if placed there.
3703 */
3704 uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
3705 const GridArea* aArea) const;
3706
3707 /**
3708 * Place aArea in the first column (in row aArea->mRows.mStart) starting at
3709 * aStartCol without overlapping other items. The resulting aArea may
3710 * overflow the current implicit grid bounds.
3711 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3712 * Pre-condition: aArea->mRows.IsDefinite() is true.
3713 * Post-condition: aArea->IsDefinite() is true.
3714 */
3715 void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea,
3716 uint32_t aClampMaxColLine) const;
3717
3718 /**
3719 * Find the first row in column aLockedCol starting at aStartRow where aArea
3720 * could be placed without overlapping other items. The returned row may
3721 * cause aArea to overflow the current implicit grid bounds if placed there.
3722 */
3723 uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
3724 const GridArea* aArea) const;
3725
3726 /**
3727 * Place aArea in the first row (in column aArea->mCols.mStart) starting at
3728 * aStartRow without overlapping other items. The resulting aArea may
3729 * overflow the current implicit grid bounds.
3730 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3731 * Pre-condition: aArea->mCols.IsDefinite() is true.
3732 * Post-condition: aArea->IsDefinite() is true.
3733 */
3734 void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea,
3735 uint32_t aClampMaxRowLine) const;
3736
3737 /**
3738 * Place aArea in the first column starting at aStartCol,aStartRow without
3739 * causing it to overlap other items or overflow mGridColEnd.
3740 * If there's no such column in aStartRow, continue in position 1,aStartRow+1.
3741 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3742 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3743 * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
3744 * Post-condition: aArea->IsDefinite() is true.
3745 */
3746 void PlaceAutoAutoInRowOrder(uint32_t aStartCol, uint32_t aStartRow,
3747 GridArea* aArea, uint32_t aClampMaxColLine,
3748 uint32_t aClampMaxRowLine) const;
3749
3750 /**
3751 * Place aArea in the first row starting at aStartCol,aStartRow without
3752 * causing it to overlap other items or overflow mGridRowEnd.
3753 * If there's no such row in aStartCol, continue in position aStartCol+1,1.
3754 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3755 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3756 * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
3757 * Post-condition: aArea->IsDefinite() is true.
3758 */
3759 void PlaceAutoAutoInColOrder(uint32_t aStartCol, uint32_t aStartRow,
3760 GridArea* aArea, uint32_t aClampMaxColLine,
3761 uint32_t aClampMaxRowLine) const;
3762
3763 /**
3764 * Return aLine if it's inside the aMin..aMax range (inclusive),
3765 * otherwise return kAutoLine.
3766 */
3767 static int32_t AutoIfOutside(int32_t aLine, int32_t aMin, int32_t aMax) {
3768 MOZ_ASSERT(aMin <= aMax)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMin <= aMax)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMin <= aMax))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aMin <= aMax"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3768)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMin <= aMax" ")"
); do { MOZ_CrashSequence(__null, 3768); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3769 if (aLine < aMin || aLine > aMax) {
3770 return kAutoLine;
3771 }
3772 return aLine;
3773 }
3774
3775 /**
3776 * Inflate the implicit grid to include aArea.
3777 * @param aArea may be definite or auto
3778 */
3779 void InflateGridFor(const GridArea& aArea) {
3780 mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
3781 mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
3782 MOZ_ASSERT(mGridColEnd <= kTranslatedMaxLine &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGridColEnd <= kTranslatedMaxLine && mGridRowEnd
<= kTranslatedMaxLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGridColEnd <= kTranslatedMaxLine
&& mGridRowEnd <= kTranslatedMaxLine))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3783)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 3783); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3783 mGridRowEnd <= kTranslatedMaxLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGridColEnd <= kTranslatedMaxLine && mGridRowEnd
<= kTranslatedMaxLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGridColEnd <= kTranslatedMaxLine
&& mGridRowEnd <= kTranslatedMaxLine))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3783)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 3783); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3784 }
3785
3786 /**
3787 * Calculates the empty tracks in a repeat(auto-fit).
3788 * @param aOutNumEmptyLines Outputs the number of tracks which are empty.
3789 * @param aSizingFunctions Sizing functions for the relevant axis.
3790 * @param aNumGridLines Number of grid lines for the relevant axis.
3791 * @param aIsEmptyFunc Functor to check if a cell is empty. This should be
3792 * mCellMap.IsColEmpty or mCellMap.IsRowEmpty, depending on the axis.
3793 */
3794 template <typename IsEmptyFuncT>
3795 static Maybe<nsTArray<uint32_t>> CalculateAdjustForAutoFitElements(
3796 uint32_t* aOutNumEmptyTracks, TrackSizingFunctions& aSizingFunctions,
3797 uint32_t aNumGridLines, IsEmptyFuncT aIsEmptyFunc);
3798
3799 /**
3800 * Return a line number for (non-auto) aLine, per:
3801 * https://drafts.csswg.org/css-grid-2/#line-placement
3802 * @param aLine style data for the line (must be non-auto)
3803 * @param aNth a number of lines to find from aFromIndex, negative if the
3804 * search should be in reverse order. In the case aLine has
3805 * a specified line name, it's permitted to pass in zero which
3806 * will be treated as one.
3807 * @param aFromIndex the zero-based index to start counting from
3808 * @param aLineNameList the explicit named lines
3809 * @param aSide the axis+edge we're resolving names for (e.g. if we're
3810 resolving a grid-row-start line, pass LogicalSide::BStart)
3811 * @param aExplicitGridEnd the last line in the explicit grid
3812 * @param aStyle the StylePosition() for the grid container
3813 * @return a definite line (1-based), clamped to
3814 * the mClampMinLine..mClampMaxLine range
3815 */
3816 int32_t ResolveLine(const StyleGridLine& aLine, int32_t aNth,
3817 uint32_t aFromIndex, const LineNameMap& aNameMap,
3818 LogicalSide aSide, uint32_t aExplicitGridEnd,
3819 const nsStylePosition* aStyle);
3820
3821 /**
3822 * Helper method for ResolveLineRange.
3823 * @see ResolveLineRange
3824 * @return a pair (start,end) of lines
3825 */
3826 typedef std::pair<int32_t, int32_t> LinePair;
3827 LinePair ResolveLineRangeHelper(const StyleGridLine& aStart,
3828 const StyleGridLine& aEnd,
3829 const LineNameMap& aNameMap,
3830 LogicalAxis aAxis, uint32_t aExplicitGridEnd,
3831 const nsStylePosition* aStyle);
3832
3833 /**
3834 * Return a LineRange based on the given style data. Non-auto lines
3835 * are resolved to a definite line number (1-based) per:
3836 * https://drafts.csswg.org/css-grid-2/#line-placement
3837 * with placement errors corrected per:
3838 * https://drafts.csswg.org/css-grid-2/#grid-placement-errors
3839 * @param aStyle the StylePosition() for the grid container
3840 * @param aStart style data for the start line
3841 * @param aEnd style data for the end line
3842 * @param aLineNameList the explicit named lines
3843 * @param aAxis the axis we're resolving names in
3844 * @param aExplicitGridEnd the last line in the explicit grid
3845 * @param aStyle the StylePosition() for the grid container
3846 */
3847 LineRange ResolveLineRange(const StyleGridLine& aStart,
3848 const StyleGridLine& aEnd,
3849 const LineNameMap& aNameMap, LogicalAxis aAxis,
3850 uint32_t aExplicitGridEnd,
3851 const nsStylePosition* aStyle);
3852
3853 /**
3854 * Return a GridArea with non-auto lines placed at a definite line (1-based)
3855 * with placement errors resolved. One or both positions may still
3856 * be 'auto'.
3857 * @param aChild the grid item
3858 * @param aStyle the StylePosition() for the grid container
3859 */
3860 GridArea PlaceDefinite(nsIFrame* aChild, const LineNameMap& aColLineNameMap,
3861 const LineNameMap& aRowLineNameMap,
3862 const nsStylePosition* aStyle);
3863
3864 bool HasImplicitNamedArea(nsAtom* aName) const {
3865 return mAreas && mAreas->has(aName);
3866 }
3867
3868 // Return true if aString ends in aSuffix and has at least one character
3869 // before the suffix. Assign aIndex to where the suffix starts.
3870 static bool IsNameWithSuffix(nsAtom* aString, const nsString& aSuffix,
3871 uint32_t* aIndex) {
3872 if (StringEndsWith(nsDependentAtomString(aString), aSuffix)) {
3873 *aIndex = aString->GetLength() - aSuffix.Length();
3874 return *aIndex != 0;
3875 }
3876 return false;
3877 }
3878
3879 static bool IsNameWithEndSuffix(nsAtom* aString, uint32_t* aIndex) {
3880 return IsNameWithSuffix(aString, u"-end"_ns, aIndex);
3881 }
3882
3883 static bool IsNameWithStartSuffix(nsAtom* aString, uint32_t* aIndex) {
3884 return IsNameWithSuffix(aString, u"-start"_ns, aIndex);
3885 }
3886
3887 // Return the relevant parent LineNameMap for the given subgrid axis aAxis.
3888 const LineNameMap* ParentLineMapForAxis(bool aIsOrthogonal,
3889 LogicalAxis aAxis) const {
3890 if (!mParentGrid) {
3891 return nullptr;
3892 }
3893 bool isRows = aIsOrthogonal == (aAxis == LogicalAxis::Inline);
3894 return isRows ? mParentGrid->mRowNameMap : mParentGrid->mColNameMap;
3895 }
3896
3897 void SetLineMaps(const LineNameMap* aColNameMap,
3898 const LineNameMap* aRowNameMap) {
3899 mColNameMap = aColNameMap;
3900 mRowNameMap = aRowNameMap;
3901 }
3902
3903 /**
3904 * A CellMap holds state for each cell in the grid.
3905 * It's row major. It's sparse in the sense that it only has enough rows to
3906 * cover the last row that has a grid item. Each row only has enough entries
3907 * to cover columns that are occupied *on that row*, i.e. it's not a full
3908 * matrix covering the entire implicit grid. An absent Cell means that it's
3909 * unoccupied by any grid item.
3910 */
3911 struct CellMap {
3912 struct Cell {
3913 constexpr Cell() : mIsOccupied(false) {}
3914 bool mIsOccupied : 1;
3915 };
3916
3917 void Fill(const GridArea& aGridArea) {
3918 MOZ_ASSERT(aGridArea.IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridArea.IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridArea.IsDefinite()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aGridArea.IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3918)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 3918); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3919 MOZ_ASSERT(aGridArea.mRows.mStart < aGridArea.mRows.mEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridArea.mRows.mStart < aGridArea.mRows.mEnd)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGridArea.mRows.mStart < aGridArea.mRows.mEnd))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aGridArea.mRows.mStart < aGridArea.mRows.mEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3919)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.mRows.mStart < aGridArea.mRows.mEnd"
")"); do { MOZ_CrashSequence(__null, 3919); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3920 MOZ_ASSERT(aGridArea.mCols.mStart < aGridArea.mCols.mEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridArea.mCols.mStart < aGridArea.mCols.mEnd)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGridArea.mCols.mStart < aGridArea.mCols.mEnd))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aGridArea.mCols.mStart < aGridArea.mCols.mEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 3920)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.mCols.mStart < aGridArea.mCols.mEnd"
")"); do { MOZ_CrashSequence(__null, 3920); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3921 const auto numRows = aGridArea.mRows.mEnd;
3922 const auto numCols = aGridArea.mCols.mEnd;
3923 mCells.EnsureLengthAtLeast(numRows);
3924 for (auto i = aGridArea.mRows.mStart; i < numRows; ++i) {
3925 nsTArray<Cell>& cellsInRow = mCells[i];
3926 cellsInRow.EnsureLengthAtLeast(numCols);
3927 for (auto j = aGridArea.mCols.mStart; j < numCols; ++j) {
3928 cellsInRow[j].mIsOccupied = true;
3929 }
3930 }
3931 }
3932
3933 uint32_t IsEmptyCol(uint32_t aCol) const {
3934 for (auto& row : mCells) {
3935 if (aCol < row.Length() && row[aCol].mIsOccupied) {
3936 return false;
3937 }
3938 }
3939 return true;
3940 }
3941 uint32_t IsEmptyRow(uint32_t aRow) const {
3942 if (aRow >= mCells.Length()) {
3943 return true;
3944 }
3945 for (const Cell& cell : mCells[aRow]) {
3946 if (cell.mIsOccupied) {
3947 return false;
3948 }
3949 }
3950 return true;
3951 }
3952#ifdef DEBUG1
3953 void Dump() const {
3954 const size_t numRows = mCells.Length();
3955 for (size_t i = 0; i < numRows; ++i) {
3956 const nsTArray<Cell>& cellsInRow = mCells[i];
3957 const size_t numCols = cellsInRow.Length();
3958 printf("%lu:\t", (unsigned long)i + 1);
3959 for (size_t j = 0; j < numCols; ++j) {
3960 printf(cellsInRow[j].mIsOccupied ? "X " : ". ");
3961 }
3962 printf("\n");
3963 }
3964 }
3965#endif
3966
3967 nsTArray<nsTArray<Cell>> mCells;
3968 };
3969
3970 /**
3971 * State for each cell in the grid.
3972 */
3973 CellMap mCellMap;
3974 /**
3975 * @see HasImplicitNamedArea.
3976 */
3977 ImplicitNamedAreas* mAreas;
3978 /**
3979 * The last column grid line (1-based) in the explicit grid.
3980 * (i.e. the number of explicit columns + 1)
3981 */
3982 uint32_t mExplicitGridColEnd;
3983 /**
3984 * The last row grid line (1-based) in the explicit grid.
3985 * (i.e. the number of explicit rows + 1)
3986 */
3987 uint32_t mExplicitGridRowEnd;
3988 // Same for the implicit grid, except these become zero-based after
3989 // resolving definite lines.
3990 uint32_t mGridColEnd;
3991 uint32_t mGridRowEnd;
3992
3993 /**
3994 * Offsets from the start of the implicit grid to the start of the translated
3995 * explicit grid. They are zero if there are no implicit lines before 1,1.
3996 * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the
3997 * corresponding GridArea::mCols will be 0 / 3 in the zero-based translated
3998 * grid.
3999 */
4000 uint32_t mExplicitGridOffsetCol;
4001 uint32_t mExplicitGridOffsetRow;
4002
4003 /**
4004 * Our parent grid if any.
4005 */
4006 const Grid* mParentGrid;
4007
4008 /**
4009 * Our LineNameMaps.
4010 */
4011 const LineNameMap* mColNameMap;
4012 const LineNameMap* mRowNameMap;
4013};
4014
4015/**
4016 * Compute margin+border+padding for aGridItem.mFrame (a subgrid) and store it
4017 * on its Subgrid property (and return that property).
4018 * aPercentageBasis is in the grid item's writing-mode.
4019 */
4020static Subgrid* SubgridComputeMarginBorderPadding(
4021 const GridItemInfo& aGridItem, const LogicalSize& aPercentageBasis) {
4022 auto* subgridFrame = aGridItem.SubgridFrame();
4023 auto cbWM = aGridItem.mFrame->GetParent()->GetWritingMode();
4024 auto* subgrid = subgridFrame->GetProperty(Subgrid::Prop());
4025 auto wm = subgridFrame->GetWritingMode();
4026 auto pmPercentageBasis = cbWM.IsOrthogonalTo(wm) ? aPercentageBasis.BSize(wm)
4027 : aPercentageBasis.ISize(wm);
4028 SizeComputationInput sz(subgridFrame, nullptr, cbWM, pmPercentageBasis);
4029 subgrid->mMarginBorderPadding =
4030 sz.ComputedLogicalMargin(cbWM) + sz.ComputedLogicalBorderPadding(cbWM);
4031 if (aGridItem.mFrame == subgridFrame) {
4032 return subgrid;
4033 }
4034
4035 if (ScrollContainerFrame* scrollContainerFrame =
4036 aGridItem.mFrame->GetScrollTargetFrame()) {
4037 MOZ_ASSERT(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
" (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
") (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")"); do { MOZ_CrashSequence(__null, 4040); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4038 sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
" (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
") (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")"); do { MOZ_CrashSequence(__null, 4040); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4039 "A scrolled inner frame should not have any margin or border / "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
" (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
") (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")"); do { MOZ_CrashSequence(__null, 4040); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4040 "padding!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM
) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin
(cbWM)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
" (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) && sz.ComputedLogicalBorderPadding(cbWM) == LogicalMargin(cbWM)"
") (" "A scrolled inner frame should not have any margin or border / "
"padding!" ")"); do { MOZ_CrashSequence(__null, 4040); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
4041 // Add the margin and border from the scroller frame.
4042 SizeComputationInput szOuterFrame(scrollContainerFrame, nullptr, cbWM,
4043 pmPercentageBasis);
4044 subgrid->mMarginBorderPadding +=
4045 szOuterFrame.ComputedLogicalMargin(cbWM) +
4046 szOuterFrame.ComputedLogicalBorderPadding(cbWM) +
4047 LogicalMargin(cbWM,
4048 scrollContainerFrame->IntrinsicScrollbarGutterSize());
4049 }
4050
4051 if (nsFieldSetFrame* f = do_QueryFrame(aGridItem.mFrame)) {
4052 const auto* inner = f->GetInner();
4053 auto wm = inner->GetWritingMode();
4054 LogicalPoint pos = inner->GetLogicalPosition(aGridItem.mFrame->GetSize());
4055 // The legend is always on the BStart side and it inflates the fieldset's
4056 // "border area" size. The inner frame's b-start pos equals that size.
4057 LogicalMargin offsets(wm, pos.B(wm), 0, 0, 0);
4058 subgrid->mMarginBorderPadding += offsets.ConvertTo(cbWM, wm);
4059 }
4060
4061 return subgrid;
4062}
4063
4064static void CopyUsedTrackSizes(TrackPlan& aResult,
4065 const nsGridContainerFrame* aUsedTrackSizesFrame,
4066 const UsedTrackSizes* aUsedTrackSizes,
4067 const nsGridContainerFrame* aSubgridFrame,
4068 const Subgrid* aSubgrid,
4069 LogicalAxis aSubgridAxis) {
4070 MOZ_ASSERT(aSubgridFrame->ParentGridContainerForSubgrid() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgridFrame->ParentGridContainerForSubgrid() ==
aUsedTrackSizesFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubgridFrame->ParentGridContainerForSubgrid
() == aUsedTrackSizesFrame))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4071)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
")"); do { MOZ_CrashSequence(__null, 4071); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4071 aUsedTrackSizesFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubgridFrame->ParentGridContainerForSubgrid() ==
aUsedTrackSizesFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubgridFrame->ParentGridContainerForSubgrid
() == aUsedTrackSizesFrame))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4071)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
")"); do { MOZ_CrashSequence(__null, 4071); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4072 aResult.SetLength(aSubgridAxis == LogicalAxis::Inline
4073 ? aSubgrid->mGridColEnd
4074 : aSubgrid->mGridRowEnd);
4075 auto parentAxis =
4076 aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aSubgridAxis) : aSubgridAxis;
4077 const auto& parentSizes = aUsedTrackSizes->mTrackPlans[parentAxis];
4078 MOZ_ASSERT(aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis])do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis
])>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis
]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis]", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4078); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis]"
")"); do { MOZ_CrashSequence(__null, 4078); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4079 if (parentSizes.IsEmpty()) {
4080 return;
4081 }
4082 const auto& range = aSubgrid->mArea.LineRangeForAxis(parentAxis);
4083 const auto cbwm = aUsedTrackSizesFrame->GetWritingMode();
4084 const auto wm = aSubgridFrame->GetWritingMode();
4085 // Recompute the MBP to resolve percentages against the resolved track sizes.
4086 if (parentAxis == LogicalAxis::Inline) {
4087 // Find the subgrid's grid item frame in its parent grid container. This
4088 // is usually the same as aSubgridFrame but it may also have a ScrollFrame,
4089 // FieldSetFrame etc. We just loop until we see the first ancestor
4090 // GridContainerFrame and pick the last frame we saw before that.
4091 // Note that all subgrids are inside a parent (sub)grid container.
4092 const nsIFrame* outerGridItemFrame = aSubgridFrame;
4093 for (nsIFrame* parent = aSubgridFrame->GetParent();
4094 parent != aUsedTrackSizesFrame; parent = parent->GetParent()) {
4095 MOZ_ASSERT(!parent->IsGridContainerFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parent->IsGridContainerFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!parent->IsGridContainerFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!parent->IsGridContainerFrame()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 4095); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4096 outerGridItemFrame = parent;
4097 }
4098 auto sizeInAxis = range.ToLength(aUsedTrackSizes->mTrackPlans[parentAxis]);
4099 LogicalSize pmPercentageBasis =
4100 aSubgrid->mIsOrthogonal ? LogicalSize(wm, nscoord(0), sizeInAxis)
4101 : LogicalSize(wm, sizeInAxis, nscoord(0));
4102 GridItemInfo info(const_cast<nsIFrame*>(outerGridItemFrame),
4103 aSubgrid->mArea);
4104 SubgridComputeMarginBorderPadding(info, pmPercentageBasis);
4105 }
4106 const LogicalMargin& mbp = aSubgrid->mMarginBorderPadding;
4107 nscoord startMBP;
4108 nscoord endMBP;
4109 if (MOZ_LIKELY(cbwm.ParallelAxisStartsOnSameSide(parentAxis, wm))(__builtin_expect(!!(cbwm.ParallelAxisStartsOnSameSide(parentAxis
, wm)), 1))
) {
4110 startMBP = mbp.Start(parentAxis, cbwm);
4111 endMBP = mbp.End(parentAxis, cbwm);
4112 uint32_t i = range.mStart;
4113 nscoord startPos = parentSizes[i].mPosition + startMBP;
4114 for (auto& sz : aResult) {
4115 sz = parentSizes[i++];
4116 sz.mPosition -= startPos;
4117 }
4118 } else {
4119 startMBP = mbp.End(parentAxis, cbwm);
4120 endMBP = mbp.Start(parentAxis, cbwm);
4121 uint32_t i = range.mEnd - 1;
4122 const auto& parentEnd = parentSizes[i];
4123 nscoord parentEndPos = parentEnd.mPosition + parentEnd.mBase - startMBP;
4124 for (auto& sz : aResult) {
4125 sz = parentSizes[i--];
4126 sz.mPosition = parentEndPos - (sz.mPosition + sz.mBase);
4127 }
4128 }
4129 auto& startTrack = aResult[0];
4130 startTrack.mPosition = 0;
4131 startTrack.mBase -= startMBP;
4132 if (MOZ_UNLIKELY(startTrack.mBase < nscoord(0))(__builtin_expect(!!(startTrack.mBase < nscoord(0)), 0))) {
4133 // Our MBP doesn't fit in the start track. Adjust the track position
4134 // to maintain track alignment with our parent.
4135 startTrack.mPosition = startTrack.mBase;
4136 startTrack.mBase = nscoord(0);
4137 }
4138 auto& endTrack = aResult.LastElement();
4139 endTrack.mBase -= endMBP;
4140 if (MOZ_UNLIKELY(endTrack.mBase < nscoord(0))(__builtin_expect(!!(endTrack.mBase < nscoord(0)), 0))) {
4141 endTrack.mBase = nscoord(0);
4142 }
4143}
4144
4145void nsGridContainerFrame::UsedTrackSizes::ResolveTrackSizesForAxis(
4146 nsGridContainerFrame* aFrame, LogicalAxis aAxis, gfxContext& aRC) {
4147 if (mCanResolveLineRangeSize[aAxis]) {
4148 return;
4149 }
4150 if (!aFrame->IsSubgrid()) {
4151 // We can't resolve sizes in this axis at this point. aFrame is the top grid
4152 // container, which will store its final track sizes later once they're
4153 // resolved in this axis (in GridReflowInput::CalculateTrackSizesForAxis).
4154 // The single caller of this method only needs track sizes for
4155 // calculating a CB size and it will treat it as indefinite when
4156 // this happens.
4157 return;
4158 }
4159 auto* parent = aFrame->ParentGridContainerForSubgrid();
4160 auto* parentSizes =
4161 parent->GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
4162 auto* subgrid = aFrame->GetProperty(Subgrid::Prop());
4163 const auto parentAxis =
4164 subgrid->mIsOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
4165 parentSizes->ResolveTrackSizesForAxis(parent, parentAxis, aRC);
4166 if (!parentSizes->mCanResolveLineRangeSize[parentAxis]) {
4167 if (aFrame->IsSubgrid(aAxis)) {
4168 ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC,
4169 NS_UNCONSTRAINEDSIZE);
4170 }
4171 return;
4172 }
4173 if (aFrame->IsSubgrid(aAxis)) {
4174 CopyUsedTrackSizes(mTrackPlans[aAxis], parent, parentSizes, aFrame, subgrid,
4175 aAxis);
4176 mCanResolveLineRangeSize[aAxis] = true;
4177 } else {
4178 const auto& range = subgrid->mArea.LineRangeForAxis(parentAxis);
4179 nscoord contentBoxSize =
4180 range.ToLength(parentSizes->mTrackPlans[parentAxis]);
4181 auto parentWM = aFrame->GetParent()->GetWritingMode();
4182 contentBoxSize -=
4183 subgrid->mMarginBorderPadding.StartEnd(parentAxis, parentWM);
4184 contentBoxSize = std::max(nscoord(0), contentBoxSize);
4185 ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC,
4186 contentBoxSize);
4187 }
4188}
4189
4190void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
4191 nsGridContainerFrame* aFrame, LogicalAxis aAxis, Subgrid* aSubgrid,
4192 gfxContext& aRC, nscoord aContentBoxSize) {
4193 GridReflowInput gridRI(aFrame, aRC);
4194 gridRI.mGridItems = aSubgrid->mGridItems.Clone();
4195 Grid grid;
4196 grid.mGridColEnd = aSubgrid->mGridColEnd;
4197 grid.mGridRowEnd = aSubgrid->mGridRowEnd;
4198 gridRI.CalculateTrackSizesForAxis(aAxis, grid, aContentBoxSize,
4199 SizingConstraint::NoConstraint);
4200 const auto& tracks = gridRI.TracksFor(aAxis);
4201 mTrackPlans[aAxis].Assign(tracks.mSizes);
4202 mCanResolveLineRangeSize[aAxis] = tracks.mCanResolveLineRangeSize;
4203 MOZ_ASSERT(mCanResolveLineRangeSize[aAxis])do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanResolveLineRangeSize[aAxis])>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCanResolveLineRangeSize[aAxis
]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mCanResolveLineRangeSize[aAxis]", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4203); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCanResolveLineRangeSize[aAxis]"
")"); do { MOZ_CrashSequence(__null, 4203); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4204}
4205
4206void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
4207 LogicalAxis aAxis, const Grid& aGrid, nscoord aContentBoxSize,
4208 SizingConstraint aConstraint) {
4209 auto& tracks = TracksFor(aAxis);
4210 const auto& sizingFunctions =
4211 aAxis == LogicalAxis::Inline ? mColFunctions : mRowFunctions;
4212 const auto& gapStyle = aAxis == LogicalAxis::Inline ? mGridStyle->mColumnGap
4213 : mGridStyle->mRowGap;
4214 if (tracks.mIsMasonry) {
4215 // See comment on nsGridContainerFrame::MasonryLayout().
4216 tracks.Initialize(sizingFunctions, gapStyle, 2, aContentBoxSize);
4217 tracks.mCanResolveLineRangeSize = true;
4218 return;
4219 }
4220 uint32_t gridEnd =
4221 aAxis == LogicalAxis::Inline ? aGrid.mGridColEnd : aGrid.mGridRowEnd;
4222 Maybe<TrackSizingFunctions> fallbackTrackSizing;
4223
4224 bool useParentGaps = false;
4225 const bool isSubgriddedAxis = mFrame->IsSubgrid(aAxis);
4226 if (MOZ_LIKELY(!isSubgriddedAxis)(__builtin_expect(!!(!isSubgriddedAxis), 1))) {
4227 tracks.Initialize(sizingFunctions, gapStyle, gridEnd, aContentBoxSize);
4228 } else {
4229 tracks.mGridGap =
4230 nsLayoutUtils::ResolveGapToLength(gapStyle, aContentBoxSize);
4231 tracks.mContentBoxSize = aContentBoxSize;
4232 const auto* subgrid = mFrame->GetProperty(Subgrid::Prop());
4233 tracks.mSizes.SetLength(gridEnd);
4234 auto* parent = mFrame->ParentGridContainerForSubgrid();
4235 auto parentAxis = subgrid->mIsOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
4236 const auto* parentSizes = parent->GetUsedTrackSizes();
4237 if (parentSizes && parentSizes->mCanResolveLineRangeSize[parentAxis]) {
4238 CopyUsedTrackSizes(tracks.mSizes, parent, parentSizes, mFrame, subgrid,
4239 aAxis);
4240 useParentGaps = gapStyle.IsNormal();
4241 } else {
4242 fallbackTrackSizing.emplace(TrackSizingFunctions::ForSubgridFallback(
4243 mFrame, subgrid, parent, parentAxis));
4244 tracks.Initialize(*fallbackTrackSizing, gapStyle, gridEnd,
4245 aContentBoxSize);
4246 }
4247 }
4248
4249 // We run the Track Sizing Algorithm in non-subgridded axes, and in some
4250 // cases in a subgridded axis when our parent track sizes aren't resolved yet.
4251 if (MOZ_LIKELY(!isSubgriddedAxis)(__builtin_expect(!!(!isSubgriddedAxis), 1)) || fallbackTrackSizing.isSome()) {
4252 const size_t origGridItemCount = mGridItems.Length();
4253 const bool hasSubgridItems = mFrame->HasSubgridItems(aAxis);
4254 if (hasSubgridItems) {
4255 AutoTArray<GridItemInfo, 8> collectedItems;
4256 CollectSubgridItemsForAxis(aAxis, collectedItems);
4257 mGridItems.AppendElements(collectedItems);
4258 }
4259 tracks.CalculateSizes(
4260 *this, mGridItems,
4261 fallbackTrackSizing ? *fallbackTrackSizing : sizingFunctions,
4262 aContentBoxSize,
4263 aAxis == LogicalAxis::Inline ? &GridArea::mCols : &GridArea::mRows,
4264 aConstraint);
4265
4266 if (hasSubgridItems &&
4267 StaticPrefs::layout_css_grid_subgrid_baselines_enabled()) {
4268 // If any of the subgrid items are baseline-aligned, we've just recorded
4269 // their baseline-alignment offsets in our own copy of their GridItemInfo
4270 // structs. Before we get rid of those copies (via TruncateLength), we
4271 // have to copy these offsets back to the subgrids' versions of the
4272 // GridItemInfo structs.
4273 //
4274 // XXXdholbert This new behavior is behind a pref due to bug 1871719.
4275 CopyBaselineMetricsToSubgridItems(aAxis, origGridItemCount);
4276 }
4277 mGridItems.TruncateLength(origGridItemCount);
4278 }
4279 if (isSubgriddedAxis) {
4280 // XXXdholbert This is a bit hacky, but this is something that
4281 // tracks.CalculateSizes does internally (unconditionally, if there are
4282 // baseline-aligned items), and it seems like subgrids need to do it too,
4283 // or else they hit the "unexpected baseline subtree alignment"
4284 // fatal-assert when aligning their children with the baseline-alignment
4285 // information that they received from the outer grid.
4286 // (This might be entirely unnecessary? Aside from the default ::AUTO
4287 // value, it looks like the ::First entry is always set to ::START and
4288 // the ::Last entry is always set to ::END...)
4289 tracks.mBaselineSubtreeAlign[BaselineSharingGroup::First] =
4290 StyleAlignFlags::START;
4291 tracks.mBaselineSubtreeAlign[BaselineSharingGroup::Last] =
4292 StyleAlignFlags::END;
4293 }
4294
4295 if (aContentBoxSize != NS_UNCONSTRAINEDSIZE) {
4296 auto alignment = mGridStyle->UsedContentAlignment(tracks.mAxis);
4297 tracks.AlignJustifyContent(mGridStyle, alignment, mWM, aContentBoxSize,
4298 isSubgriddedAxis);
4299 } else if (!useParentGaps) {
4300 const nscoord gridGap = tracks.mGridGap;
4301 nscoord pos = 0;
4302 for (TrackSize& sz : tracks.mSizes) {
4303 sz.mPosition = pos;
4304 pos += sz.mBase + gridGap;
4305 }
4306 }
4307
4308 if (aConstraint == SizingConstraint::NoConstraint &&
4309 (mFrame->HasSubgridItems() || mFrame->IsSubgrid())) {
4310 mFrame->StoreUsedTrackSizes(aAxis, tracks.mSizes);
4311 }
4312
4313 // positions and sizes are now final
4314 tracks.mCanResolveLineRangeSize = true;
4315}
4316
4317void nsGridContainerFrame::GridReflowInput::InvalidateTrackSizesForAxis(
4318 LogicalAxis aAxis) {
4319 for (auto& item : mGridItems) {
4320 item.ResetTrackSizingBits(aAxis);
4321 }
4322 TracksFor(aAxis).mCanResolveLineRangeSize = false;
4323}
4324
4325// Align an item's margin box in its aAxis inside aCBSize.
4326static void AlignJustifySelf(StyleAlignFlags aAlignment, LogicalAxis aAxis,
4327 AlignJustifyFlags aFlags, nscoord aBaselineAdjust,
4328 nscoord aCBSize, const ReflowInput& aRI,
4329 const LogicalSize& aChildSize,
4330 LogicalPoint* aPos) {
4331 MOZ_ASSERT(aAlignment != StyleAlignFlags::AUTO,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAlignment != StyleAlignFlags::AUTO)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAlignment != StyleAlignFlags
::AUTO))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAlignment != StyleAlignFlags::AUTO" " (" "unexpected 'auto' "
"computed value for normal flow grid item" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4332 "unexpected 'auto' "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAlignment != StyleAlignFlags::AUTO)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAlignment != StyleAlignFlags
::AUTO))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAlignment != StyleAlignFlags::AUTO" " (" "unexpected 'auto' "
"computed value for normal flow grid item" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4333 "computed value for normal flow grid item")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAlignment != StyleAlignFlags::AUTO)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAlignment != StyleAlignFlags
::AUTO))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAlignment != StyleAlignFlags::AUTO" " (" "unexpected 'auto' "
"computed value for normal flow grid item" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4334
4335 // NOTE: this is the resulting frame offset (border box).
4336 nscoord offset = CSSAlignUtils::AlignJustifySelf(
4337 aAlignment, aAxis, aFlags, aBaselineAdjust, aCBSize, aRI, aChildSize);
4338
4339 // Set the position (aPos) for the requested alignment.
4340 if (offset != 0) {
4341 WritingMode wm = aRI.GetWritingMode();
4342 nscoord& pos = aAxis == LogicalAxis::Block ? aPos->B(wm) : aPos->I(wm);
4343 pos += MOZ_LIKELY(aFlags.contains(AlignJustifyFlag::SameSide))(__builtin_expect(!!(aFlags.contains(AlignJustifyFlag::SameSide
)), 1))
? offset
4344 : -offset;
4345 }
4346}
4347
4348static void AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
4349 StyleAlignFlags aAlignSelf, nscoord aCBSize,
4350 const WritingMode aCBWM, const ReflowInput& aRI,
4351 const LogicalSize& aSize, AlignJustifyFlags aFlags,
4352 LogicalPoint* aPos) {
4353 AlignJustifyFlags flags = aFlags;
4354 if (aAlignSelf & StyleAlignFlags::SAFE) {
4355 flags += AlignJustifyFlag::OverflowSafe;
4356 }
4357 aAlignSelf &= ~StyleAlignFlags::FLAG_BITS;
4358
4359 WritingMode childWM = aRI.GetWritingMode();
4360 if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, childWM)) {
4361 flags += AlignJustifyFlag::SameSide;
4362 }
4363
4364 if (aGridItem.mState[LogicalAxis::Block] &
4365 GridItemInfo::eLastBaselineSharingGroup) {
4366 flags += AlignJustifyFlag::LastBaselineSharingGroup;
4367 }
4368
4369 // Grid's 'align-self' axis is never parallel to the container's inline axis.
4370 if (aAlignSelf == StyleAlignFlags::LEFT ||
4371 aAlignSelf == StyleAlignFlags::RIGHT) {
4372 aAlignSelf = StyleAlignFlags::START;
4373 }
4374 if (MOZ_LIKELY(aAlignSelf == StyleAlignFlags::NORMAL)(__builtin_expect(!!(aAlignSelf == StyleAlignFlags::NORMAL), 1
))
) {
4375 aAlignSelf = StyleAlignFlags::STRETCH;
4376 }
4377
4378 nscoord baselineAdjust = 0;
4379 if (aAlignSelf == StyleAlignFlags::BASELINE ||
4380 aAlignSelf == StyleAlignFlags::LAST_BASELINE) {
4381 aAlignSelf = aGridItem.GetSelfBaseline(aAlignSelf, LogicalAxis::Block,
4382 &baselineAdjust);
4383 }
4384
4385 const auto bAxisInChildWM = aCBWM.ConvertAxisTo(LogicalAxis::Block, childWM);
4386 AlignJustifySelf(aAlignSelf, bAxisInChildWM, flags, baselineAdjust, aCBSize,
4387 aRI, aSize, aPos);
4388}
4389
4390static void JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
4391 StyleAlignFlags aJustifySelf, nscoord aCBSize,
4392 const WritingMode aCBWM, const ReflowInput& aRI,
4393 const LogicalSize& aSize, AlignJustifyFlags aFlags,
4394 LogicalPoint* aPos) {
4395 AlignJustifyFlags flags = aFlags;
4396 if (aJustifySelf & StyleAlignFlags::SAFE) {
4397 flags += AlignJustifyFlag::OverflowSafe;
4398 }
4399 aJustifySelf &= ~StyleAlignFlags::FLAG_BITS;
4400
4401 WritingMode childWM = aRI.GetWritingMode();
4402 if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, childWM)) {
4403 flags += AlignJustifyFlag::SameSide;
4404 }
4405
4406 if (aGridItem.mState[LogicalAxis::Inline] &
4407 GridItemInfo::eLastBaselineSharingGroup) {
4408 flags += AlignJustifyFlag::LastBaselineSharingGroup;
4409 }
4410
4411 if (MOZ_LIKELY(aJustifySelf == StyleAlignFlags::NORMAL)(__builtin_expect(!!(aJustifySelf == StyleAlignFlags::NORMAL)
, 1))
) {
4412 aJustifySelf = StyleAlignFlags::STRETCH;
4413 }
4414
4415 nscoord baselineAdjust = 0;
4416 // Grid's 'justify-self' axis is always parallel to the container's inline
4417 // axis, so justify-self:left|right always applies.
4418 if (aJustifySelf == StyleAlignFlags::LEFT) {
4419 aJustifySelf =
4420 aCBWM.IsBidiLTR() ? StyleAlignFlags::START : StyleAlignFlags::END;
4421 } else if (aJustifySelf == StyleAlignFlags::RIGHT) {
4422 aJustifySelf =
4423 aCBWM.IsBidiLTR() ? StyleAlignFlags::END : StyleAlignFlags::START;
4424 } else if (aJustifySelf == StyleAlignFlags::BASELINE ||
4425 aJustifySelf == StyleAlignFlags::LAST_BASELINE) {
4426 aJustifySelf = aGridItem.GetSelfBaseline(aJustifySelf, LogicalAxis::Inline,
4427 &baselineAdjust);
4428 }
4429
4430 const auto iAxisInChildWM = aCBWM.ConvertAxisTo(LogicalAxis::Inline, childWM);
4431 AlignJustifySelf(aJustifySelf, iAxisInChildWM, flags, baselineAdjust, aCBSize,
4432 aRI, aSize, aPos);
4433}
4434
4435static StyleAlignFlags GetAlignJustifyValue(StyleAlignFlags aAlignment,
4436 const WritingMode aWM,
4437 const bool aIsAlign,
4438 bool* aOverflowSafe) {
4439 *aOverflowSafe = bool(aAlignment & StyleAlignFlags::SAFE);
4440 aAlignment &= ~StyleAlignFlags::FLAG_BITS;
4441
4442 // Map some alignment values to 'start' / 'end'.
4443 if (aAlignment == StyleAlignFlags::LEFT ||
4444 aAlignment == StyleAlignFlags::RIGHT) {
4445 if (aIsAlign) {
4446 // Grid's 'align-content' axis is never parallel to the inline axis.
4447 return StyleAlignFlags::START;
4448 }
4449 bool isStart = aWM.IsBidiLTR() == (aAlignment == StyleAlignFlags::LEFT);
4450 return isStart ? StyleAlignFlags::START : StyleAlignFlags::END;
4451 }
4452 if (aAlignment == StyleAlignFlags::FLEX_START) {
4453 return StyleAlignFlags::START; // same as 'start' for Grid
4454 }
4455 if (aAlignment == StyleAlignFlags::FLEX_END) {
4456 return StyleAlignFlags::END; // same as 'end' for Grid
4457 }
4458 return aAlignment;
4459}
4460
4461static Maybe<StyleAlignFlags> GetAlignJustifyDistributionFallback(
4462 const StyleContentDistribution& aDistribution, bool* aOverflowSafe) {
4463 // See "4.3. Distributed Alignment" for the default fallback alignment values:
4464 // https://drafts.csswg.org/css-align-3/#distribution-values
4465 //
4466 // TODO: Extend this function to handle explicitly specified fallback
4467 // alignment once the CSS Alignment Module introduces that syntax:
4468 // https://github.com/w3c/csswg-drafts/issues/1002.
4469 if (aDistribution.primary == StyleAlignFlags::SPACE_BETWEEN) {
4470 *aOverflowSafe = true;
4471 return Some(StyleAlignFlags::START);
4472 }
4473 if (aDistribution.primary == StyleAlignFlags::SPACE_AROUND ||
4474 aDistribution.primary == StyleAlignFlags::SPACE_EVENLY) {
4475 *aOverflowSafe = true;
4476 return Some(StyleAlignFlags::CENTER);
4477 }
4478 if (aDistribution.primary == StyleAlignFlags::STRETCH) {
4479 *aOverflowSafe = false;
4480 return Some(StyleAlignFlags::START);
4481 }
4482 return Nothing();
4483}
4484
4485//----------------------------------------------------------------------
4486
4487// Frame class boilerplate
4488// =======================
4489
4490NS_QUERYFRAME_HEAD(nsGridContainerFrame)void* nsGridContainerFrame ::QueryFrame(FrameIID id) const { switch
(id) {
4491 NS_QUERYFRAME_ENTRY(nsGridContainerFrame)case nsGridContainerFrame ::kFrameIID: { static_assert( std::
is_same_v<nsGridContainerFrame, nsGridContainerFrame ::Has_NS_DECL_QUERYFRAME_TARGET
>, "nsGridContainerFrame" " must declare itself as a queryframe target"
); return const_cast<nsGridContainerFrame*>(static_cast
<const nsGridContainerFrame*>(this)); }
4492NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)default: break; } return nsContainerFrame ::QueryFrame(id); }
4493
4494NS_IMPL_FRAMEARENA_HELPERS(nsGridContainerFrame)void* nsGridContainerFrame ::operator new(size_t sz, mozilla::
PresShell * aShell) { return aShell->AllocateFrame(nsQueryFrame
::nsGridContainerFrame_id, sz); }
4495
4496nsContainerFrame* NS_NewGridContainerFrame(PresShell* aPresShell,
4497 ComputedStyle* aStyle) {
4498 return new (aPresShell)
4499 nsGridContainerFrame(aStyle, aPresShell->GetPresContext());
4500}
4501
4502//----------------------------------------------------------------------
4503
4504// nsGridContainerFrame Method Implementations
4505// ===========================================
4506
4507/*static*/ const nsRect& nsGridContainerFrame::GridItemCB(nsIFrame* aChild) {
4508 MOZ_ASSERT(aChild->IsAbsolutelyPositioned())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->IsAbsolutelyPositioned())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChild->IsAbsolutelyPositioned
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->IsAbsolutelyPositioned()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsAbsolutelyPositioned()"
")"); do { MOZ_CrashSequence(__null, 4508); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4509 nsRect* cb = aChild->GetProperty(GridItemContainingBlockRect());
4510 MOZ_ASSERT(cb,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cb)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(cb))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("cb" " (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4512
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cb" ") (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")"); do { MOZ_CrashSequence(__null, 4512); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4511 "this method must only be called on grid items, and the grid "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cb)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(cb))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("cb" " (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4512
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cb" ") (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")"); do { MOZ_CrashSequence(__null, 4512); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4512 "container should've reflowed this item by now and set up cb")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cb)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(cb))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("cb" " (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4512
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cb" ") (" "this method must only be called on grid items, and the grid "
"container should've reflowed this item by now and set up cb"
")"); do { MOZ_CrashSequence(__null, 4512); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4513 return *cb;
4514}
4515
4516void nsGridContainerFrame::AddImplicitNamedAreasInternal(
4517 LineNameList& aNameList,
4518 nsGridContainerFrame::ImplicitNamedAreas*& aAreas) {
4519 for (const auto& nameIdent : aNameList.AsSpan()) {
4520 nsAtom* name = nameIdent.AsAtom();
4521 uint32_t indexOfSuffix;
4522 if (Grid::IsNameWithStartSuffix(name, &indexOfSuffix) ||
4523 Grid::IsNameWithEndSuffix(name, &indexOfSuffix)) {
4524 // Extract the name that was found earlier.
4525 nsDependentSubstring areaName(nsDependentAtomString(name), 0,
4526 indexOfSuffix);
4527
4528 // Lazily create the ImplicitNamedAreas.
4529 if (!aAreas) {
4530 aAreas = new nsGridContainerFrame::ImplicitNamedAreas;
4531 SetProperty(nsGridContainerFrame::ImplicitNamedAreasProperty(), aAreas);
4532 }
4533
4534 RefPtr<nsAtom> name = NS_Atomize(areaName);
4535 auto addPtr = aAreas->lookupForAdd(name);
4536 if (!addPtr) {
4537 if (!aAreas->add(addPtr, name,
4538 nsGridContainerFrame::NamedArea{
4539 StyleAtom(do_AddRef(name)), {0, 0}, {0, 0}})) {
4540 MOZ_CRASH("OOM while adding grid name lists")do { do { } while (false); MOZ_ReportCrash("" "OOM while adding grid name lists"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4540)
; AnnotateMozCrashReason("MOZ_CRASH(" "OOM while adding grid name lists"
")"); do { MOZ_CrashSequence(__null, 4540); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4541 }
4542 }
4543 }
4544 }
4545}
4546
4547void nsGridContainerFrame::AddImplicitNamedAreas(
4548 Span<LineNameList> aLineNameLists) {
4549 // https://drafts.csswg.org/css-grid-2/#implicit-named-areas
4550 // Note: recording these names for fast lookup later is just an optimization.
4551 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4552 const uint32_t len = std::min(aLineNameLists.Length(), size_t(kMaxLine));
4553 for (uint32_t i = 0; i < len; ++i) {
4554 AddImplicitNamedAreasInternal(aLineNameLists[i], areas);
4555 }
4556}
4557
4558void nsGridContainerFrame::AddImplicitNamedAreas(
4559 Span<StyleLineNameListValue> aLineNameList) {
4560 // https://drafts.csswg.org/css-grid-2/#implicit-named-areas
4561 // Note: recording these names for fast lookup later is just an optimization.
4562 uint32_t count = 0;
4563 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4564 for (const auto& nameList : aLineNameList) {
4565 if (nameList.IsRepeat()) {
4566 for (const auto& repeatNameList :
4567 nameList.AsRepeat().line_names.AsSpan()) {
4568 AddImplicitNamedAreasInternal(repeatNameList, areas);
4569 ++count;
4570 }
4571 } else {
4572 MOZ_ASSERT(nameList.IsLineNames())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nameList.IsLineNames())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nameList.IsLineNames()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("nameList.IsLineNames()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4572)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "nameList.IsLineNames()"
")"); do { MOZ_CrashSequence(__null, 4572); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4573 AddImplicitNamedAreasInternal(nameList.AsLineNames(), areas);
4574 ++count;
4575 }
4576
4577 if (count >= size_t(kMaxLine)) {
4578 break;
4579 }
4580 }
4581}
4582
4583void nsGridContainerFrame::InitImplicitNamedAreas(
4584 const nsStylePosition* aStyle) {
4585 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4586 if (areas) {
4587 // Clear it, but reuse the hashtable itself for now. We'll remove it
4588 // below if it isn't needed anymore.
4589 areas->clear();
4590 }
4591 auto Add = [&](const GridTemplate& aTemplate, bool aIsSubgrid) {
4592 AddImplicitNamedAreas(aTemplate.LineNameLists());
4593 for (auto& value : aTemplate.TrackListValues()) {
4594 if (value.IsTrackRepeat()) {
4595 AddImplicitNamedAreas(value.AsTrackRepeat().line_names.AsSpan());
4596 }
4597 }
4598
4599 if (aIsSubgrid && aTemplate.IsSubgrid()) {
4600 // For subgrid, |aTemplate.LineNameLists(aIsSubgrid)| returns an empty
4601 // list so we have to manually add each item.
4602 AddImplicitNamedAreas(aTemplate.AsSubgrid()->line_names.AsSpan());
4603 }
4604 };
4605 Add(aStyle->mGridTemplateColumns, IsColSubgrid());
4606 Add(aStyle->mGridTemplateRows, IsRowSubgrid());
4607 if (areas && areas->count() == 0) {
4608 RemoveProperty(ImplicitNamedAreasProperty());
4609 }
4610}
4611
4612int32_t nsGridContainerFrame::Grid::ResolveLine(
4613 const StyleGridLine& aLine, int32_t aNth, uint32_t aFromIndex,
4614 const LineNameMap& aNameMap, LogicalSide aSide, uint32_t aExplicitGridEnd,
4615 const nsStylePosition* aStyle) {
4616 MOZ_ASSERT(!aLine.IsAuto())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aLine.IsAuto())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aLine.IsAuto()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aLine.IsAuto()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4616)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLine.IsAuto()" ")"
); do { MOZ_CrashSequence(__null, 4616); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4617 aNth = std::clamp(aNth, kMinLine, kMaxLine);
4618 int32_t line = 0;
4619 if (aLine.LineName()->IsEmpty()) {
4620 MOZ_ASSERT(aNth != 0, "css-grid 9.2: <integer> must not be zero.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNth != 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNth != 0" " (" "css-grid 9.2: <integer> must not be zero."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4620
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth != 0" ") (" "css-grid 9.2: <integer> must not be zero."
")"); do { MOZ_CrashSequence(__null, 4620); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4621 line = int32_t(aFromIndex) + aNth;
4622 } else {
4623 if (aNth == 0) {
4624 // <integer> was omitted; treat it as 1.
4625 aNth = 1;
4626 }
4627 bool isNameOnly = !aLine.is_span && aLine.line_num == 0;
4628 if (isNameOnly) {
4629 AutoTArray<uint32_t, 16> implicitLines;
4630 aNameMap.FindNamedAreas(aLine.ident.AsAtom(), aSide, implicitLines);
4631 if (!implicitLines.IsEmpty() ||
4632 aNameMap.HasImplicitNamedArea(aLine.LineName())) {
4633 // aName is a named area - look for explicit lines named
4634 // <name>-start/-end depending on which side we're resolving.
4635 // https://drafts.csswg.org/css-grid-2/#grid-placement-slot
4636 nsAutoString lineName(nsDependentAtomString(aLine.LineName()));
4637 if (IsStart(aSide)) {
4638 lineName.AppendLiteral("-start");
4639 } else {
4640 lineName.AppendLiteral("-end");
4641 }
4642 RefPtr<nsAtom> name = NS_Atomize(lineName);
4643 line = aNameMap.FindNamedLine(name, &aNth, aFromIndex, implicitLines);
4644 }
4645 }
4646
4647 if (line == 0) {
4648 // If LineName() ends in -start/-end, try the prefix as a named area.
4649 AutoTArray<uint32_t, 16> implicitLines;
4650 uint32_t index;
4651 bool useStart = IsNameWithStartSuffix(aLine.LineName(), &index);
4652 if (useStart || IsNameWithEndSuffix(aLine.LineName(), &index)) {
4653 auto side = MakeLogicalSide(
4654 GetAxis(aSide), useStart ? LogicalEdge::Start : LogicalEdge::End);
4655 RefPtr<nsAtom> name = NS_Atomize(nsDependentSubstring(
4656 nsDependentAtomString(aLine.LineName()), 0, index));
4657 aNameMap.FindNamedAreas(name, side, implicitLines);
4658 }
4659 line = aNameMap.FindNamedLine(aLine.LineName(), &aNth, aFromIndex,
4660 implicitLines);
4661 }
4662
4663 if (line == 0) {
4664 MOZ_ASSERT(aNth != 0, "we found all N named lines but 'line' is zero!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNth != 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNth != 0" " (" "we found all N named lines but 'line' is zero!"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4664
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth != 0" ") (" "we found all N named lines but 'line' is zero!"
")"); do { MOZ_CrashSequence(__null, 4664); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4665 int32_t edgeLine;
4666 if (aLine.is_span) {
4667 // https://drafts.csswg.org/css-grid-2/#grid-placement-span-int
4668 // 'span <custom-ident> N'
4669 edgeLine = IsStart(aSide) ? 1 : aExplicitGridEnd;
4670 } else {
4671 // https://drafts.csswg.org/css-grid-2/#grid-placement-int
4672 // '<custom-ident> N'
4673 edgeLine = aNth < 0 ? 1 : aExplicitGridEnd;
4674 }
4675 // "If not enough lines with that name exist, all lines in the implicit
4676 // grid are assumed to have that name..."
4677 line = edgeLine + aNth;
4678 }
4679 }
4680 // Note: at this point, 'line' might be outside of aNameMap's allowed range,
4681 // [mClampMinLin, mClampMaxLine]. This is fine; we'll clamp once we've
4682 // resolved *both* the start and end line -- in particular, we clamp in
4683 // ResolveLineRange(). If we clamped here, it'd be premature -- if one line
4684 // is definite and the other is specified as a span to some named line
4685 // (i.e. we need to perform a name-search that starts from the definite
4686 // line), then it matters whether we clamp the definite line before or after
4687 // that search. See https://bugzilla.mozilla.org/show_bug.cgi?id=1800566#c6
4688 // for more.
4689 return line;
4690}
4691
4692nsGridContainerFrame::Grid::LinePair
4693nsGridContainerFrame::Grid::ResolveLineRangeHelper(
4694 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4695 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4696 const nsStylePosition* aStyle) {
4697 MOZ_ASSERT(int32_t(kAutoLine) > kMaxLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(kAutoLine) > kMaxLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(kAutoLine) > kMaxLine
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"int32_t(kAutoLine) > kMaxLine", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(kAutoLine) > kMaxLine"
")"); do { MOZ_CrashSequence(__null, 4697); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4698 auto startNum = std::clamp(aStart.line_num, kMinLine, kMaxLine);
4699 auto endNum = std::clamp(aEnd.line_num, kMinLine, kMaxLine);
4700
4701 if (aStart.is_span) {
4702 if (aEnd.is_span || aEnd.IsAuto()) {
4703 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4704 if (aStart.LineName()->IsEmpty()) {
4705 // span <integer> / span *
4706 // span <integer> / auto
4707 return LinePair(kAutoLine, startNum);
4708 }
4709 // span <custom-ident> / span *
4710 // span <custom-ident> / auto
4711 return LinePair(kAutoLine, 1); // XXX subgrid explicit size instead of 1?
4712 }
4713
4714 uint32_t from = endNum < 0 ? aExplicitGridEnd + 1 : 0;
4715 auto end = ResolveLine(aEnd, endNum, from, aNameMap,
4716 MakeLogicalSide(aAxis, LogicalEdge::End),
4717 aExplicitGridEnd, aStyle);
4718 int32_t span = startNum == 0 ? 1 : startNum;
4719 if (end <= 1) {
4720 // The end is at or before the first explicit line, thus all lines before
4721 // it match <custom-ident> since they're implicit.
4722 int32_t start = std::max(end - span, aNameMap.mClampMinLine);
4723 return LinePair(start, end);
4724 }
4725 auto start = ResolveLine(aStart, -span, end, aNameMap,
4726 MakeLogicalSide(aAxis, LogicalEdge::Start),
4727 aExplicitGridEnd, aStyle);
4728 return LinePair(start, end);
4729 }
4730
4731 int32_t start = kAutoLine;
4732 if (aStart.IsAuto()) {
4733 if (aEnd.IsAuto()) {
4734 // auto / auto
4735 return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
4736 }
4737 if (aEnd.is_span) {
4738 if (aEnd.LineName()->IsEmpty()) {
4739 // auto / span <integer>
4740 MOZ_ASSERT(endNum != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(endNum != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(endNum != 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("endNum != 0", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "endNum != 0"
")"); do { MOZ_CrashSequence(__null, 4740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4741 return LinePair(start, endNum);
4742 }
4743 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4744 // auto / span <custom-ident>
4745 return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
4746 }
4747 } else {
4748 uint32_t from = startNum < 0 ? aExplicitGridEnd + 1 : 0;
4749 start = ResolveLine(aStart, startNum, from, aNameMap,
4750 MakeLogicalSide(aAxis, LogicalEdge::Start),
4751 aExplicitGridEnd, aStyle);
4752 if (aEnd.IsAuto()) {
4753 // A "definite line / auto" should resolve the auto to 'span 1'.
4754 // The error handling in ResolveLineRange will make that happen and also
4755 // clamp the end line correctly if we return "start / start".
4756 return LinePair(start, start);
4757 }
4758 }
4759
4760 uint32_t from;
4761 int32_t nth = endNum == 0 ? 1 : endNum;
4762 if (aEnd.is_span) {
4763 if (MOZ_UNLIKELY(start < 0)(__builtin_expect(!!(start < 0), 0))) {
4764 if (aEnd.LineName()->IsEmpty()) {
4765 return LinePair(start, start + nth);
4766 }
4767 from = 0;
4768 } else {
4769 if (start >= int32_t(aExplicitGridEnd)) {
4770 // The start is at or after the last explicit line, thus all lines
4771 // after it match <custom-ident> since they're implicit.
4772 return LinePair(start, std::min(start + nth, aNameMap.mClampMaxLine));
4773 }
4774 from = start;
4775 }
4776 } else {
4777 from = endNum < 0 ? aExplicitGridEnd + 1 : 0;
4778 }
4779 auto end = ResolveLine(aEnd, nth, from, aNameMap,
4780 MakeLogicalSide(aAxis, LogicalEdge::End),
4781 aExplicitGridEnd, aStyle);
4782 if (start == int32_t(kAutoLine)) {
4783 // auto / definite line
4784 start = std::max(aNameMap.mClampMinLine, end - 1);
4785 }
4786 return LinePair(start, end);
4787}
4788
4789nsGridContainerFrame::LineRange nsGridContainerFrame::Grid::ResolveLineRange(
4790 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4791 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4792 const nsStylePosition* aStyle) {
4793 LinePair r = ResolveLineRangeHelper(aStart, aEnd, aNameMap, aAxis,
4794 aExplicitGridEnd, aStyle);
4795 MOZ_ASSERT(r.second != int32_t(kAutoLine))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(r.second != int32_t(kAutoLine))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(r.second != int32_t(kAutoLine
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("r.second != int32_t(kAutoLine)", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 4795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r.second != int32_t(kAutoLine)"
")"); do { MOZ_CrashSequence(__null, 4795); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4796
4797 if (r.first == int32_t(kAutoLine)) {
4798 // r.second is a span, clamp it to aNameMap.mClampMaxLine - 1 so that
4799 // the returned range has a HypotheticalEnd <= aNameMap.mClampMaxLine.
4800 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
4801 r.second = std::min(r.second, aNameMap.mClampMaxLine - 1);
4802 } else {
4803 // Clamp the lines to be within our limits, per
4804 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
4805 // Note that our limits here might come from the [kMinLine, kMaxLine]
4806 // extremes; or, they might just be the bounds of a subgrid's explicit
4807 // grid. We use the same clamping approach either way, per
4808 // https://drafts.csswg.org/css-grid-2/#subgrid-implicit ("using the same
4809 // procedure as for clamping placement in an overly-large grid").
4810 //
4811 // Note that these two clamped assignments might collapse our range to
4812 // have both edges pointing at the same line (spanning 0 tracks); this
4813 // might happen here if e.g. r.first were mClampMaxLine, and r.second gets
4814 // clamped from some higher number down to mClampMaxLine. We'll handle this
4815 // by shifting the inner line (r.first in this hypothetical) inwards by 1,
4816 // in the #grid-placement-errors section; that achieves the outcome of
4817 // the #overlarge-grids clamping spec text that says "its span must be
4818 // truncated to 1" when clamping an item that was completely outside the
4819 // limits.
4820 r.first =
4821 std::clamp(r.first, aNameMap.mClampMinLine, aNameMap.mClampMaxLine);
4822 r.second =
4823 std::clamp(r.second, aNameMap.mClampMinLine, aNameMap.mClampMaxLine);
4824
4825 // Handle grid placement errors.
4826 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4827 if (r.first > r.second) {
4828 std::swap(r.first, r.second);
4829 } else if (r.first == r.second) {
4830 // (This is #grid-placement-errors fixup, but it's also where we ensure
4831 // that any #overlarge-grids fixup that we did above will end up
4832 // truncating the range to a span of 1 rather than 0 -- i.e. sliding
4833 // inwards if needed.)
4834 if (MOZ_UNLIKELY(r.first == aNameMap.mClampMaxLine)(__builtin_expect(!!(r.first == aNameMap.mClampMaxLine), 0))) {
4835 r.first = aNameMap.mClampMaxLine - 1;
4836 }
4837 r.second = r.first + 1;
4838 }
4839 }
4840 return LineRange(r.first, r.second);
4841}
4842
4843nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceDefinite(
4844 nsIFrame* aChild, const LineNameMap& aColLineNameMap,
4845 const LineNameMap& aRowLineNameMap, const nsStylePosition* aStyle) {
4846 const nsStylePosition* itemStyle = aChild->StylePosition();
4847 return GridArea(
4848 ResolveLineRange(itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
4849 aColLineNameMap, LogicalAxis::Inline,
4850 mExplicitGridColEnd, aStyle),
4851 ResolveLineRange(itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
4852 aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
4853 aStyle));
4854}
4855
4856nsGridContainerFrame::LineRange
4857nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
4858 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4859 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4860 int32_t aGridStart, int32_t aGridEnd, const nsStylePosition* aStyle) {
4861 if (aStart.IsAuto()) {
4862 if (aEnd.IsAuto()) {
4863 return LineRange(kAutoLine, kAutoLine);
4864 }
4865 uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0;
4866 int32_t end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap,
4867 MakeLogicalSide(aAxis, LogicalEdge::End),
4868 aExplicitGridEnd, aStyle);
4869 if (aEnd.is_span) {
4870 ++end;
4871 }
4872 // A line outside the existing grid is treated as 'auto' for abs.pos (10.1).
4873 end = AutoIfOutside(end, aGridStart, aGridEnd);
4874 return LineRange(kAutoLine, end);
4875 }
4876
4877 if (aEnd.IsAuto()) {
4878 uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0;
4879 int32_t start = ResolveLine(aStart, aStart.line_num, from, aNameMap,
4880 MakeLogicalSide(aAxis, LogicalEdge::Start),
4881 aExplicitGridEnd, aStyle);
4882 if (aStart.is_span) {
4883 start = std::max(aGridEnd - start, aGridStart);
4884 }
4885 start = AutoIfOutside(start, aGridStart, aGridEnd);
4886 return LineRange(start, kAutoLine);
4887 }
4888
4889 LineRange r =
4890 ResolveLineRange(aStart, aEnd, aNameMap, aAxis, aExplicitGridEnd, aStyle);
4891 if (r.IsAuto()) {
4892 MOZ_ASSERT(aStart.is_span && aEnd.is_span,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart.is_span && aEnd.is_span)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStart.is_span && aEnd.is_span))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStart.is_span && aEnd.is_span"
" (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4894
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart.is_span && aEnd.is_span"
") (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")"); do { MOZ_CrashSequence(__null, 4894); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4893 "span / span is the only case "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart.is_span && aEnd.is_span)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStart.is_span && aEnd.is_span))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStart.is_span && aEnd.is_span"
" (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4894
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart.is_span && aEnd.is_span"
") (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")"); do { MOZ_CrashSequence(__null, 4894); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4894 "leading to IsAuto here -- we dealt with the other cases above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStart.is_span && aEnd.is_span)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStart.is_span && aEnd.is_span))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStart.is_span && aEnd.is_span"
" (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 4894
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart.is_span && aEnd.is_span"
") (" "span / span is the only case " "leading to IsAuto here -- we dealt with the other cases above"
")"); do { MOZ_CrashSequence(__null, 4894); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4895 // The second span was ignored per 9.2.1. For abs.pos., 10.1 says that this
4896 // case should result in "auto / auto" unlike normal flow grid items.
4897 return LineRange(kAutoLine, kAutoLine);
4898 }
4899
4900 return LineRange(AutoIfOutside(r.mUntranslatedStart, aGridStart, aGridEnd),
4901 AutoIfOutside(r.mUntranslatedEnd, aGridStart, aGridEnd));
4902}
4903
4904nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceAbsPos(
4905 nsIFrame* aChild, const LineNameMap& aColLineNameMap,
4906 const LineNameMap& aRowLineNameMap, const nsStylePosition* aStyle) {
4907 const nsStylePosition* itemStyle = aChild->StylePosition();
4908 int32_t gridColStart = 1 - mExplicitGridOffsetCol;
4909 int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
4910 return GridArea(ResolveAbsPosLineRange(
4911 itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
4912 aColLineNameMap, LogicalAxis::Inline, mExplicitGridColEnd,
4913 gridColStart, mGridColEnd, aStyle),
4914 ResolveAbsPosLineRange(
4915 itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
4916 aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
4917 gridRowStart, mGridRowEnd, aStyle));
4918}
4919
4920uint32_t nsGridContainerFrame::Grid::FindAutoCol(uint32_t aStartCol,
4921 uint32_t aLockedRow,
4922 const GridArea* aArea) const {
4923 const uint32_t extent = aArea->mCols.Extent();
4924 const uint32_t iStart = aLockedRow;
4925 const uint32_t iEnd = iStart + aArea->mRows.Extent();
4926 uint32_t candidate = aStartCol;
4927 for (uint32_t i = iStart; i < iEnd;) {
4928 if (i >= mCellMap.mCells.Length()) {
4929 break;
4930 }
4931 const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
4932 const uint32_t len = cellsInRow.Length();
4933 const uint32_t lastCandidate = candidate;
4934 // Find the first gap in the current row that's at least 'extent' wide.
4935 // ('gap' tracks how wide the current column gap is.)
4936 for (uint32_t j = candidate, gap = 0; j < len && gap < extent; ++j) {
4937 if (!cellsInRow[j].mIsOccupied) {
4938 ++gap;
4939 continue;
4940 }
4941 candidate = j + 1;
4942 gap = 0;
4943 }
4944 if (lastCandidate < candidate && i != iStart) {
4945 // Couldn't fit 'extent' tracks at 'lastCandidate' here so we must
4946 // restart from the beginning with the new 'candidate'.
4947 i = iStart;
4948 } else {
4949 ++i;
4950 }
4951 }
4952 return candidate;
4953}
4954
4955void nsGridContainerFrame::Grid::PlaceAutoCol(uint32_t aStartCol,
4956 GridArea* aArea,
4957 uint32_t aClampMaxColLine) const {
4958 MOZ_ASSERT(aArea->mRows.IsDefinite() && aArea->mCols.IsAuto())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->mRows.IsDefinite() && aArea->mCols
.IsAuto())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aArea->mRows.IsDefinite() &&
aArea->mCols.IsAuto()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aArea->mRows.IsDefinite() && aArea->mCols.IsAuto()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4958)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mRows.IsDefinite() && aArea->mCols.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 4958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4959 uint32_t col = FindAutoCol(aStartCol, aArea->mRows.mStart, aArea);
4960 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
4961 MOZ_ASSERT(aArea->IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea->IsDefinite()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aArea->IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4961)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 4961); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4962}
4963
4964uint32_t nsGridContainerFrame::Grid::FindAutoRow(uint32_t aLockedCol,
4965 uint32_t aStartRow,
4966 const GridArea* aArea) const {
4967 const uint32_t extent = aArea->mRows.Extent();
4968 const uint32_t jStart = aLockedCol;
4969 const uint32_t jEnd = jStart + aArea->mCols.Extent();
4970 const uint32_t iEnd = mCellMap.mCells.Length();
4971 uint32_t candidate = aStartRow;
4972 // Find the first gap in the rows that's at least 'extent' tall.
4973 // ('gap' tracks how tall the current row gap is.)
4974 for (uint32_t i = candidate, gap = 0; i < iEnd && gap < extent; ++i) {
4975 ++gap; // tentative, but we may reset it below if a column is occupied
4976 const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
4977 const uint32_t clampedJEnd = std::min<uint32_t>(jEnd, cellsInRow.Length());
4978 // Check if the current row is unoccupied from jStart to jEnd.
4979 for (uint32_t j = jStart; j < clampedJEnd; ++j) {
4980 if (cellsInRow[j].mIsOccupied) {
4981 // Couldn't fit 'extent' rows at 'candidate' here; we hit something
4982 // at row 'i'. So, try the row after 'i' as our next candidate.
4983 candidate = i + 1;
4984 gap = 0;
4985 break;
4986 }
4987 }
4988 }
4989 return candidate;
4990}
4991
4992void nsGridContainerFrame::Grid::PlaceAutoRow(uint32_t aStartRow,
4993 GridArea* aArea,
4994 uint32_t aClampMaxRowLine) const {
4995 MOZ_ASSERT(aArea->mCols.IsDefinite() && aArea->mRows.IsAuto())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->mCols.IsDefinite() && aArea->mRows
.IsAuto())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aArea->mCols.IsDefinite() &&
aArea->mRows.IsAuto()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aArea->mCols.IsDefinite() && aArea->mRows.IsAuto()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4995)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsDefinite() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 4995); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4996 uint32_t row = FindAutoRow(aArea->mCols.mStart, aStartRow, aArea);
4997 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
4998 MOZ_ASSERT(aArea->IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea->IsDefinite()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aArea->IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4998)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 4998); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4999}
5000
5001void nsGridContainerFrame::Grid::PlaceAutoAutoInRowOrder(
5002 uint32_t aStartCol, uint32_t aStartRow, GridArea* aArea,
5003 uint32_t aClampMaxColLine, uint32_t aClampMaxRowLine) const {
5004 MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->mCols.IsAuto() && aArea->mRows.
IsAuto())>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aArea->mCols.IsAuto() && aArea
->mRows.IsAuto()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5004)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 5004); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5005 const uint32_t colExtent = aArea->mCols.Extent();
5006 const uint32_t gridRowEnd = mGridRowEnd;
5007 const uint32_t gridColEnd = mGridColEnd;
5008 uint32_t col = aStartCol;
5009 uint32_t row = aStartRow;
5010 for (; row < gridRowEnd; ++row) {
5011 col = FindAutoCol(col, row, aArea);
5012 if (col + colExtent <= gridColEnd) {
5013 break;
5014 }
5015 col = 0;
5016 }
5017 MOZ_ASSERT(row < gridRowEnd || col == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(row < gridRowEnd || col == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(row < gridRowEnd || col ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("row < gridRowEnd || col == 0" " (" "expected column 0 for placing in a new row"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5018
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "row < gridRowEnd || col == 0"
") (" "expected column 0 for placing in a new row" ")"); do {
MOZ_CrashSequence(__null, 5018); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5018 "expected column 0 for placing in a new row")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(row < gridRowEnd || col == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(row < gridRowEnd || col ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("row < gridRowEnd || col == 0" " (" "expected column 0 for placing in a new row"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5018
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "row < gridRowEnd || col == 0"
") (" "expected column 0 for placing in a new row" ")"); do {
MOZ_CrashSequence(__null, 5018); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5019 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
5020 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
5021 MOZ_ASSERT(aArea->IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea->IsDefinite()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aArea->IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5021)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 5021); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5022}
5023
5024void nsGridContainerFrame::Grid::PlaceAutoAutoInColOrder(
5025 uint32_t aStartCol, uint32_t aStartRow, GridArea* aArea,
5026 uint32_t aClampMaxColLine, uint32_t aClampMaxRowLine) const {
5027 MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->mCols.IsAuto() && aArea->mRows.
IsAuto())>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aArea->mCols.IsAuto() && aArea
->mRows.IsAuto()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5027)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 5027); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5028 const uint32_t rowExtent = aArea->mRows.Extent();
5029 const uint32_t gridRowEnd = mGridRowEnd;
5030 const uint32_t gridColEnd = mGridColEnd;
5031 uint32_t col = aStartCol;
5032 uint32_t row = aStartRow;
5033 for (; col < gridColEnd; ++col) {
5034 row = FindAutoRow(col, row, aArea);
5035 if (row + rowExtent <= gridRowEnd) {
5036 break;
5037 }
5038 row = 0;
5039 }
5040 MOZ_ASSERT(col < gridColEnd || row == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(col < gridColEnd || row == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(col < gridColEnd || row ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("col < gridColEnd || row == 0" " (" "expected row 0 for placing in a new column"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5041
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "col < gridColEnd || row == 0"
") (" "expected row 0 for placing in a new column" ")"); do {
MOZ_CrashSequence(__null, 5041); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5041 "expected row 0 for placing in a new column")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(col < gridColEnd || row == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(col < gridColEnd || row ==
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("col < gridColEnd || row == 0" " (" "expected row 0 for placing in a new column"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5041
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "col < gridColEnd || row == 0"
") (" "expected row 0 for placing in a new column" ")"); do {
MOZ_CrashSequence(__null, 5041); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5042 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
5043 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
5044 MOZ_ASSERT(aArea->IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea->IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea->IsDefinite()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aArea->IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5044)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 5044); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5045}
5046
5047template <typename IsEmptyFuncT>
5048Maybe<nsTArray<uint32_t>>
5049nsGridContainerFrame::Grid::CalculateAdjustForAutoFitElements(
5050 uint32_t* const aOutNumEmptyLines, TrackSizingFunctions& aSizingFunctions,
5051 uint32_t aNumGridLines, IsEmptyFuncT aIsEmptyFunc) {
5052 Maybe<nsTArray<uint32_t>> trackAdjust;
5053 uint32_t& numEmptyLines = *aOutNumEmptyLines;
5054 numEmptyLines = 0;
5055 if (aSizingFunctions.NumRepeatTracks() > 0) {
5056 MOZ_ASSERT(aSizingFunctions.mHasRepeatAuto)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSizingFunctions.mHasRepeatAuto)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSizingFunctions.mHasRepeatAuto
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aSizingFunctions.mHasRepeatAuto", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSizingFunctions.mHasRepeatAuto"
")"); do { MOZ_CrashSequence(__null, 5056); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5057 // Since this loop is concerned with just the repeat tracks, we
5058 // iterate from 0..NumRepeatTracks() which is the natural range of
5059 // mRemoveRepeatTracks. This means we have to add
5060 // (mExplicitGridOffset + mRepeatAutoStart) to get a zero-based
5061 // index for arrays like mCellMap/aIsEmptyFunc and trackAdjust. We'll then
5062 // fill out the trackAdjust array for all the remaining lines.
5063 const uint32_t repeatStart = (aSizingFunctions.mExplicitGridOffset +
5064 aSizingFunctions.mRepeatAutoStart);
5065 const uint32_t numRepeats = aSizingFunctions.NumRepeatTracks();
5066 for (uint32_t i = 0; i < numRepeats; ++i) {
5067 if (numEmptyLines) {
5068 MOZ_ASSERT(trackAdjust.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(trackAdjust.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(trackAdjust.isSome()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("trackAdjust.isSome()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5068)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "trackAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5068); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5069 (*trackAdjust)[repeatStart + i] = numEmptyLines;
5070 }
5071 if (aIsEmptyFunc(repeatStart + i)) {
5072 ++numEmptyLines;
5073 if (trackAdjust.isNothing()) {
5074 trackAdjust.emplace(aNumGridLines);
5075 trackAdjust->SetLength(aNumGridLines);
5076 PodZero(trackAdjust->Elements(), trackAdjust->Length());
5077 }
5078
5079 aSizingFunctions.mRemovedRepeatTracks[i] = true;
5080 }
5081 }
5082 // Fill out the trackAdjust array for all the tracks after the repeats.
5083 if (numEmptyLines) {
5084 for (uint32_t line = repeatStart + numRepeats; line < aNumGridLines;
5085 ++line) {
5086 (*trackAdjust)[line] = numEmptyLines;
5087 }
5088 }
5089 }
5090
5091 return trackAdjust;
5092}
5093
5094void nsGridContainerFrame::Grid::SubgridPlaceGridItems(
5095 GridReflowInput& aParentGridRI, Grid* aParentGrid,
5096 const GridItemInfo& aGridItem) {
5097 MOZ_ASSERT(aGridItem.mArea.IsDefinite() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mArea.IsDefinite() || aGridItem.mFrame->
HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridItem.mArea.IsDefinite()
|| aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
" (" "the subgrid's lines should be resolved by now" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
") (" "the subgrid's lines should be resolved by now" ")"); do
{ MOZ_CrashSequence(__null, 5099); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5098 aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mArea.IsDefinite() || aGridItem.mFrame->
HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridItem.mArea.IsDefinite()
|| aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
" (" "the subgrid's lines should be resolved by now" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
") (" "the subgrid's lines should be resolved by now" ")"); do
{ MOZ_CrashSequence(__null, 5099); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5099 "the subgrid's lines should be resolved by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mArea.IsDefinite() || aGridItem.mFrame->
HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridItem.mArea.IsDefinite()
|| aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
" (" "the subgrid's lines should be resolved by now" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mArea.IsDefinite() || aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
") (" "the subgrid's lines should be resolved by now" ")"); do
{ MOZ_CrashSequence(__null, 5099); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5100 if (aGridItem.IsSubgrid(LogicalAxis::Inline)) {
5101 aParentGridRI.mFrame->AddStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
5102 }
5103 if (aGridItem.IsSubgrid(LogicalAxis::Block)) {
5104 aParentGridRI.mFrame->AddStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
5105 }
5106 auto* childGrid = aGridItem.SubgridFrame();
5107 const auto* pos = childGrid->StylePosition();
5108 childGrid->NormalizeChildLists();
5109 GridReflowInput gridRI(childGrid, aParentGridRI.mRenderingContext);
5110 childGrid->InitImplicitNamedAreas(pos);
5111
5112 const bool isOrthogonal = aParentGridRI.mWM.IsOrthogonalTo(gridRI.mWM);
5113 // Record the subgrid's GridArea in a frame property.
5114 auto* subgrid = childGrid->GetProperty(Subgrid::Prop());
5115 if (!subgrid) {
5116 subgrid = new Subgrid(aGridItem.mArea, isOrthogonal, aParentGridRI.mWM);
5117 childGrid->SetProperty(Subgrid::Prop(), subgrid);
5118 } else {
5119 subgrid->mArea = aGridItem.mArea;
5120 subgrid->mIsOrthogonal = isOrthogonal;
5121 subgrid->mGridItems.Clear();
5122 subgrid->mAbsPosItems.Clear();
5123 }
5124
5125 // Abs.pos. subgrids may have kAutoLine in their area. Map those to the edge
5126 // line in the parent's grid (zero-based line numbers).
5127 if (MOZ_UNLIKELY(subgrid->mArea.mCols.mStart == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mCols.mStart == kAutoLine
), 0))
) {
5128 subgrid->mArea.mCols.mStart = 0;
5129 }
5130 if (MOZ_UNLIKELY(subgrid->mArea.mCols.mEnd == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mCols.mEnd == kAutoLine
), 0))
) {
5131 subgrid->mArea.mCols.mEnd = aParentGrid->mGridColEnd - 1;
5132 }
5133 if (MOZ_UNLIKELY(subgrid->mArea.mRows.mStart == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mRows.mStart == kAutoLine
), 0))
) {
5134 subgrid->mArea.mRows.mStart = 0;
5135 }
5136 if (MOZ_UNLIKELY(subgrid->mArea.mRows.mEnd == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mRows.mEnd == kAutoLine
), 0))
) {
5137 subgrid->mArea.mRows.mEnd = aParentGrid->mGridRowEnd - 1;
5138 }
5139
5140 MOZ_ASSERT((subgrid->mArea.mCols.Extent() > 0 &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
" (" "subgrid needs at least one track for its items" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
") (" "subgrid needs at least one track for its items" ")");
do { MOZ_CrashSequence(__null, 5143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5141 subgrid->mArea.mRows.Extent() > 0) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
" (" "subgrid needs at least one track for its items" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
") (" "subgrid needs at least one track for its items" ")");
do { MOZ_CrashSequence(__null, 5143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5142 gridRI.mGridItems.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
" (" "subgrid needs at least one track for its items" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
") (" "subgrid needs at least one track for its items" ")");
do { MOZ_CrashSequence(__null, 5143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5143 "subgrid needs at least one track for its items")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((subgrid->mArea.mCols.Extent() > 0 && subgrid
->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
" (" "subgrid needs at least one track for its items" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(subgrid->mArea.mCols.Extent() > 0 && subgrid->mArea.mRows.Extent() > 0) || gridRI.mGridItems.IsEmpty()"
") (" "subgrid needs at least one track for its items" ")");
do { MOZ_CrashSequence(__null, 5143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5144
5145 // The min/sz/max sizes are the input to the "repeat-to-fill" algorithm:
5146 // https://drafts.csswg.org/css-grid-2/#auto-repeat
5147 // They're only used for auto-repeat in a non-subgridded axis so we skip
5148 // computing them otherwise.
5149 RepeatTrackSizingInput repeatSizing(gridRI.mWM);
5150 if (!childGrid->IsColSubgrid() && gridRI.mColFunctions.mHasRepeatAuto) {
5151 // FIXME: Bug 1918794. Figure out if it is fine to pass Nothing() here. It
5152 // seems we use a different way to calculate the size if the container is a
5153 // subgrid. Otherwise, we may have to know the area size that this grid item
5154 // is placed, and pass the area size as the containing block size to this
5155 // function.
5156 repeatSizing.InitFromStyle(LogicalAxis::Inline, gridRI.mWM, gridRI.mFrame,
5157 gridRI.mFrame->Style(),
5158 gridRI.mFrame->GetAspectRatio(), Nothing());
5159 }
5160 if (!childGrid->IsRowSubgrid() && gridRI.mRowFunctions.mHasRepeatAuto) {
5161 // FIXME: Bug 1918794. Same as above.
5162 repeatSizing.InitFromStyle(LogicalAxis::Block, gridRI.mWM, gridRI.mFrame,
5163 gridRI.mFrame->Style(),
5164 gridRI.mFrame->GetAspectRatio(), Nothing());
5165 }
5166
5167 PlaceGridItems(gridRI, repeatSizing);
5168
5169 subgrid->mGridItems = std::move(gridRI.mGridItems);
5170 subgrid->mAbsPosItems = std::move(gridRI.mAbsPosItems);
5171 subgrid->mGridColEnd = mGridColEnd;
5172 subgrid->mGridRowEnd = mGridRowEnd;
5173}
5174
5175void nsGridContainerFrame::Grid::PlaceGridItems(
5176 GridReflowInput& aGridRI, const RepeatTrackSizingInput& aSizes) {
5177 MOZ_ASSERT(mCellMap.mCells.IsEmpty(), "unexpected entries in cell map")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCellMap.mCells.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCellMap.mCells.IsEmpty())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCellMap.mCells.IsEmpty()"
" (" "unexpected entries in cell map" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5177); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCellMap.mCells.IsEmpty()"
") (" "unexpected entries in cell map" ")"); do { MOZ_CrashSequence
(__null, 5177); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5178
5179 mAreas = aGridRI.mFrame->GetImplicitNamedAreas();
5180
5181 if (aGridRI.mFrame->HasSubgridItems() || aGridRI.mFrame->IsSubgrid()) {
5182 if (auto* uts = aGridRI.mFrame->GetUsedTrackSizes()) {
5183 uts->mCanResolveLineRangeSize = {false, false};
5184 uts->mTrackPlans[LogicalAxis::Inline].ClearAndRetainStorage();
5185 uts->mTrackPlans[LogicalAxis::Block].ClearAndRetainStorage();
5186 }
5187 }
5188
5189 // SubgridPlaceGridItems will set these if we find any subgrid items.
5190 aGridRI.mFrame->RemoveStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
5191 NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
5192
5193 // https://drafts.csswg.org/css-grid-2/#grid-definition
5194 // Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
5195 // This is determined by the larger of the number of rows/columns defined
5196 // by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
5197 // Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
5198 // Note that this is for a grid with a 1,1 origin. We'll change that
5199 // to a 0,0 based grid after placing definite lines.
5200 const nsStylePosition* const gridStyle = aGridRI.mGridStyle;
5201 const auto* areas = gridStyle->mGridTemplateAreas.IsNone()
5202 ? nullptr
5203 : &*gridStyle->mGridTemplateAreas.AsAreas();
5204 const LineNameMap* parentLineNameMap = nullptr;
5205 const LineRange* subgridRange = nullptr;
5206 bool subgridAxisIsSameDirection = true;
5207 bool subgridIsOrthogonal = false;
5208 if (!aGridRI.mFrame->IsColSubgrid()) {
5209 aGridRI.mColFunctions.InitRepeatTracks(
5210 gridStyle->mColumnGap, aSizes.mMin.ISize(aGridRI.mWM),
5211 aSizes.mSize.ISize(aGridRI.mWM), aSizes.mMax.ISize(aGridRI.mWM));
5212 uint32_t areaCols = areas ? areas->width + 1 : 1;
5213 mExplicitGridColEnd =
5214 aGridRI.mColFunctions.ComputeExplicitGridEnd(areaCols);
5215 } else {
5216 const auto* subgrid = aGridRI.mFrame->GetProperty(Subgrid::Prop());
5217 subgridRange = &subgrid->SubgridCols();
5218 uint32_t extent = subgridRange->Extent();
5219 mExplicitGridColEnd = extent + 1; // the grid is 1-based at this point
5220 parentLineNameMap =
5221 ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Inline);
5222 auto parentWM =
5223 aGridRI.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
5224 subgridAxisIsSameDirection =
5225 aGridRI.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, parentWM);
5226 subgridIsOrthogonal = subgrid->mIsOrthogonal;
5227 }
5228 mGridColEnd = mExplicitGridColEnd;
5229 LineNameMap colLineNameMap(gridStyle, mAreas, aGridRI.mColFunctions,
5230 parentLineNameMap, subgridRange,
5231 subgridAxisIsSameDirection, subgridIsOrthogonal);
5232
5233 if (!aGridRI.mFrame->IsRowSubgrid()) {
5234 const Maybe<nscoord> containBSize = aGridRI.mFrame->ContainIntrinsicBSize();
5235 const nscoord repeatTrackSizingBSize = [&] {
5236 // This clamping only applies to auto sizes.
5237 if (containBSize &&
5238 aSizes.mSize.BSize(aGridRI.mWM) == NS_UNCONSTRAINEDSIZE) {
5239 return CSSMinMax(*containBSize, aSizes.mMin.BSize(aGridRI.mWM),
5240 aSizes.mMax.BSize(aGridRI.mWM));
5241 }
5242 return aSizes.mSize.BSize(aGridRI.mWM);
5243 }();
5244 aGridRI.mRowFunctions.InitRepeatTracks(
5245 gridStyle->mRowGap, aSizes.mMin.BSize(aGridRI.mWM),
5246 repeatTrackSizingBSize, aSizes.mMax.BSize(aGridRI.mWM));
5247 uint32_t areaRows = areas ? areas->strings.Length() + 1 : 1;
5248 mExplicitGridRowEnd =
5249 aGridRI.mRowFunctions.ComputeExplicitGridEnd(areaRows);
5250 parentLineNameMap = nullptr;
5251 subgridRange = nullptr;
5252 } else {
5253 const auto* subgrid = aGridRI.mFrame->GetProperty(Subgrid::Prop());
5254 subgridRange = &subgrid->SubgridRows();
5255 uint32_t extent = subgridRange->Extent();
5256 mExplicitGridRowEnd = extent + 1; // the grid is 1-based at this point
5257 parentLineNameMap =
5258 ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Block);
5259 auto parentWM =
5260 aGridRI.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
5261 subgridAxisIsSameDirection =
5262 aGridRI.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, parentWM);
5263 subgridIsOrthogonal = subgrid->mIsOrthogonal;
5264 }
5265 mGridRowEnd = mExplicitGridRowEnd;
5266 LineNameMap rowLineNameMap(gridStyle, mAreas, aGridRI.mRowFunctions,
5267 parentLineNameMap, subgridRange,
5268 subgridAxisIsSameDirection, subgridIsOrthogonal);
5269
5270 const bool isSubgridOrItemInSubgrid =
5271 aGridRI.mFrame->IsSubgrid() || !!mParentGrid;
5272 auto SetSubgridChildEdgeBits =
5273 [this, isSubgridOrItemInSubgrid](GridItemInfo& aItem) -> void {
5274 if (isSubgridOrItemInSubgrid) {
5275 const auto& area = aItem.mArea;
5276 if (area.mCols.mStart == 0) {
5277 aItem.mState[LogicalAxis::Inline] |= ItemState::eStartEdge;
5278 }
5279 if (area.mCols.mEnd == mGridColEnd) {
5280 aItem.mState[LogicalAxis::Inline] |= ItemState::eEndEdge;
5281 }
5282 if (area.mRows.mStart == 0) {
5283 aItem.mState[LogicalAxis::Block] |= ItemState::eStartEdge;
5284 }
5285 if (area.mRows.mEnd == mGridRowEnd) {
5286 aItem.mState[LogicalAxis::Block] |= ItemState::eEndEdge;
5287 }
5288 }
5289 };
5290
5291 SetLineMaps(&colLineNameMap, &rowLineNameMap);
5292
5293 // https://drafts.csswg.org/css-grid-2/#line-placement
5294 // Resolve definite positions per spec chapter 8.3.
5295 int32_t minCol = 1;
5296 int32_t minRow = 1;
5297 aGridRI.mGridItems.ClearAndRetainStorage();
5298 aGridRI.mIter.Reset();
5299
5300 bool needToRecordAutoFlowCounter =
5301 gridStyle->mGridTemplateColumns.IsNone() &&
5302 !gridStyle->mGridTemplateRows.IsNone() &&
5303 !aGridRI.mFrame->Style()->HasAuthorOrUserSpecifiedGridAutoFlow();
5304
5305 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5306 nsIFrame* child = *aGridRI.mIter;
5307 GridItemInfo* info = aGridRI.mGridItems.AppendElement(GridItemInfo(
5308 child,
5309 PlaceDefinite(child, colLineNameMap, rowLineNameMap, gridStyle)));
5310 MOZ_ASSERT(aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length
() - 1)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length
() - 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
" (" "ItemIndex() is broken" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5311); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
") (" "ItemIndex() is broken" ")"); do { MOZ_CrashSequence(__null
, 5311); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
5311 "ItemIndex() is broken")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length
() - 1)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length
() - 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
" (" "ItemIndex() is broken" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5311); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
") (" "ItemIndex() is broken" ")"); do { MOZ_CrashSequence(__null
, 5311); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
5312 if (needToRecordAutoFlowCounter &&
5313 (info->mState[LogicalAxis::Inline] & ItemState::eAutoPlacement ||
5314 info->mState[LogicalAxis::Block] & ItemState::eAutoPlacement)) {
5315 aGridRI.mFrame->PresContext()->Document()->SetUseCounter(
5316 eUseCounter_custom_GridAutoFlowInitialValueChange);
5317 needToRecordAutoFlowCounter = false;
5318 }
5319
5320 GridArea& area = info->mArea;
5321 if (area.mCols.IsDefinite()) {
5322 minCol = std::min(minCol, area.mCols.mUntranslatedStart);
5323 }
5324 if (area.mRows.IsDefinite()) {
5325 minRow = std::min(minRow, area.mRows.mUntranslatedStart);
5326 }
5327 }
5328
5329 // Translate the whole grid so that the top-/left-most area is at 0,0.
5330 mExplicitGridOffsetCol = 1 - minCol; // minCol/Row is always <= 1, see above
5331 mExplicitGridOffsetRow = 1 - minRow;
5332 aGridRI.mColFunctions.mExplicitGridOffset = mExplicitGridOffsetCol;
5333 aGridRI.mRowFunctions.mExplicitGridOffset = mExplicitGridOffsetRow;
5334 const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
5335 const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
5336 const bool isRowMasonry = aGridRI.mFrame->IsRowMasonry();
5337 const bool isColMasonry = aGridRI.mFrame->IsColMasonry();
5338 const bool isMasonry = isColMasonry || isRowMasonry;
5339 mGridColEnd += offsetToColZero;
5340 mGridRowEnd += offsetToRowZero;
5341 const uint32_t gridAxisTrackCount = isRowMasonry ? mGridColEnd : mGridRowEnd;
5342 aGridRI.mIter.Reset();
5343 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5344 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5345 GridArea& area = item.mArea;
5346 if (area.mCols.IsDefinite()) {
5347 area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
5348 area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
5349 }
5350 if (area.mRows.IsDefinite()) {
5351 area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
5352 area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
5353 }
5354 if (area.IsDefinite()) {
5355 if (isMasonry) {
5356 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5357 }
5358 if (item.IsSubgrid()) {
5359 Grid grid(this);
5360 grid.SubgridPlaceGridItems(aGridRI, this, item);
5361 }
5362 mCellMap.Fill(area);
5363 InflateGridFor(area);
5364 SetSubgridChildEdgeBits(item);
5365 }
5366 }
5367
5368 // https://drafts.csswg.org/css-grid-2/#auto-placement-algo
5369 // Step 1, place 'auto' items that have one definite position -
5370 // definite row (column) for grid-auto-flow:row (column).
5371 auto flowStyle = gridStyle->mGridAutoFlow;
5372 const bool isRowOrder =
5373 isMasonry ? isRowMasonry : !!(flowStyle & StyleGridAutoFlow::ROW);
5374 const bool isSparse = !(flowStyle & StyleGridAutoFlow::DENSE);
5375 uint32_t clampMaxColLine = colLineNameMap.mClampMaxLine + offsetToColZero;
5376 uint32_t clampMaxRowLine = rowLineNameMap.mClampMaxLine + offsetToRowZero;
5377 // We need 1 cursor per row (or column) if placement is sparse.
5378 {
5379 Maybe<nsTHashMap<nsUint32HashKey, uint32_t>> cursors;
5380 if (isSparse) {
5381 cursors.emplace();
5382 }
5383 auto placeAutoMinorFunc =
5384 isRowOrder ? &Grid::PlaceAutoCol : &Grid::PlaceAutoRow;
5385 uint32_t clampMaxLine = isRowOrder ? clampMaxColLine : clampMaxRowLine;
5386 aGridRI.mIter.Reset();
5387 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5388 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5389 GridArea& area = item.mArea;
5390 LineRange& major = isRowOrder ? area.mRows : area.mCols;
5391 LineRange& minor = isRowOrder ? area.mCols : area.mRows;
5392 if (major.IsDefinite() && minor.IsAuto()) {
5393 // Items with 'auto' in the minor dimension only.
5394 const uint32_t cursor = isSparse ? cursors->Get(major.mStart) : 0;
5395 (this->*placeAutoMinorFunc)(cursor, &area, clampMaxLine);
5396 if (isMasonry) {
5397 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5398 }
5399 if (item.IsSubgrid()) {
5400 Grid grid(this);
5401 grid.SubgridPlaceGridItems(aGridRI, this, item);
5402 }
5403 mCellMap.Fill(area);
5404 SetSubgridChildEdgeBits(item);
5405 if (isSparse) {
5406 cursors->InsertOrUpdate(major.mStart, minor.mEnd);
5407 }
5408 }
5409 InflateGridFor(area); // Step 2, inflating for auto items too
5410 }
5411 }
5412
5413 // XXX NOTE possible spec issue.
5414 // XXX It's unclear if the remaining major-dimension auto and
5415 // XXX auto in both dimensions should use the same cursor or not,
5416 // XXX https://www.w3.org/Bugs/Public/show_bug.cgi?id=16044
5417 // XXX seems to indicate it shouldn't.
5418 // XXX https://drafts.csswg.org/css-grid-2/#auto-placement-algo
5419 // XXX now says it should (but didn't in earlier versions)
5420
5421 // Step 3, place the remaining grid items
5422 uint32_t cursorMajor = 0; // for 'dense' these two cursors will stay at 0,0
5423 uint32_t cursorMinor = 0;
5424 auto placeAutoMajorFunc =
5425 isRowOrder ? &Grid::PlaceAutoRow : &Grid::PlaceAutoCol;
5426 uint32_t clampMaxMajorLine = isRowOrder ? clampMaxRowLine : clampMaxColLine;
5427 aGridRI.mIter.Reset();
5428 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5429 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5430 GridArea& area = item.mArea;
5431 MOZ_ASSERT(*aGridRI.mIter == item.mFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aGridRI.mIter == item.mFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aGridRI.mIter == item.mFrame
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"*aGridRI.mIter == item.mFrame" " (" "iterator out of sync with aState.mGridItems"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5432
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aGridRI.mIter == item.mFrame"
") (" "iterator out of sync with aState.mGridItems" ")"); do
{ MOZ_CrashSequence(__null, 5432); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5432 "iterator out of sync with aState.mGridItems")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aGridRI.mIter == item.mFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aGridRI.mIter == item.mFrame
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"*aGridRI.mIter == item.mFrame" " (" "iterator out of sync with aState.mGridItems"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5432
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aGridRI.mIter == item.mFrame"
") (" "iterator out of sync with aState.mGridItems" ")"); do
{ MOZ_CrashSequence(__null, 5432); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5433 LineRange& major = isRowOrder ? area.mRows : area.mCols;
5434 LineRange& minor = isRowOrder ? area.mCols : area.mRows;
5435 if (major.IsAuto()) {
5436 if (minor.IsDefinite()) {
5437 // Items with 'auto' in the major dimension only.
5438 if (isSparse) {
5439 if (minor.mStart < cursorMinor) {
5440 ++cursorMajor;
5441 }
5442 cursorMinor = minor.mStart;
5443 }
5444 (this->*placeAutoMajorFunc)(cursorMajor, &area, clampMaxMajorLine);
5445 if (isSparse) {
5446 cursorMajor = major.mStart;
5447 }
5448 } else {
5449 // Items with 'auto' in both dimensions.
5450 if (isRowOrder) {
5451 PlaceAutoAutoInRowOrder(cursorMinor, cursorMajor, &area,
5452 clampMaxColLine, clampMaxRowLine);
5453 } else {
5454 PlaceAutoAutoInColOrder(cursorMajor, cursorMinor, &area,
5455 clampMaxColLine, clampMaxRowLine);
5456 }
5457 if (isSparse) {
5458 cursorMajor = major.mStart;
5459 cursorMinor = minor.mEnd;
5460#ifdef DEBUG1
5461 uint32_t gridMajorEnd = isRowOrder ? mGridRowEnd : mGridColEnd;
5462 uint32_t gridMinorEnd = isRowOrder ? mGridColEnd : mGridRowEnd;
5463 MOZ_ASSERT(cursorMajor <= gridMajorEnd,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cursorMajor <= gridMajorEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cursorMajor <= gridMajorEnd
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"cursorMajor <= gridMajorEnd" " (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMajor <= gridMajorEnd"
") (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")");
do { MOZ_CrashSequence(__null, 5465); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5464 "we shouldn't need to place items further than 1 track "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cursorMajor <= gridMajorEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cursorMajor <= gridMajorEnd
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"cursorMajor <= gridMajorEnd" " (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMajor <= gridMajorEnd"
") (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")");
do { MOZ_CrashSequence(__null, 5465); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5465 "past the current end of the grid, in major dimension")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cursorMajor <= gridMajorEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cursorMajor <= gridMajorEnd
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"cursorMajor <= gridMajorEnd" " (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMajor <= gridMajorEnd"
") (" "we shouldn't need to place items further than 1 track "
"past the current end of the grid, in major dimension" ")");
do { MOZ_CrashSequence(__null, 5465); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5466 MOZ_ASSERT(cursorMinor <= gridMinorEnd,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cursorMinor <= gridMinorEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cursorMinor <= gridMinorEnd
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"cursorMinor <= gridMinorEnd" " (" "we shouldn't add implicit minor tracks for auto/auto"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5467
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMinor <= gridMinorEnd"
") (" "we shouldn't add implicit minor tracks for auto/auto"
")"); do { MOZ_CrashSequence(__null, 5467); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5467 "we shouldn't add implicit minor tracks for auto/auto")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cursorMinor <= gridMinorEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cursorMinor <= gridMinorEnd
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"cursorMinor <= gridMinorEnd" " (" "we shouldn't add implicit minor tracks for auto/auto"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 5467
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMinor <= gridMinorEnd"
") (" "we shouldn't add implicit minor tracks for auto/auto"
")"); do { MOZ_CrashSequence(__null, 5467); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5468#endif
5469 }
5470 }
5471 if (isMasonry) {
5472 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5473 }
5474 if (item.IsSubgrid()) {
5475 Grid grid(this);
5476 grid.SubgridPlaceGridItems(aGridRI, this, item);
5477 }
5478 mCellMap.Fill(area);
5479 InflateGridFor(area);
5480 SetSubgridChildEdgeBits(item);
5481 // XXXmats it might be possible to optimize this a bit for masonry layout
5482 // if this item was placed in the 2nd row && !isSparse, or the 1st row
5483 // is full. Still gotta inflate the grid for all items though to make
5484 // the grid large enough...
5485 }
5486 }
5487
5488 // Force all items into the 1st/2nd track and have span 1 in the masonry axis.
5489 // (See comment on nsGridContainerFrame::MasonryLayout().)
5490 if (isMasonry) {
5491 auto masonryAxis = isRowMasonry ? LogicalAxis::Block : LogicalAxis::Inline;
5492 aGridRI.mIter.Reset();
5493 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5494 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5495 auto& masonryRange = item.mArea.LineRangeForAxis(masonryAxis);
5496 masonryRange.mStart = std::min(masonryRange.mStart, 1U);
5497 masonryRange.mEnd = masonryRange.mStart + 1U;
5498 }
5499 }
5500
5501 if (auto* absCB = aGridRI.mFrame->GetAbsoluteContainingBlock();
5502 absCB && absCB->PrepareAbsoluteFrames(aGridRI.mFrame)) {
5503 // 10.1. With a Grid Container as Containing Block
5504 // https://drafts.csswg.org/css-grid-2/#abspos-items
5505 // We only resolve definite lines here; we'll align auto positions to the
5506 // grid container later during reflow.
5507 const nsFrameList& children = absCB->GetChildList();
5508 const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
5509 const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
5510 // Untranslate the grid again temporarily while resolving abs.pos. lines.
5511 AutoRestore<uint32_t> zeroOffsetGridColEnd(mGridColEnd);
5512 AutoRestore<uint32_t> zeroOffsetGridRowEnd(mGridRowEnd);
5513 mGridColEnd -= offsetToColZero;
5514 mGridRowEnd -= offsetToRowZero;
5515 aGridRI.mAbsPosItems.ClearAndRetainStorage();
5516 for (nsIFrame* child : children) {
5517 GridItemInfo* info = aGridRI.mAbsPosItems.AppendElement(GridItemInfo(
5518 child,
5519 PlaceAbsPos(child, colLineNameMap, rowLineNameMap, gridStyle)));
5520 GridArea& area = info->mArea;
5521 if (area.mCols.mUntranslatedStart != int32_t(kAutoLine)) {
5522 area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
5523 if (isColMasonry) {
5524 // XXXmats clamp any non-auto line to 0 or 1. This is intended to
5525 // allow authors to address the start/end of the masonry box.
5526 // This is experimental at this point though and needs author feedback
5527 // and spec work to sort out what is desired and how it should work.
5528 // See https://github.com/w3c/csswg-drafts/issues/4650
5529 area.mCols.mStart = std::min(area.mCols.mStart, 1U);
5530 }
5531 }
5532 if (area.mCols.mUntranslatedEnd != int32_t(kAutoLine)) {
5533 area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
5534 if (isColMasonry) {
5535 // ditto
5536 area.mCols.mEnd = std::min(area.mCols.mEnd, 1U);
5537 }
5538 }
5539 if (area.mRows.mUntranslatedStart != int32_t(kAutoLine)) {
5540 area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
5541 if (isRowMasonry) {
5542 // ditto
5543 area.mRows.mStart = std::min(area.mRows.mStart, 1U);
5544 }
5545 }
5546 if (area.mRows.mUntranslatedEnd != int32_t(kAutoLine)) {
5547 area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
5548 if (isRowMasonry) {
5549 // ditto
5550 area.mRows.mEnd = std::min(area.mRows.mEnd, 1U);
5551 }
5552 }
5553 if (isMasonry) {
5554 info->MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5555 }
5556
5557 // An abs.pos. subgrid with placement auto/1 or -1/auto technically
5558 // doesn't span any parent tracks. Inhibit subgridding in this case.
5559 if (info->IsSubgrid(LogicalAxis::Inline)) {
5560 if (info->mArea.mCols.mStart == zeroOffsetGridColEnd.SavedValue() ||
5561 info->mArea.mCols.mEnd == 0) {
5562 info->InhibitSubgrid(aGridRI.mFrame, LogicalAxis::Inline);
5563 }
5564 }
5565 if (info->IsSubgrid(LogicalAxis::Block)) {
5566 if (info->mArea.mRows.mStart == zeroOffsetGridRowEnd.SavedValue() ||
5567 info->mArea.mRows.mEnd == 0) {
5568 info->InhibitSubgrid(aGridRI.mFrame, LogicalAxis::Block);
5569 }
5570 }
5571
5572 if (info->IsSubgrid()) {
5573 Grid grid(this);
5574 grid.SubgridPlaceGridItems(aGridRI, this, *info);
5575 }
5576 }
5577 }
5578
5579 // Count empty 'auto-fit' tracks in the repeat() range.
5580 // |colAdjust| will have a count for each line in the grid of how many
5581 // tracks were empty between the start of the grid and that line.
5582
5583 Maybe<nsTArray<uint32_t>> colAdjust;
5584 uint32_t numEmptyCols = 0;
5585 if (aGridRI.mColFunctions.mHasRepeatAuto &&
5586 gridStyle->mGridTemplateColumns.GetRepeatAutoValue()->count.IsAutoFit()) {
5587 const auto& cellMap = mCellMap;
5588 colAdjust = CalculateAdjustForAutoFitElements(
5589 &numEmptyCols, aGridRI.mColFunctions, mGridColEnd + 1,
5590 [&cellMap](uint32_t i) -> bool { return cellMap.IsEmptyCol(i); });
5591 }
5592
5593 // Do similar work for the row tracks, with the same logic.
5594 Maybe<nsTArray<uint32_t>> rowAdjust;
5595 uint32_t numEmptyRows = 0;
5596 if (aGridRI.mRowFunctions.mHasRepeatAuto &&
5597 gridStyle->mGridTemplateRows.GetRepeatAutoValue()->count.IsAutoFit()) {
5598 const auto& cellMap = mCellMap;
5599 rowAdjust = CalculateAdjustForAutoFitElements(
5600 &numEmptyRows, aGridRI.mRowFunctions, mGridRowEnd + 1,
5601 [&cellMap](uint32_t i) -> bool { return cellMap.IsEmptyRow(i); });
5602 }
5603 MOZ_ASSERT((numEmptyCols > 0) == colAdjust.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype((numEmptyCols > 0) == colAdjust.isSome())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((numEmptyCols > 0) == colAdjust.isSome()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("(numEmptyCols > 0) == colAdjust.isSome()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5603)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(numEmptyCols > 0) == colAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5603); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5604 MOZ_ASSERT((numEmptyRows > 0) == rowAdjust.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype((numEmptyRows > 0) == rowAdjust.isSome())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((numEmptyRows > 0) == rowAdjust.isSome()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("(numEmptyRows > 0) == rowAdjust.isSome()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5604)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(numEmptyRows > 0) == rowAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5604); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5605 // Remove the empty 'auto-fit' tracks we found above, if any.
5606 if (numEmptyCols || numEmptyRows) {
5607 // Adjust the line numbers in the grid areas.
5608 for (auto& item : aGridRI.mGridItems) {
5609 if (numEmptyCols) {
5610 item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
5611 }
5612 if (numEmptyRows) {
5613 item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
5614 }
5615 }
5616 for (auto& item : aGridRI.mAbsPosItems) {
5617 if (numEmptyCols) {
5618 item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
5619 }
5620 if (numEmptyRows) {
5621 item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
5622 }
5623 }
5624 // Adjust the grid size.
5625 mGridColEnd -= numEmptyCols;
5626 mExplicitGridColEnd -= numEmptyCols;
5627 mGridRowEnd -= numEmptyRows;
5628 mExplicitGridRowEnd -= numEmptyRows;
5629 // Adjust the track mapping to unmap the removed tracks.
5630 auto colRepeatCount = aGridRI.mColFunctions.NumRepeatTracks();
5631 aGridRI.mColFunctions.SetNumRepeatTracks(colRepeatCount - numEmptyCols);
5632 auto rowRepeatCount = aGridRI.mRowFunctions.NumRepeatTracks();
5633 aGridRI.mRowFunctions.SetNumRepeatTracks(rowRepeatCount - numEmptyRows);
5634 }
5635
5636 // Update the line boundaries of the implicit grid areas, if needed.
5637 if (mAreas && aGridRI.mFrame->HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO)) {
5638 for (auto iter = mAreas->iter(); !iter.done(); iter.next()) {
5639 auto& areaInfo = iter.get().value();
5640
5641 // Resolve the lines for the area. We use the name of the area as the
5642 // name of the lines, knowing that the line placement algorithm will
5643 // add the -start and -end suffixes as appropriate for layout.
5644 StyleGridLine lineStartAndEnd;
5645 lineStartAndEnd.ident._0 = areaInfo.name;
5646
5647 LineRange columnLines =
5648 ResolveLineRange(lineStartAndEnd, lineStartAndEnd, colLineNameMap,
5649 LogicalAxis::Inline, mExplicitGridColEnd, gridStyle);
5650
5651 LineRange rowLines =
5652 ResolveLineRange(lineStartAndEnd, lineStartAndEnd, rowLineNameMap,
5653 LogicalAxis::Block, mExplicitGridRowEnd, gridStyle);
5654
5655 // Put the resolved line indices back into the area structure.
5656 areaInfo.columns.start = columnLines.mStart + mExplicitGridOffsetCol;
5657 areaInfo.columns.end = columnLines.mEnd + mExplicitGridOffsetCol;
5658 areaInfo.rows.start = rowLines.mStart + mExplicitGridOffsetRow;
5659 areaInfo.rows.end = rowLines.mEnd + mExplicitGridOffsetRow;
5660 }
5661 }
5662}
5663
5664void nsGridContainerFrame::Tracks::Initialize(
5665 const TrackSizingFunctions& aFunctions,
5666 const NonNegativeLengthPercentageOrNormal& aGridGap, uint32_t aNumTracks,
5667 nscoord aContentBoxSize) {
5668 mSizes.SetLength(aNumTracks);
5669 mSizes.ZeroInitialize();
5670 for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
5671 auto& sz = mSizes[i];
5672 mStateUnion |= sz.Initialize(aContentBoxSize, aFunctions.SizingFor(i));
5673 if (mIsMasonry) {
5674 sz.mBase = aContentBoxSize;
5675 sz.mLimit = aContentBoxSize;
5676 }
5677 }
5678 mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize);
5679 mContentBoxSize = aContentBoxSize;
5680}
5681
5682// A measuring reflow performed during intrinsic sizing leaves aChild laid out
5683// with a size that generally might not be its final one. Mark it dirty up to
5684// the nearest ancestor that is already dirty or being reflowed. Callers must
5685// do this after reading whatever they need from aChild's measured state.
5686static void MarkDirtyAfterIntrinsicSizingReflow(nsIFrame* aChild) {
5687 aChild->MarkSubtreeDirty();
5688 auto* cur = aChild;
5689 while (true) {
5690 nsIFrame* parent = cur->GetParent();
5691 if (!parent || parent->IsSubtreeDirty() ||
5692 parent->HasAnyStateBits(NS_FRAME_IN_REFLOW)) {
5693 return;
5694 }
5695 parent->ChildIsDirty(cur);
5696 cur = parent;
5697 }
5698}
5699
5700// Reflow aChild in the given aAvailableSize.
5701static MeasuringReflowResult MeasuringReflow(
5702 nsIFrame* aChild, const ReflowInput* aReflowInput, gfxContext* aRC,
5703 const LogicalSize& aAvailableSize, const LogicalSize& aCBSize,
5704 nscoord aIMinSizeClamp = NS_MAXSIZE, nscoord aBMinSizeClamp = NS_MAXSIZE) {
5705 MOZ_ASSERT(aChild->IsGridItem(), "aChild should be a grid item!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->IsGridItem())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChild->IsGridItem()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->IsGridItem()"
" (" "aChild should be a grid item!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsGridItem()"
") (" "aChild should be a grid item!" ")"); do { MOZ_CrashSequence
(__null, 5705); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5706 auto wm = aChild->GetWritingMode();
5707 // NOTE: Reflowing or FinishReflowChild might invalidate the cache.
5708 if (const auto* cachedMeasurement =
5709 aChild->GetProperty(GridItemCachedBAxisMeasurement::Prop());
5710 cachedMeasurement && cachedMeasurement->IsValidFor(aChild, aCBSize)) {
5711 GRID_LOG(do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow accepted cached value=%d, child=%p, "
"aCBSize.ISize=%d", cachedMeasurement->Result().mBSize, aChild
, aCBSize.ISize(wm)); } } while (0);
5712 "[perf] MeasuringReflow accepted cached value=%d, child=%p, "do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow accepted cached value=%d, child=%p, "
"aCBSize.ISize=%d", cachedMeasurement->Result().mBSize, aChild
, aCBSize.ISize(wm)); } } while (0);
5713 "aCBSize.ISize=%d",do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow accepted cached value=%d, child=%p, "
"aCBSize.ISize=%d", cachedMeasurement->Result().mBSize, aChild
, aCBSize.ISize(wm)); } } while (0);
5714 cachedMeasurement->Result().mBSize, aChild, aCBSize.ISize(wm))do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow accepted cached value=%d, child=%p, "
"aCBSize.ISize=%d", cachedMeasurement->Result().mBSize, aChild
, aCBSize.ISize(wm)); } } while (0);
;
5715 return cachedMeasurement->Result();
5716 }
5717
5718 auto* parent = static_cast<nsGridContainerFrame*>(aChild->GetParent());
5719 nsPresContext* pc = aChild->PresContext();
5720 Maybe<ReflowInput> dummyParentState;
5721 const ReflowInput* rs = aReflowInput;
5722 if (!aReflowInput) {
5723 MOZ_ASSERT(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5723)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW)"
")"); do { MOZ_CrashSequence(__null, 5723); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5724 dummyParentState.emplace(
5725 pc, parent, aRC,
5726 LogicalSize(parent->GetWritingMode(), 0, NS_UNCONSTRAINEDSIZE),
5727 ReflowInput::InitFlag::DummyParentReflowInput);
5728 rs = dummyParentState.ptr();
5729 }
5730#ifdef DEBUG1
5731 // This will suppress various ABSURD_SIZE warnings for this reflow.
5732 parent->SetProperty(nsContainerFrame::DebugReflowingWithInfiniteISize(),
5733 true);
5734#endif
5735 ComputeSizeFlags csFlags = ComputeSizeFlag::IsGridMeasuringReflow;
5736 // Shrink-wrap grid items that will be aligned (rather than stretched) in
5737 // their own inline axis.
5738 if (!parent->GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
5739 csFlags += ComputeSizeFlag::ShrinkWrap;
5740 }
5741 if (aAvailableSize.ISize(wm) == INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60))) {
5742 csFlags += ComputeSizeFlag::ShrinkWrap;
5743 }
5744 if (aIMinSizeClamp != NS_MAXSIZE) {
5745 csFlags += ComputeSizeFlag::IClampMarginBoxMinSize;
5746 }
5747 if (aBMinSizeClamp != NS_MAXSIZE) {
5748 csFlags += ComputeSizeFlag::BClampMarginBoxMinSize;
5749 aChild->SetProperty(nsIFrame::BClampMarginBoxMinSizeProperty(),
5750 aBMinSizeClamp);
5751 } else {
5752 aChild->RemoveProperty(nsIFrame::BClampMarginBoxMinSizeProperty());
5753 }
5754 ReflowInput childRI(pc, *rs, aChild, aAvailableSize, Some(aCBSize), {}, {},
5755 csFlags);
5756
5757 // FIXME (perf): It would be faster to do this only if the previous reflow of
5758 // the child was not a measuring reflow, and only if the child does some of
5759 // the things that are affected by ComputeSizeFlag::IsGridMeasuringReflow.
5760 childRI.SetBResize(true);
5761 // Not 100% sure this is needed, but be conservative for now:
5762 childRI.SetBResizeForPercentages(true);
5763
5764 ReflowOutput childSize(childRI);
5765 nsReflowStatus childStatus;
5766 const nsIFrame::ReflowChildFlags flags =
5767 nsIFrame::ReflowChildFlags::NoMoveFrame |
5768 nsIFrame::ReflowChildFlags::NoDeleteNextInFlowChild;
5769
5770 parent->ReflowChild(aChild, pc, childSize, childRI, wm, LogicalPoint(wm),
5771 nsSize(), flags, childStatus);
5772 nsContainerFrame::FinishReflowChild(aChild, pc, childSize, &childRI, wm,
5773 LogicalPoint(wm), nsSize(), flags);
5774#ifdef DEBUG1
5775 parent->RemoveProperty(nsContainerFrame::DebugReflowingWithInfiniteISize());
5776#endif
5777
5778 const MeasuringReflowResult result{
5779 childSize.BSize(wm),
5780 childSize.BSize(wm) -
5781 childRI.ComputedLogicalBorderPadding(wm).BStartEnd(wm)};
5782 if (GridItemCachedBAxisMeasurement* cachedMeasurement =
5783 aChild->GetProperty(GridItemCachedBAxisMeasurement::Prop())) {
5784 cachedMeasurement->Update(aChild, aCBSize, result);
5785 GRID_LOG(do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow rejected but updated cached value=%d, "
"child=%p, aCBSize.ISize=%d", result.mBSize, aChild, aCBSize
.ISize(wm)); } } while (0);
5786 "[perf] MeasuringReflow rejected but updated cached value=%d, "do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow rejected but updated cached value=%d, "
"child=%p, aCBSize.ISize=%d", result.mBSize, aChild, aCBSize
.ISize(wm)); } } while (0);
5787 "child=%p, aCBSize.ISize=%d",do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow rejected but updated cached value=%d, "
"child=%p, aCBSize.ISize=%d", result.mBSize, aChild, aCBSize
.ISize(wm)); } } while (0);
5788 result.mBSize, aChild, aCBSize.ISize(wm))do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow rejected but updated cached value=%d, "
"child=%p, aCBSize.ISize=%d", result.mBSize, aChild, aCBSize
.ISize(wm)); } } while (0);
;
5789 } else {
5790 cachedMeasurement =
5791 new GridItemCachedBAxisMeasurement(aChild, aCBSize, result);
5792 aChild->SetProperty(GridItemCachedBAxisMeasurement::Prop(),
5793 cachedMeasurement);
5794 GRID_LOG(do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow created new cached value=%d, child=%p, "
"aCBSize.ISize=%d", result.mBSize, aChild, aCBSize.ISize(wm)
); } } while (0);
5795 "[perf] MeasuringReflow created new cached value=%d, child=%p, "do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow created new cached value=%d, child=%p, "
"aCBSize.ISize=%d", result.mBSize, aChild, aCBSize.ISize(wm)
); } } while (0);
5796 "aCBSize.ISize=%d",do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow created new cached value=%d, child=%p, "
"aCBSize.ISize=%d", result.mBSize, aChild, aCBSize.ISize(wm)
); } } while (0);
5797 result.mBSize, aChild, aCBSize.ISize(wm))do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "[perf] MeasuringReflow created new cached value=%d, child=%p, "
"aCBSize.ISize=%d", result.mBSize, aChild, aCBSize.ISize(wm)
); } } while (0);
;
5798 }
5799
5800 return result;
5801}
5802
5803/**
5804 * Return the accumulated margin+border+padding in aAxis for aFrame (a subgrid)
5805 * and its ancestor subgrids.
5806 */
5807static LogicalMargin SubgridAccumulatedMarginBorderPadding(
5808 nsIFrame* aFrame, const Subgrid* aSubgrid, WritingMode aResultWM,
5809 LogicalAxis aAxis) {
5810 MOZ_ASSERT(aFrame->IsGridContainerFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->IsGridContainerFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->IsGridContainerFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFrame->IsGridContainerFrame()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 5810); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5811 auto* subgridFrame = static_cast<nsGridContainerFrame*>(aFrame);
5812 LogicalMargin result(aSubgrid->mMarginBorderPadding);
5813 auto* parent = subgridFrame->ParentGridContainerForSubgrid();
5814 auto subgridCBWM = parent->GetWritingMode();
5815 auto childRange = aSubgrid->mArea.LineRangeForAxis(aAxis);
5816 bool skipStartSide = false;
5817 bool skipEndSide = false;
5818 auto axis = aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
5819 // If aFrame's parent is also a subgrid, then add its MBP on the edges that
5820 // are adjacent (i.e. start or end in the same track), recursively.
5821 // ("parent" refers to the grid-frame we're currently adding MBP for,
5822 // and "grandParent" its parent, as we walk up the chain.)
5823 while (parent->IsSubgrid(axis)) {
5824 auto* parentSubgrid = parent->GetProperty(Subgrid::Prop());
5825 auto* grandParent = parent->ParentGridContainerForSubgrid();
5826 auto parentCBWM = grandParent->GetWritingMode();
5827 if (parentCBWM.IsOrthogonalTo(subgridCBWM)) {
5828 axis = GetOrthogonalAxis(axis);
5829 }
5830 const auto& parentRange = parentSubgrid->mArea.LineRangeForAxis(axis);
5831 bool sameDir = parentCBWM.ParallelAxisStartsOnSameSide(axis, subgridCBWM);
5832 if (sameDir) {
5833 skipStartSide |= childRange.mStart != 0;
5834 skipEndSide |= childRange.mEnd != parentRange.Extent();
5835 } else {
5836 skipEndSide |= childRange.mStart != 0;
5837 skipStartSide |= childRange.mEnd != parentRange.Extent();
5838 }
5839 if (skipStartSide && skipEndSide) {
5840 break;
5841 }
5842 auto mbp =
5843 parentSubgrid->mMarginBorderPadding.ConvertTo(subgridCBWM, parentCBWM);
5844 if (skipStartSide) {
5845 mbp.Start(aAxis, subgridCBWM) = nscoord(0);
5846 }
5847 if (skipEndSide) {
5848 mbp.End(aAxis, subgridCBWM) = nscoord(0);
5849 }
5850 result += mbp;
5851 parent = grandParent;
5852 childRange = parentRange;
5853 }
5854 return result.ConvertTo(aResultWM, subgridCBWM);
5855}
5856
5857/**
5858 * Return the [min|max]-content contribution of aChild to its parent (i.e.
5859 * the child's margin-box) in aAxis.
5860 */
5861static nscoord ContentContribution(const GridItemInfo& aGridItem,
5862 const GridReflowInput& aGridRI,
5863 LogicalAxis aAxis,
5864 const LogicalSize& aPercentageBasis,
5865 IntrinsicISizeType aConstraint,
5866 nscoord aMinSizeClamp = NS_MAXSIZE,
5867 const StyleSizeOverrides& aOverrides = {}) {
5868 nsIFrame* child = aGridItem.mFrame;
5869
5870 const WritingMode gridWM = aGridRI.mWM;
5871 nscoord extraMargin = 0;
5872 nsGridContainerFrame::Subgrid* subgrid = nullptr;
5873 if (child->GetParent() != aGridRI.mFrame) {
5874 // |child| is a subgrid descendant, so it contributes its subgrids'
5875 // margin+border+padding for any edge tracks that it spans.
5876 auto* subgridFrame = child->GetParent();
5877 subgrid = subgridFrame->GetProperty(Subgrid::Prop());
5878 const auto itemEdgeBits = aGridItem.mState[aAxis] & ItemState::eEdgeBits;
5879 if (itemEdgeBits) {
5880 LogicalMargin mbp = SubgridAccumulatedMarginBorderPadding(
5881 subgridFrame, subgrid, gridWM, aAxis);
5882 if (itemEdgeBits & ItemState::eStartEdge) {
5883 extraMargin += mbp.Start(aAxis, gridWM);
5884 }
5885 if (itemEdgeBits & ItemState::eEndEdge) {
5886 extraMargin += mbp.End(aAxis, gridWM);
5887 }
5888 }
5889 // It also contributes (half of) the subgrid's gap on its edges (if any)
5890 // subtracted by the non-subgrid ancestor grid container's gap.
5891 // Note that this can also be negative since it's considered a margin.
5892 if (itemEdgeBits != ItemState::eEdgeBits) {
5893 const auto subgridAxis =
5894 gridWM.ConvertAxisTo(aAxis, subgridFrame->GetWritingMode());
5895 auto& gapStyle = subgridAxis == LogicalAxis::Block
5896 ? subgridFrame->StylePosition()->mRowGap
5897 : subgridFrame->StylePosition()->mColumnGap;
5898 if (!gapStyle.IsNormal()) {
5899 auto subgridExtent = subgridAxis == LogicalAxis::Block
5900 ? subgrid->mGridRowEnd
5901 : subgrid->mGridColEnd;
5902 if (subgridExtent > 1) {
5903 nscoord subgridGap =
5904 nsLayoutUtils::ResolveGapToLength(gapStyle, NS_UNCONSTRAINEDSIZE);
5905 const auto& tracks = aGridRI.TracksFor(aAxis);
5906 auto gapDelta = subgridGap - tracks.mGridGap;
5907 if (!itemEdgeBits) {
5908 extraMargin += gapDelta;
5909 } else {
5910 extraMargin += gapDelta / 2;
5911 }
5912 }
5913 }
5914 }
5915 }
5916
5917 gfxContext* rc = &aGridRI.mRenderingContext;
5918 PhysicalAxis axis = gridWM.PhysicalAxis(aAxis);
5919 auto childWM = child->GetWritingMode();
5920 const bool isOrthogonal = childWM.IsOrthogonalTo(gridWM);
5921 auto childAxis = isOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
5922
5923 StyleSizeOverrides overrides = aOverrides;
5924 if (childAxis == LogicalAxis::Inline && !overrides.mStyleBSize) {
5925 const bool stretchesInBlockAxis =
5926 child->StylePosition()
5927 ->BSize(childWM, AnchorPosResolutionParams::From(child))
5928 ->IsAuto() &&
5929 aGridRI.mFrame->GridItemShouldStretch(child, LogicalAxis::Block);
5930 if (stretchesInBlockAxis) {
5931 overrides.mStyleBSize.emplace(StyleSize::Stretch());
5932 }
5933 }
5934
5935 nscoord size = nsLayoutUtils::IntrinsicForAxis(
5936 axis, rc, child, aConstraint, Some(aPercentageBasis),
5937 nsLayoutUtils::BAIL_IF_REFLOW_NEEDED, aMinSizeClamp, overrides);
5938 if (size == NS_INTRINSIC_ISIZE_UNKNOWN && childAxis == LogicalAxis::Block) {
5939 nscoord contentBSize = 0;
5940 if (aGridRI.mIsGridIntrinsicSizing && aAxis == LogicalAxis::Block &&
5941 !StaticPrefs::layout_css_grid_intrinsic_sizing_measure_bsize()) {
5942 // FIXME: Remove this code-path once the stack overflow crashes it causes
5943 // are figured out.
5944 size = 0;
5945 } else {
5946 // We need to reflow the child to find its BSize contribution.
5947 nscoord availISize = INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60));
5948 nscoord availBSize = NS_UNCONSTRAINEDSIZE;
5949 // The next two variables are MinSizeClamp values in the child's axes.
5950 nscoord iMinSizeClamp = NS_MAXSIZE;
5951 nscoord bMinSizeClamp = NS_MAXSIZE;
5952 LogicalSize cbSize = aPercentageBasis;
5953 // Below, we try to resolve the child's grid-area size in its inline-axis
5954 // to use as the CB/Available size in the MeasuringReflow that follows.
5955 if (child->GetParent() != aGridRI.mFrame) {
5956 // This item is a child of a subgrid descendant.
5957 auto* subgridFrame =
5958 static_cast<nsGridContainerFrame*>(child->GetParent());
5959 MOZ_ASSERT(subgridFrame->IsGridContainerFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(subgridFrame->IsGridContainerFrame())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(subgridFrame->IsGridContainerFrame()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("subgridFrame->IsGridContainerFrame()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 5959)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgridFrame->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 5959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5960 auto* uts =
5961 subgridFrame->GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
5962 // The grid-item's inline-axis as expressed in the subgrid's WM.
5963 const auto subgridAxis = childWM.ConvertAxisTo(
5964 LogicalAxis::Inline, subgridFrame->GetWritingMode());
5965 uts->ResolveTrackSizesForAxis(subgridFrame, subgridAxis, *rc);
5966 if (uts->mCanResolveLineRangeSize[subgridAxis]) {
5967 auto* subgrid =
5968 subgridFrame->GetProperty(nsGridContainerFrame::Subgrid::Prop());
5969 const GridItemInfo* originalItem = nullptr;
5970 for (const auto& item : subgrid->mGridItems) {
5971 if (item.mFrame == child) {
5972 originalItem = &item;
5973 break;
5974 }
5975 }
5976 MOZ_ASSERT(originalItem, "huh?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(originalItem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(originalItem))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("originalItem" " ("
"huh?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "originalItem"
") (" "huh?" ")"); do { MOZ_CrashSequence(__null, 5976); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5977 const auto& range = originalItem->mArea.LineRangeForAxis(subgridAxis);
5978 const nscoord sz = range.ToLength(uts->mTrackPlans[subgridAxis]);
5979 if (childWM.IsOrthogonalTo(subgridFrame->GetWritingMode())) {
5980 availBSize = sz;
5981 cbSize.BSize(childWM) = sz;
5982 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
5983 bMinSizeClamp = sz;
5984 }
5985 } else {
5986 availISize = sz;
5987 cbSize.ISize(childWM) = sz;
5988 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
5989 iMinSizeClamp = sz;
5990 }
5991 }
5992 }
5993 } else {
5994 const LogicalAxis inlineAxisInChildWM =
5995 isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
5996 const nscoord colSize = cbSize.Size(inlineAxisInChildWM, childWM);
5997 if (colSize != NS_UNCONSTRAINEDSIZE) {
5998 MOZ_ASSERT(aGridRI.mCols.mCanResolveLineRangeSize,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mCols.mCanResolveLineRangeSize)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridRI.mCols.mCanResolveLineRangeSize))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGridRI.mCols.mCanResolveLineRangeSize"
" (" "Grid column sizes should be resolvable!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mCols.mCanResolveLineRangeSize"
") (" "Grid column sizes should be resolvable!" ")"); do { MOZ_CrashSequence
(__null, 5999); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5999 "Grid column sizes should be resolvable!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mCols.mCanResolveLineRangeSize)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridRI.mCols.mCanResolveLineRangeSize))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGridRI.mCols.mCanResolveLineRangeSize"
" (" "Grid column sizes should be resolvable!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 5999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mCols.mCanResolveLineRangeSize"
") (" "Grid column sizes should be resolvable!" ")"); do { MOZ_CrashSequence
(__null, 5999); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6000 if (isOrthogonal) {
6001 availBSize = colSize;
6002 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
6003 bMinSizeClamp = colSize;
6004 }
6005 } else {
6006 availISize = colSize;
6007 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
6008 iMinSizeClamp = colSize;
6009 }
6010 }
6011 }
6012 }
6013 if (isOrthogonal == (aAxis == LogicalAxis::Inline)) {
6014 bMinSizeClamp = aMinSizeClamp;
6015 } else {
6016 iMinSizeClamp = aMinSizeClamp;
6017 }
6018 LogicalSize availableSize(childWM, availISize, availBSize);
6019 const auto measurement =
6020 ::MeasuringReflow(child, aGridRI.mReflowInput, rc, availableSize,
6021 cbSize, iMinSizeClamp, bMinSizeClamp);
6022 size = measurement.mBSize;
6023 contentBSize = measurement.mContentBSize;
6024 if (aGridRI.mIsGridIntrinsicSizing) {
6025 MarkDirtyAfterIntrinsicSizingReflow(child);
6026 }
6027 }
6028 size += child->GetLogicalUsedMargin(childWM).BStartEnd(childWM);
6029 nscoord overflow = size - aMinSizeClamp;
6030 if (MOZ_UNLIKELY(overflow > 0)(__builtin_expect(!!(overflow > 0), 0))) {
6031 nscoord newContentSize = std::max(nscoord(0), contentBSize - overflow);
6032 // XXXmats deal with percentages better, see bug 1300369 comment 27.
6033 size -= contentBSize - newContentSize;
6034 }
6035 }
6036 MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mBaselineOffset[aAxis] >= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridItem.mBaselineOffset[aAxis] >= 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aGridItem.mBaselineOffset[aAxis] >= 0"
" (" "baseline offset should be non-negative at this point" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6037)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6037); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6037 "baseline offset should be non-negative at this point")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mBaselineOffset[aAxis] >= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridItem.mBaselineOffset[aAxis] >= 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aGridItem.mBaselineOffset[aAxis] >= 0"
" (" "baseline offset should be non-negative at this point" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6037)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6037); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6038 MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6040
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6040); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6039 aGridItem.mBaselineOffset[aAxis] == nscoord(0),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6040
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6040); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6040 "baseline offset should be zero when not baseline-aligned")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6040
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0)"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6040); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6041 size += aGridItem.mBaselineOffset[aAxis];
6042 size += extraMargin;
6043 return std::max(size, 0);
6044}
6045
6046struct CachedIntrinsicSizes {
6047 CachedIntrinsicSizes() = delete;
6048 CachedIntrinsicSizes(const GridItemInfo& aGridItem,
6049 const GridReflowInput& aGridRI, const LogicalAxis aAxis)
6050 : mPercentageBasis(aGridRI.PercentageBasisFor(aAxis, aGridItem)) {}
6051
6052 void EnsureContributions(EnumSet<GridIntrinsicSizeType> aTypes,
6053 const GridItemInfo& aGridItem,
6054 const GridReflowInput& aGridRI, LogicalAxis aAxis) {
6055 // max-content and min-content should behave as initial value in block axis.
6056 // XXXalaskanemily: The specifics might have changed in the spec?
6057 // https://drafts.csswg.org/css-sizing-3/#valdef-width-min-content
6058 // https://drafts.csswg.org/css-sizing-3/#valdef-width-max-content
6059
6060 // If we need to calculate GridIntrinsicSizeType::MinContribution, we might
6061 // need to substitute GridIntrinsicSizeType::MinContentContribution instead.
6062 // Per https://drafts.csswg.org/css-grid-2/#algo-single-span-items
6063 // Section "For auto minimums":
6064 // * "if the item's computed preferred size behaves as auto or depends on
6065 // the size of its containing block in the relevant axis," then we do in
6066 // fact need the used minimum size."
6067 // * "...else the item's minimum contribution is its min-content
6068 // contribution" in which case we make a recursive call to compute
6069 // GridIntrinsicSizeType::MinContentContribution instead, and do a fixup
6070 // to place that value in the MinContentContribution slot.
6071 // Note that we use BehavesLikeInitialValue and HasPercent to implement
6072 // the spec check for "behaves as auto or depends on the size of its
6073 // containing block".
6074 // We make a similar check in MinContributionDependsOnAutoMinSize as
6075 // an earlier test for whether we need the used minimum size.
6076 if (aTypes.contains(GridIntrinsicSizeType::MinContribution)) {
6077 nsIFrame* const child = aGridItem.mFrame;
6078 const nsStylePosition* const stylePos = child->StylePosition();
6079 const auto anchorResolutionParams =
6080 AnchorPosResolutionParams::From(child);
6081 const WritingMode cbwm = aGridRI.mWM;
6082 auto styleSize = stylePos->Size(aAxis, cbwm, anchorResolutionParams);
6083 const LogicalAxis axisInItemWM =
6084 cbwm.ConvertAxisTo(aAxis, child->GetWritingMode());
6085 // FIXME: Bug 567039: moz-fit-content and -moz-available are not
6086 // supported for block size dimension on sizing properties (e.g. height),
6087 // so we treat it as `auto`.
6088 if (!styleSize->BehavesLikeInitialValue(axisInItemWM) &&
6089 !styleSize->HasPercent()) {
6090 // Calculate without MinSize, but ensuring MinContentContribution.
6091 aTypes -= GridIntrinsicSizeType::MinContribution;
6092 aTypes += GridIntrinsicSizeType::MinContentContribution;
6093 EnsureContributions(aTypes, aGridItem, aGridRI, aAxis);
6094 // Copy the MinSize from the MinContentContribution.
6095 mSizes[GridIntrinsicSizeType::MinContribution] =
6096 mSizes[GridIntrinsicSizeType::MinContentContribution];
6097 return;
6098 }
6099 }
6100
6101 for (const GridIntrinsicSizeType type : aTypes) {
6102 if (mSizes[type].isNothing()) {
6103 mSizes[type].emplace(ComputeContribution(
6104 type, aGridItem, aGridRI, aAxis, mPercentageBasis, mMinSizeClamp));
6105 }
6106 }
6107 }
6108
6109 private:
6110 // Computes the MinSize, MinContentContribution, or MaxContentContribution of
6111 // an item in the given axis.
6112 // This helps to implement EnsureContributions. It's here to prevent other
6113 // places from using it, as it is not general purpose and requires that the
6114 // caller has made checks for when we will use the MinContentContribution as
6115 // the MinSize, as EnsureContributions does.
6116 static nscoord ComputeContribution(GridIntrinsicSizeType aType,
6117 const GridItemInfo& aGridItem,
6118 const GridReflowInput& aGridRI,
6119 LogicalAxis aAxis,
6120 const LogicalSize& aPercentageBasis,
6121 nscoord aMinSizeClamp) {
6122 const WritingMode containerWM = aGridRI.mWM;
6123 gfxContext* const rc = &aGridRI.mRenderingContext;
6124 switch (aType) {
6125 case GridIntrinsicSizeType::MinContentContribution:
6126 return ContentContribution(aGridItem, aGridRI, aAxis, aPercentageBasis,
6127 IntrinsicISizeType::MinISize, aMinSizeClamp);
6128 case GridIntrinsicSizeType::MaxContentContribution:
6129 return ContentContribution(aGridItem, aGridRI, aAxis, aPercentageBasis,
6130 IntrinsicISizeType::PrefISize,
6131 aMinSizeClamp);
6132 case GridIntrinsicSizeType::MinContribution: {
6133 // Compute the min-size contribution for a grid item, as defined at
6134 // https://drafts.csswg.org/css-grid-2/#min-size-contribution
6135 nsIFrame* const child = aGridItem.mFrame;
6136 const nsStylePosition* const stylePos = child->StylePosition();
6137 const auto anchorResolutionParams =
6138 AnchorPosResolutionParams::From(child);
6139 const LogicalAxis axisInItemWM =
6140 containerWM.ConvertAxisTo(aAxis, child->GetWritingMode());
6141#ifdef DEBUG1
6142 // The caller must handle this case separately.
6143 // See EnsureContributions.
6144 {
6145 const auto styleSize =
6146 stylePos->Size(aAxis, containerWM, anchorResolutionParams);
6147 MOZ_ASSERT(styleSize->BehavesLikeInitialValue(axisInItemWM) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(styleSize->BehavesLikeInitialValue(axisInItemWM) ||
styleSize->HasPercent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(styleSize->BehavesLikeInitialValue
(axisInItemWM) || styleSize->HasPercent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
" (" "Should have been caught in EnsureContributions" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6149); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6148 styleSize->HasPercent(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(styleSize->BehavesLikeInitialValue(axisInItemWM) ||
styleSize->HasPercent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(styleSize->BehavesLikeInitialValue
(axisInItemWM) || styleSize->HasPercent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
" (" "Should have been caught in EnsureContributions" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6149); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6149 "Should have been caught in EnsureContributions")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(styleSize->BehavesLikeInitialValue(axisInItemWM) ||
styleSize->HasPercent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(styleSize->BehavesLikeInitialValue
(axisInItemWM) || styleSize->HasPercent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
" (" "Should have been caught in EnsureContributions" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6149); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6150 }
6151#endif
6152 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6153 // This calculates the min-content contribution from either a definite
6154 // min-width (or min-height depending on aAxis), or the
6155 // "specified / transferred size" for min-width:auto if
6156 // overflow == visible (as min-width:0 otherwise), or
6157 // NS_UNCONSTRAINEDSIZE for other min-width intrinsic values
6158 // (which results in always taking the "content size" part below).
6159 MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mBaselineOffset[aAxis] >= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridItem.mBaselineOffset[aAxis] >= 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aGridItem.mBaselineOffset[aAxis] >= 0"
" (" "baseline offset should be non-negative at this point" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6160)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6160); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6160 "baseline offset should be non-negative at this point")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItem.mBaselineOffset[aAxis] >= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridItem.mBaselineOffset[aAxis] >= 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aGridItem.mBaselineOffset[aAxis] >= 0"
" (" "baseline offset should be non-negative at this point" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6160)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6160); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6161 MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6163
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6163); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6162 aGridItem.mBaselineOffset[aAxis] == (nscoord)0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6163
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6163); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6163 "baseline offset should be zero when not baseline-aligned")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned
) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
" (" "baseline offset should be zero when not baseline-aligned"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6163
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == (nscoord)0"
") (" "baseline offset should be zero when not baseline-aligned"
")"); do { MOZ_CrashSequence(__null, 6163); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6164 const auto styleMinSize =
6165 stylePos->MinSize(aAxis, containerWM, anchorResolutionParams);
6166
6167 // max-content and min-content should behave as initial value in block
6168 // axis.
6169 // FIXME: Bug 567039: moz-fit-content and -moz-available are not
6170 // supported for block size dimension on sizing properties
6171 // (e.g. height), so we treat it as `auto`.
6172 const bool isAuto = styleMinSize->BehavesLikeInitialValue(axisInItemWM);
6173 nscoord s = aGridItem.mBaselineOffset[aAxis];
6174
6175 // Check if the min-size style of the grid item is auto and the
6176 // minimum contribution is content-based.
6177 // While the eContentBasedAutoMinSize flag is not synonymous with
6178 // an item having content-based automatic minimum contribution,
6179 // the previous checks should catch the other cases in which the
6180 // automatic minimum contribution is zero instead.
6181 //
6182 // See bug 1951821 for this discrepency between the flag's usage
6183 // and the specification:
6184 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6185 if (!isAuto ||
6186 (aGridItem.mState[aAxis] & ItemState::eContentBasedAutoMinSize)) {
6187 nscoord contrib = nsLayoutUtils::MinSizeContributionForAxis(
6188 containerWM.PhysicalAxis(aAxis), rc, child,
6189 IntrinsicISizeType::MinISize, aPercentageBasis);
6190 if (contrib == NS_UNCONSTRAINEDSIZE) {
6191 s = contrib;
6192 } else {
6193 s += contrib;
6194 }
6195
6196 if ((axisInItemWM == LogicalAxis::Inline &&
6197 nsIFrame::ToExtremumLength(*styleMinSize)) ||
6198 (isAuto && !child->StyleDisplay()->IsScrollableOverflow())) {
6199 // "if the item's computed preferred size behaves as auto or
6200 // depends on the size of its containing block in the relevant
6201 // axis, its minimum contribution is the outer size that would
6202 // result from assuming the item's used minimum size as its
6203 // preferred size"
6204 //
6205 // The "auto or depends on the size of its containing block" is
6206 // checked above with ItemState::eContentBasedAutoMinSize.
6207 //
6208 // https://drafts.csswg.org/css-grid-2/#minimum-contribution
6209 StyleSizeOverrides overrides;
6210 if (axisInItemWM == LogicalAxis::Inline) {
6211 overrides.mStyleISize.emplace(*styleMinSize.get());
6212 } else {
6213 overrides.mStyleBSize.emplace(*styleMinSize.get());
6214 }
6215 // Now calculate the "content size" part and return whichever is
6216 // smaller.
6217 MOZ_ASSERT(isAuto || s == NS_UNCONSTRAINEDSIZE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isAuto || s == NS_UNCONSTRAINEDSIZE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isAuto || s == NS_UNCONSTRAINEDSIZE
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"isAuto || s == NS_UNCONSTRAINEDSIZE", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isAuto || s == NS_UNCONSTRAINEDSIZE"
")"); do { MOZ_CrashSequence(__null, 6217); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6218 s = std::min(s, ContentContribution(aGridItem, aGridRI, aAxis,
6219 aPercentageBasis,
6220 IntrinsicISizeType::MinISize,
6221 aMinSizeClamp, overrides));
6222 }
6223 }
6224 return s;
6225 }
6226 }
6227 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected contribution type")do { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected contribution type" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected contribution type" ")"
); do { MOZ_CrashSequence(__null, 6227); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); __builtin_unreachable
(); } while (false)
;
6228 }
6229
6230 public:
6231 EnumeratedArray<GridIntrinsicSizeType, nscoord> SizesOrDefault() const {
6232 EnumeratedArray<GridIntrinsicSizeType, nscoord> sizes;
6233 for (GridIntrinsicSizeType type : kAllGridIntrinsicSizeTypes) {
6234 sizes[type] = mSizes[type].valueOr(0);
6235 }
6236 return sizes;
6237 }
6238
6239 EnumeratedArray<GridIntrinsicSizeType, Maybe<nscoord>> mSizes;
6240
6241 // The item's percentage basis for intrinsic sizing purposes.
6242 const LogicalSize mPercentageBasis;
6243
6244 // "if the grid item spans only grid tracks that have a fixed max track
6245 // sizing function, its automatic minimum size in that dimension is
6246 // further clamped to less than or equal to the size necessary to fit its
6247 // margin box within the resulting grid area (flooring at zero)"
6248 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6249 // This is the clamp value to use for that:
6250 nscoord mMinSizeClamp = NS_MAXSIZE;
6251};
6252
6253void nsGridContainerFrame::Tracks::CalculateSizes(
6254 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
6255 const TrackSizingFunctions& aFunctions, nscoord aContentBoxSize,
6256 LineRange GridArea::* aRange, SizingConstraint aConstraint) {
6257 // Implement the intrinsic sizing algorithm, step 12.5 as described in:
6258 // https://drafts.csswg.org/css-grid-2/#algo-content
6259 nscoord percentageBasis = aContentBoxSize;
6260 if (percentageBasis == NS_UNCONSTRAINEDSIZE) {
6261 percentageBasis = 0;
6262 }
6263 // 12.5 step 1: Shim baseline-aligned items so their intrinsic size
6264 // contributions reflect their baseline alignment
6265 // https://drafts.csswg.org/css-grid-2/#algo-baseline-shims
6266 InitializeItemBaselines(aGridRI, aGridItems);
6267
6268 // 12.5 steps 2-5
6269 ResolveIntrinsicSize(aGridRI, aGridItems, aFunctions, aRange, percentageBasis,
6270 aConstraint);
6271
6272 // Neither 12.6 nor 12.7 will occur under min content constraint.
6273 if (aConstraint != SizingConstraint::MinContent) {
6274 nscoord freeSpace = aContentBoxSize;
6275 if (freeSpace != NS_UNCONSTRAINEDSIZE) {
6276 freeSpace -= SumOfGridGaps();
6277 }
6278 // 12.6 maximize tracks by distributing free space.
6279 // https://drafts.csswg.org/css-grid-2/#algo-grow-tracks
6280 DistributeFreeSpace(freeSpace);
6281
6282 // 12.7 Expand flexible tracks.
6283 // https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
6284 StretchFlexibleTracks(aGridRI, aGridItems, aFunctions, freeSpace);
6285 }
6286}
6287
6288TrackSize::StateBits nsGridContainerFrame::Tracks::StateBitsForRange(
6289 const LineRange& aRange) const {
6290 MOZ_ASSERT(!aRange.IsAuto(), "must have a definite range")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aRange.IsAuto())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aRange.IsAuto()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aRange.IsAuto()"
" (" "must have a definite range" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aRange.IsAuto()"
") (" "must have a definite range" ")"); do { MOZ_CrashSequence
(__null, 6290); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6291 TrackSize::StateBits state = TrackSize::StateBits::eNone;
6292 for (auto i : aRange.Range()) {
6293 state |= mSizes[i].mState;
6294 }
6295 return state;
6296}
6297
6298static void AddSubgridContribution(TrackSize& aSize,
6299 nscoord aMarginBorderPadding) {
6300 if (aSize.mState & TrackSize::eIntrinsicMinSizing) {
6301 aSize.mBase = std::max(aSize.mBase, aMarginBorderPadding);
6302 aSize.mLimit = std::max(aSize.mLimit, aSize.mBase);
6303 }
6304 // XXX maybe eFlexMaxSizing too?
6305 // (once we implement https://github.com/w3c/csswg-drafts/issues/2177)
6306 if (aSize.mState &
6307 (TrackSize::eIntrinsicMaxSizing | TrackSize::eApplyFitContentClamping)) {
6308 aSize.mLimit = std::max(aSize.mLimit, aMarginBorderPadding);
6309 }
6310}
6311
6312Maybe<nscoord> nsGridContainerFrame::Tracks::ComputeMinSizeClamp(
6313 const TrackSizingFunctions& aFunctions, nscoord aPercentageBasis,
6314 const LineRange& aLineRange, const TrackSize::StateBits aState) const {
6315 if (!TrackSize::IsDefiniteMaxSizing(aState)) {
6316 return Nothing();
6317 }
6318 nscoord minSizeClamp = 0;
6319 for (auto i : aLineRange.Range()) {
6320 minSizeClamp +=
6321 aFunctions.MaxSizingFor(i).AsBreadth().Resolve(aPercentageBasis);
6322 }
6323 minSizeClamp += mGridGap * (aLineRange.Extent() - 1);
6324 return Some(minSizeClamp);
6325}
6326
6327void nsGridContainerFrame::Tracks::ResolveIntrinsicSizeForNonSpanningItems(
6328 GridReflowInput& aGridRI, const TrackSizingFunctions& aFunctions,
6329 nscoord aPercentageBasis, SizingConstraint aConstraint,
6330 const LineRange& aRange, const GridItemInfo& aGridItem) {
6331 // Calculate track sizes for fit non-spanning items.
6332 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
6333 CachedIntrinsicSizes cache{aGridItem, aGridRI, mAxis};
6334 TrackSize& sz = mSizes[aRange.mStart];
6335
6336 // Contribution type to use as the base size.
6337 // This is a Maybe as we might not need to calculate a contribution at all,
6338 // for instance if the base sizing function is a definite length.
6339 Maybe<GridIntrinsicSizeType> baseSizeType;
6340 if (sz.mState & TrackSize::eAutoMinSizing) {
6341 // "For auto minimums:"
6342 // "If the track has an 'auto' min track sizing function and the grid
6343 // container is being sized under a min-/max-content constraint, set
6344 // the track's base size to the maximum of its items' limited
6345 // min-content contributions"
6346 if (aGridItem.MinContributionDependsOnAutoMinSize(aGridRI.mWM, mAxis)) {
6347 // Clamp it if it's spanning a definite track max-sizing function.
6348 if (const Maybe<nscoord> minSizeClamp =
6349 ComputeMinSizeClamp(aFunctions, aPercentageBasis, aRange)) {
6350 cache.mMinSizeClamp = *minSizeClamp;
6351 aGridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
6352 }
6353 // Use the content-based contribution.
6354 baseSizeType.emplace((aConstraint == SizingConstraint::MaxContent)
6355 ? GridIntrinsicSizeType::MaxContentContribution
6356 : GridIntrinsicSizeType::MinContentContribution);
6357 } else {
6358 // Use the minimum contribution.
6359 // Note that this could still become MinContentContribution in practice.
6360 // MinContributionDependsOnAutoMinSize can return false when the item's
6361 // size depends on the size of its containing block. In that case, using
6362 // EnsureContributions to compute MinSize will instead compute
6363 // MinContentContribution, which will then be placed in the MinSize
6364 // slot on the cache.
6365 baseSizeType.emplace(GridIntrinsicSizeType::MinContribution);
6366 }
6367 } else if (sz.mState & TrackSize::eMinContentMinSizing) {
6368 // "For min-content minimums:"
6369 // "If the track has a 'min-content' min track sizing function, set its
6370 // base size to the maximum of the items' min-content contributions"
6371 baseSizeType.emplace(GridIntrinsicSizeType::MinContentContribution);
6372 } else if (sz.mState & TrackSize::eMaxContentMinSizing) {
6373 // "For max-content minimums:"
6374 // "If the track has a 'max-content' min track sizing function, set its
6375 // base size to the maximum of the items' max-content contributions"
6376 baseSizeType.emplace(GridIntrinsicSizeType::MaxContentContribution);
6377 }
6378
6379 // Size of fit-content maximum, if any.
6380 Maybe<nscoord> fitContentClamp;
6381 // Contribution type to use as the growth limit.
6382 // This is a Maybe as we might not need to calculate a contribution at all,
6383 // for instance if the growth limit sizing function is a definite length.
6384 Maybe<GridIntrinsicSizeType> limitType;
6385 if (sz.mState & TrackSize::eMinContentMaxSizing) {
6386 // "For min-content maximums:"
6387 // "If the track has a 'min-content' max track sizing function, set its
6388 // growth limit to the maximum of the items' min-content contributions"
6389 limitType.emplace(GridIntrinsicSizeType::MinContentContribution);
6390 } else if (sz.mState &
6391 (TrackSize::eAutoMaxSizing | TrackSize::eMaxContentMaxSizing)) {
6392 // "For max-content maximums:"
6393 // "If the track has a 'max-content' max track sizing function, set its
6394 // growth limit to the maximum of the items' max-content contributions"
6395 limitType.emplace(GridIntrinsicSizeType::MaxContentContribution);
6396 if (MOZ_UNLIKELY(sz.mState & TrackSize::eApplyFitContentClamping)(__builtin_expect(!!(sz.mState & TrackSize::eApplyFitContentClamping
), 0))
) {
6397 // "For fit-content() maximums, furthermore clamp this growth limit by
6398 // the fit-content() argument."
6399 fitContentClamp.emplace(aFunctions.SizingFor(aRange.mStart)
6400 .AsFitContent()
6401 .AsBreadth()
6402 .Resolve(aPercentageBasis));
6403 }
6404 }
6405
6406 // Even if it was possible to use the minimum contribution as the limit in
6407 // the spec, this could get trashed by the checks for whether the item's auto
6408 // minimum size depends on the size implemented in
6409 // GridItemInfo::MinContributionDependsOnAutoMinSize and
6410 // CachedIntrinsicSizes::EnsureContributions.
6411 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(limitType != Some(GridIntrinsicSizeType::MinContribution
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(limitType != Some(GridIntrinsicSizeType::MinContribution
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("limitType != Some(GridIntrinsicSizeType::MinContribution)" " ("
"We should never be using the minimum contribution as the limit size."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6413
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6413); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6412 limitType != Some(GridIntrinsicSizeType::MinContribution),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(limitType != Some(GridIntrinsicSizeType::MinContribution
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(limitType != Some(GridIntrinsicSizeType::MinContribution
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("limitType != Some(GridIntrinsicSizeType::MinContribution)" " ("
"We should never be using the minimum contribution as the limit size."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6413
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6413); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6413 "We should never be using the minimum contribution as the limit size.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(limitType != Some(GridIntrinsicSizeType::MinContribution
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(limitType != Some(GridIntrinsicSizeType::MinContribution
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("limitType != Some(GridIntrinsicSizeType::MinContribution)" " ("
"We should never be using the minimum contribution as the limit size."
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6413
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6413); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6414
6415 // Accumulate the required size types and compute the contributions.
6416 {
6417 EnumSet<GridIntrinsicSizeType> sizeTypesToCalculate;
6418 for (const auto& maybeType : {baseSizeType, limitType}) {
6419 if (maybeType) {
6420 sizeTypesToCalculate += *maybeType;
6421 }
6422 }
6423 cache.EnsureContributions(sizeTypesToCalculate, aGridItem, aGridRI, mAxis);
6424 }
6425
6426 if (baseSizeType) {
6427 sz.mBase = std::max(sz.mBase, *cache.mSizes[*baseSizeType]);
6428 }
6429
6430 // Limit based on max size type.
6431 if (limitType) {
6432 if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
6433 sz.mLimit = 0; // Use only the contribution instead.
6434 }
6435 sz.mLimit = std::max(sz.mLimit, *cache.mSizes[*limitType]);
6436 if (fitContentClamp) {
6437 // "furthermore clamp this growth limit by the fit-content() argument."
6438 sz.mLimit = std::min(sz.mLimit, *fitContentClamp);
6439 }
6440 }
6441
6442 // "In all cases, if a track's growth limit is now less than its base size,
6443 // increase the growth limit to match the base size."
6444 sz.mLimit = std::max(sz.mLimit, sz.mBase);
6445}
6446
6447void nsGridContainerFrame::Tracks::CalculateItemBaselines(
6448 nsTArray<ItemBaselineData>& aBaselineItems,
6449 BaselineSharingGroup aBaselineGroup) {
6450 if (aBaselineItems.IsEmpty()) {
6451 return;
6452 }
6453
6454 // Sort the collected items on their baseline track.
6455 std::sort(aBaselineItems.begin(), aBaselineItems.end(),
6456 ItemBaselineData::IsBaselineTrackLessThan);
6457
6458 MOZ_ASSERT(mSizes.Length() > 0, "having an item implies at least one track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSizes.Length() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSizes.Length() > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mSizes.Length() > 0"
" (" "having an item implies at least one track" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6458); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSizes.Length() > 0"
") (" "having an item implies at least one track" ")"); do {
MOZ_CrashSequence(__null, 6458); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6459
6460 // Make sure we have enough space to store the baselines. Use the highest
6461 // track number (+1 to account for the 0 based indexing).
6462 auto baselineCount = aBaselineItems.LastElement().mBaselineTrack + 1;
6463 mBaselines.EnsureLengthAtLeast(baselineCount);
6464
6465 nscoord maxBaseline = 0;
6466 nscoord maxDescent = 0;
6467 uint32_t currentTrack = kAutoLine; // guaranteed to not match any item
6468 uint32_t trackStartIndex = 0;
6469 for (uint32_t i = 0, len = aBaselineItems.Length(); true; ++i) {
6470 // Find the maximum baseline and descent in the current track.
6471 if (i != len) {
6472 const ItemBaselineData& item = aBaselineItems[i];
6473 if (currentTrack == item.mBaselineTrack) {
6474 maxBaseline = std::max(maxBaseline, item.mBaseline);
6475 maxDescent = std::max(maxDescent, item.mSize - item.mBaseline);
6476 continue;
6477 }
6478 }
6479 // Iterate the current track again and update the baseline offsets making
6480 // all items baseline-aligned within this group in this track.
6481 for (uint32_t j = trackStartIndex; j < i; ++j) {
6482 const ItemBaselineData& item = aBaselineItems[j];
6483 item.mGridItem->mBaselineOffset[mAxis] = maxBaseline - item.mBaseline;
6484 MOZ_ASSERT(item.mGridItem->mBaselineOffset[mAxis] >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item.mGridItem->mBaselineOffset[mAxis] >= 0)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(item.mGridItem->mBaselineOffset[mAxis] >= 0)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("item.mGridItem->mBaselineOffset[mAxis] >= 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6484)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mGridItem->mBaselineOffset[mAxis] >= 0"
")"); do { MOZ_CrashSequence(__null, 6484); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6485 }
6486 if (i != 0) {
6487 // Store the size of this baseline-aligned subtree.
6488 mSizes[currentTrack].mBaselineSubtreeSize[aBaselineGroup] =
6489 maxBaseline + maxDescent;
6490
6491 // Record the baseline for the current track.
6492 mBaselines[currentTrack][aBaselineGroup] = Some(maxBaseline);
6493 }
6494 if (i == len) {
6495 break;
6496 }
6497 // Initialize data for the next track with baseline-aligned items.
6498 const ItemBaselineData& item = aBaselineItems[i];
6499 currentTrack = item.mBaselineTrack;
6500 trackStartIndex = i;
6501 maxBaseline = item.mBaseline;
6502 maxDescent = item.mSize - item.mBaseline;
6503 }
6504}
6505
6506void nsGridContainerFrame::Tracks::InitializeItemBaselines(
6507 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems) {
6508 MOZ_ASSERT(!mIsMasonry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsMasonry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsMasonry))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mIsMasonry", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mIsMasonry"
")"); do { MOZ_CrashSequence(__null, 6508); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6509 if (aGridRI.mFrame->IsSubgrid(mAxis)) {
6510 // A grid container's subgridded axis doesn't have a baseline.
6511 return;
6512 }
6513
6514 nsTArray<ItemBaselineData> firstBaselineItems;
6515 nsTArray<ItemBaselineData> lastBaselineItems;
6516 const WritingMode containerWM = aGridRI.mWM;
6517 ComputedStyle* containerStyle = aGridRI.mFrame->Style();
6518
6519 for (GridItemInfo& gridItem : aGridItems) {
6520 if (gridItem.IsSubgrid(mAxis)) {
6521 // A subgrid itself is never baseline-aligned.
6522 continue;
6523 }
6524
6525 nsIFrame* child = gridItem.mFrame;
6526 uint32_t baselineTrack = kAutoLine;
6527 auto state = ItemState(0);
6528 const auto childWM = child->GetWritingMode();
6529
6530 const bool isOrthogonal = containerWM.IsOrthogonalTo(childWM);
6531 const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
6532 const bool itemHasBaselineParallelToTrack = isInlineAxis == isOrthogonal;
6533
6534 // [align|justify]-self:[last ]baseline.
6535 auto selfAlignment =
6536 child->StylePosition()->UsedSelfAlignment(mAxis, containerStyle);
6537 selfAlignment &= ~StyleAlignFlags::FLAG_BITS;
6538 if (selfAlignment == StyleAlignFlags::BASELINE) {
6539 state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
6540 } else if (selfAlignment == StyleAlignFlags::LAST_BASELINE) {
6541 state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
6542 }
6543
6544 // https://drafts.csswg.org/css-align-3/#baseline-align-content
6545 // Baseline content-alignment can only apply if the align-content axis is
6546 // parallel with the box’s block axis; otherwise the fallback alignment is
6547 // used.
6548 if (!isInlineAxis) {
6549 // Handle align-content:[last ]baseline (if present)
6550 auto alignContent = child->StylePosition()->mAlignContent.primary;
6551 alignContent &= ~StyleAlignFlags::FLAG_BITS;
6552 if (alignContent == StyleAlignFlags::BASELINE ||
6553 alignContent == StyleAlignFlags::LAST_BASELINE) {
6554 const auto selfAlignEdge = alignContent == StyleAlignFlags::BASELINE
6555 ? StyleAlignFlags::SELF_START
6556 : StyleAlignFlags::SELF_END;
6557 bool validCombo = selfAlignment == StyleAlignFlags::NORMAL ||
6558 selfAlignment == StyleAlignFlags::STRETCH ||
6559 selfAlignment == selfAlignEdge;
6560 if (!validCombo) {
6561 // We're doing alignment in the axis that's orthogonal to mAxis here.
6562 LogicalAxis alignAxis = GetOrthogonalAxis(mAxis);
6563 // |sameSide| is true if the container's start side in this axis is
6564 // the same as the child's start side, in the child's parallel axis.
6565 bool sameSide =
6566 containerWM.ParallelAxisStartsOnSameSide(alignAxis, childWM);
6567 if (selfAlignment == StyleAlignFlags::LEFT) {
6568 selfAlignment = containerWM.IsBidiLTR() ? StyleAlignFlags::START
6569 : StyleAlignFlags::END;
6570 } else if (selfAlignment == StyleAlignFlags::RIGHT) {
6571 selfAlignment = StyleAlignFlags::START;
6572 }
6573
6574 if (selfAlignment == StyleAlignFlags::START ||
6575 selfAlignment == StyleAlignFlags::FLEX_START) {
6576 validCombo =
6577 sameSide == (alignContent == StyleAlignFlags::BASELINE);
6578 } else if (selfAlignment == StyleAlignFlags::END ||
6579 selfAlignment == StyleAlignFlags::FLEX_END) {
6580 validCombo =
6581 sameSide == (alignContent == StyleAlignFlags::LAST_BASELINE);
6582 }
6583 }
6584 if (validCombo) {
6585 const GridArea& area = gridItem.mArea;
6586 if (alignContent == StyleAlignFlags::BASELINE) {
6587 state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
6588 baselineTrack = area.mRows.mStart;
6589 } else if (alignContent == StyleAlignFlags::LAST_BASELINE) {
6590 state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
6591 baselineTrack = area.mRows.mEnd - 1;
Value stored to 'baselineTrack' is never read
6592 }
6593 }
6594 }
6595 }
6596
6597 if (state & ItemState::eIsBaselineAligned) {
6598 // The item is baseline aligned, so calculate the baseline sharing group.
6599 // <https://drafts.csswg.org/css-align-3/#baseline-terms>
6600 bool isFirstBaseline = (state & ItemState::eFirstBaseline) != 0;
6601 BaselineSharingGroup baselineAlignment = isFirstBaseline
6602 ? BaselineSharingGroup::First
6603 : BaselineSharingGroup::Last;
6604 // Baseline alignment occurs along `mAxis`, but baselines are defined in
6605 // the orthogonal axis (the axis of the baseline context that defines the
6606 // baseline sharing group).
6607 auto baselineWM = WritingMode::DetermineWritingModeForBaselineSynthesis(
6608 containerWM, childWM, GetOrthogonalAxis(mAxis));
6609
6610 auto sameSideInBaselineWM =
6611 containerWM.ParallelAxisStartsOnSameSide(mAxis, baselineWM);
6612 auto baselineSharingGroup = BaselineSharingGroup::First;
6613 if (sameSideInBaselineWM != isFirstBaseline) {
6614 baselineSharingGroup = BaselineSharingGroup::Last;
6615 state |= ItemState::eLastBaselineSharingGroup;
6616
6617 baselineTrack = (isInlineAxis ? gridItem.mArea.mCols.mEnd
6618 : gridItem.mArea.mRows.mEnd) -
6619 1;
6620 } else {
6621 baselineTrack = isInlineAxis ? gridItem.mArea.mCols.mStart
6622 : gridItem.mArea.mRows.mStart;
6623 }
6624
6625 // XXXmats if |child| is a descendant of a subgrid then the metrics
6626 // below needs to account for the accumulated MPB somehow...
6627
6628 auto* rc = &aGridRI.mRenderingContext;
6629 // XXX figure out if we can avoid/merge this reflow with the main reflow.
6630 // XXX (after bug 1174569 is sorted out)
6631 //
6632 // XXX How should we handle percentage padding here? (bug 1330866)
6633 // XXX (see ::ContentContribution and how it deals with percentages)
6634 // XXX What if the true baseline after line-breaking differs from this
6635 // XXX hypothetical baseline based on an infinite inline size?
6636 // XXX Maybe we should just call ::ContentContribution here instead?
6637 const LogicalSize cbSize = aGridRI.PercentageBasisFor(mAxis, gridItem);
6638 LogicalSize avail(childWM, INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60)), NS_UNCONSTRAINEDSIZE);
6639 const LogicalAxis inlineAxisInChildWM =
6640 isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
6641 const nscoord colSize = cbSize.Size(inlineAxisInChildWM, childWM);
6642 if (colSize != NS_UNCONSTRAINEDSIZE) {
6643 avail.Size(inlineAxisInChildWM, childWM) = colSize;
6644 }
6645 ::MeasuringReflow(child, aGridRI.mReflowInput, rc, avail, cbSize);
6646
6647 nsGridContainerFrame* grid = do_QueryFrame(child);
6648 auto frameSize =
6649 isInlineAxis ? child->ISize(containerWM) : child->BSize(containerWM);
6650 auto margin = child->GetLogicalUsedMargin(containerWM);
6651 auto alignSize =
6652 frameSize + (isInlineAxis ? margin.IStartEnd(containerWM)
6653 : margin.BStartEnd(containerWM));
6654
6655 Maybe<nscoord> baseline;
6656 if (grid) {
6657 baseline.emplace((isOrthogonal == isInlineAxis)
6658 ? grid->GetBBaseline(baselineAlignment)
6659 : grid->GetIBaseline(baselineAlignment));
6660 } else {
6661 if (itemHasBaselineParallelToTrack) {
6662 baseline = child->GetNaturalBaselineBOffset(
6663 childWM, baselineAlignment, BaselineExportContext::Other);
6664 }
6665
6666 if (!baseline) {
6667 // If baseline alignment is specified on a grid item whose size in
6668 // that axis depends on the size of an intrinsically-sized track, that
6669 // item does not participate in baseline alignment, and instead uses
6670 // its fallback alignment as if that were originally specified.
6671 // https://drafts.csswg.org/css-grid-2/#row-align
6672
6673 // Check if the item crosses any tracks that are intrinsically sized.
6674 auto range = gridItem.mArea.LineRangeForAxis(mAxis).Range();
6675 auto isTrackAutoSize =
6676 std::find_if(range.begin(), range.end(), [&](auto track) {
6677 constexpr auto intrinsicSizeFlags =
6678 TrackSize::eIntrinsicMinSizing |
6679 TrackSize::eIntrinsicMaxSizing |
6680 TrackSize::eApplyFitContentClamping |
6681 TrackSize::eFlexMaxSizing;
6682 return (mSizes[track].mState & intrinsicSizeFlags) != 0;
6683 }) != range.end();
6684
6685 // If either the track or the item is not auto sized, then the item
6686 // participates in baseline alignment.
6687 if (!isTrackAutoSize ||
6688 !gridItem.IsBSizeDependentOnContainerSize(containerWM)) {
6689 // We're synthesizing the baseline from the child's border-box
6690 // (frameSize is the size of the border-box). See:
6691 // https://drafts.csswg.org/css-align-3/#baseline-export.
6692
6693 if (containerWM.IsCentralBaseline()) {
6694 // We want to use the exact same central position within the
6695 // frame, regardless of which side we're measuring from. To
6696 // achieve that, we round *up* if we're in the first baseline
6697 // sharing group, and *down* if we're in the last baseline sharing
6698 // group.
6699 const bool isFirstBaselineSharingGroup =
6700 baselineSharingGroup == BaselineSharingGroup::First;
6701 baseline.emplace(frameSize / 2 + (isFirstBaselineSharingGroup
6702 ? 0
6703 : frameSize % 2));
6704 } else {
6705 // The baseline offset is measured from the block-{start,end} edge
6706 // of the container, using the block axis of 'baselineWM' (which
6707 // may differ from the child or container’s writing mode).
6708 //
6709 // If we're synthesizing a baseline from the edge nearest to the
6710 // container's reference side (start for the first baseline group,
6711 // end for the last), the offset is `0`. Otherwise, it's from the
6712 // opposite edge, so we use `frameSize`.
6713 //
6714 // This logic depends on whether we're in the first or last
6715 // baseline-sharing group, and whether the line is inverted (e.g.,
6716 // in vertical-rl mode), which affects which edge is considered
6717 // the "start" or "end".
6718 baseline.emplace((isFirstBaseline == baselineWM.IsLineInverted())
6719 ? 0
6720 : frameSize);
6721 }
6722 }
6723 }
6724 }
6725
6726 if (baseline) {
6727 nscoord finalBaseline = *baseline;
6728 NS_ASSERTION(finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN,do { if (!(finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6729)
; MOZ_PretendNoReturn(); } } while (0)
6729 "about to use an unknown baseline")do { if (!(finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6729)
; MOZ_PretendNoReturn(); } } while (0)
;
6730
6731 nscoord marginAdjust = 0;
6732 if (baselineSharingGroup == BaselineSharingGroup::First) {
6733 marginAdjust = isInlineAxis ? margin.IStart(containerWM)
6734 : margin.BStart(containerWM);
6735 } else {
6736 marginAdjust = isInlineAxis ? margin.IEnd(containerWM)
6737 : margin.BEnd(containerWM);
6738
6739 // This flag is used in ::AlignSelf(...) to check whether the item is
6740 // last baseline aligned, but this flag should go away.
6741 state |= GridItemInfo::eEndSideBaseline;
6742 }
6743 finalBaseline += marginAdjust;
6744
6745 auto& baselineItems =
6746 (baselineSharingGroup == BaselineSharingGroup::First)
6747 ? firstBaselineItems
6748 : lastBaselineItems;
6749 baselineItems.AppendElement(ItemBaselineData{
6750 baselineTrack, finalBaseline, alignSize, &gridItem});
6751 } else {
6752 state &= ~ItemState::eAllBaselineBits;
6753 }
6754
6755 if (aGridRI.mIsGridIntrinsicSizing) {
6756 MarkDirtyAfterIntrinsicSizingReflow(child);
6757 }
6758 }
6759
6760 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6763); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6763); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6761 (state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) !=do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6763); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6763); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6762 (ItemState::eFirstBaseline | ItemState::eLastBaseline),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6763); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6763); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6763 "first/last baseline bits are mutually exclusive")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6763); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6763); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6764 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6767); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6765 (state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) !=do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6767); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6766 (ItemState::eSelfBaseline | ItemState::eContentBaseline),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6767); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6767 "*-self and *-content baseline bits are mutually exclusive")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6767); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6768 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6771
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6769 !(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6771
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6770 !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6771
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6771 "first/last bit requires self/content bit and vice versa")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6771
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6771); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6772
6773 gridItem.mState[mAxis] |= state;
6774 gridItem.mBaselineOffset[mAxis] = nscoord(0);
6775 }
6776
6777 if (firstBaselineItems.IsEmpty() && lastBaselineItems.IsEmpty()) {
6778 return;
6779 }
6780
6781 // TODO: CSS Align spec issue - how to align a baseline subtree in a track?
6782 // https://lists.w3.org/Archives/Public/www-style/2016May/0141.html
6783 mBaselineSubtreeAlign[BaselineSharingGroup::First] = StyleAlignFlags::START;
6784 mBaselineSubtreeAlign[BaselineSharingGroup::Last] = StyleAlignFlags::END;
6785
6786 CalculateItemBaselines(firstBaselineItems, BaselineSharingGroup::First);
6787 CalculateItemBaselines(lastBaselineItems, BaselineSharingGroup::Last);
6788}
6789
6790// TODO: we store the wrong baseline group offset in some cases (bug 1632200)
6791void nsGridContainerFrame::Tracks::InitializeItemBaselinesInMasonryAxis(
6792 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
6793 BaselineAlignmentSet aSet, const nsSize& aContainerSize,
6794 nsTArray<nscoord>& aTrackSizes,
6795 nsTArray<ItemBaselineData>& aFirstBaselineItems,
6796 nsTArray<ItemBaselineData>& aLastBaselineItems) {
6797 MOZ_ASSERT(mIsMasonry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIsMasonry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIsMasonry))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mIsMasonry", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIsMasonry"
")"); do { MOZ_CrashSequence(__null, 6797); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6798 WritingMode wm = aGridRI.mWM;
6799 ComputedStyle* containerSC = aGridRI.mFrame->Style();
6800 for (GridItemInfo& gridItem : aGridItems) {
6801 if (gridItem.IsSubgrid(mAxis)) {
6802 // A subgrid itself is never baseline-aligned.
6803 continue;
6804 }
6805 const auto& area = gridItem.mArea;
6806 if (aSet.mItemSet == BaselineAlignmentSet::LastItems) {
6807 // NOTE: eIsLastItemInMasonryTrack is set also if the item is the ONLY
6808 // item in its track; the eIsBaselineAligned check excludes it though
6809 // since it participates in the start baseline groups in that case.
6810 //
6811 // XXX what if it's the only item in THAT baseline group?
6812 // XXX should it participate in the last-item group instead then
6813 // if there are more baseline-aligned items there?
6814 if (!(gridItem.mState[mAxis] & ItemState::eIsLastItemInMasonryTrack) ||
6815 (gridItem.mState[mAxis] & ItemState::eIsBaselineAligned)) {
6816 continue;
6817 }
6818 } else {
6819 if (area.LineRangeForAxis(mAxis).mStart > 0 ||
6820 (gridItem.mState[mAxis] & ItemState::eIsBaselineAligned)) {
6821 continue;
6822 }
6823 }
6824 if (!aSet.MatchTrackAlignment(StyleAlignFlags::START)) {
6825 continue;
6826 }
6827
6828 nsIFrame* child = gridItem.mFrame;
6829 uint32_t baselineTrack = kAutoLine;
6830 auto state = ItemState(0);
6831 auto childWM = child->GetWritingMode();
6832 const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
6833 const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
6834 // XXX update the line below to include orthogonal grid/table boxes
6835 // XXX since they have baselines in both dimensions. And flexbox with
6836 // XXX reversed main/cross axis?
6837 const bool itemHasBaselineParallelToTrack = isInlineAxis == isOrthogonal;
6838 if (itemHasBaselineParallelToTrack) {
6839 const auto* pos = child->StylePosition();
6840 // [align|justify]-self:[last ]baseline.
6841 auto selfAlignment = pos->UsedSelfAlignment(mAxis, containerSC);
6842 selfAlignment &= ~StyleAlignFlags::FLAG_BITS;
6843 if (selfAlignment == StyleAlignFlags::BASELINE) {
6844 state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
6845 baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
6846 } else if (selfAlignment == StyleAlignFlags::LAST_BASELINE) {
6847 state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
6848 baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
6849 } else {
6850 // [align|justify]-content:[last ]baseline.
6851 auto childAxis = isOrthogonal ? GetOrthogonalAxis(mAxis) : mAxis;
6852 auto alignContent = pos->UsedContentAlignment(childAxis).primary;
6853 alignContent &= ~StyleAlignFlags::FLAG_BITS;
6854 if (alignContent == StyleAlignFlags::BASELINE) {
6855 state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
6856 baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
6857 } else if (alignContent == StyleAlignFlags::LAST_BASELINE) {
6858 state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
6859 baselineTrack =
6860 (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
6861 }
6862 }
6863 }
6864
6865 if (state & ItemState::eIsBaselineAligned) {
6866 // XXXmats if |child| is a descendant of a subgrid then the metrics
6867 // below needs to account for the accumulated MPB somehow...
6868
6869 nscoord baseline;
6870 nsGridContainerFrame* grid = do_QueryFrame(child);
6871 if (state & ItemState::eFirstBaseline) {
6872 if (grid) {
6873 if (isOrthogonal == isInlineAxis) {
6874 baseline = grid->GetBBaseline(BaselineSharingGroup::First);
6875 } else {
6876 baseline = grid->GetIBaseline(BaselineSharingGroup::First);
6877 }
6878 }
6879 if (grid || nsLayoutUtils::GetFirstLineBaseline(wm, child, &baseline)) {
6880 NS_ASSERTION(baseline != NS_INTRINSIC_ISIZE_UNKNOWN,do { if (!(baseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "baseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6881)
; MOZ_PretendNoReturn(); } } while (0)
6881 "about to use an unknown baseline")do { if (!(baseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "baseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6881)
; MOZ_PretendNoReturn(); } } while (0)
;
6882 auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
6883 nscoord alignSize;
6884 LogicalPoint pos =
6885 child->GetLogicalNormalPosition(wm, aContainerSize);
6886 baseline += pos.Pos(mAxis, wm);
6887 if (aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6888 state |= ItemState::eEndSideBaseline;
6889 // Convert to distance from the track end.
6890 baseline =
6891 aTrackSizes[gridItem.mArea
6892 .LineRangeForAxis(GetOrthogonalAxis(mAxis))
6893 .mStart] -
6894 baseline;
6895 }
6896 alignSize = frameSize;
6897 aFirstBaselineItems.AppendElement(ItemBaselineData(
6898 {baselineTrack, baseline, alignSize, &gridItem}));
6899 } else {
6900 state &= ~ItemState::eAllBaselineBits;
6901 }
6902 } else {
6903 if (grid) {
6904 if (isOrthogonal == isInlineAxis) {
6905 baseline = grid->GetBBaseline(BaselineSharingGroup::Last);
6906 } else {
6907 baseline = grid->GetIBaseline(BaselineSharingGroup::Last);
6908 }
6909 }
6910 if (grid || nsLayoutUtils::GetLastLineBaseline(wm, child, &baseline)) {
6911 NS_ASSERTION(baseline != NS_INTRINSIC_ISIZE_UNKNOWN,do { if (!(baseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "baseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6912)
; MOZ_PretendNoReturn(); } } while (0)
6912 "about to use an unknown baseline")do { if (!(baseline != NS_INTRINSIC_ISIZE_UNKNOWN)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "about to use an unknown baseline", "baseline != NS_INTRINSIC_ISIZE_UNKNOWN"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 6912)
; MOZ_PretendNoReturn(); } } while (0)
;
6913 auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
6914 auto m = child->GetLogicalUsedMargin(wm);
6915 if (!grid &&
6916 aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6917 // Convert to distance from border-box end.
6918 state |= ItemState::eEndSideBaseline;
6919 LogicalPoint pos =
6920 child->GetLogicalNormalPosition(wm, aContainerSize);
6921 baseline += pos.Pos(mAxis, wm);
6922 baseline =
6923 aTrackSizes[gridItem.mArea
6924 .LineRangeForAxis(GetOrthogonalAxis(mAxis))
6925 .mStart] -
6926 baseline;
6927 } else if (grid && aSet.mTrackAlignmentSet ==
6928 BaselineAlignmentSet::StartStretch) {
6929 // Convert to distance from border-box start.
6930 baseline = frameSize - baseline;
6931 }
6932 if (aSet.mItemSet == BaselineAlignmentSet::LastItems &&
6933 aSet.mTrackAlignmentSet == BaselineAlignmentSet::StartStretch) {
6934 LogicalPoint pos =
6935 child->GetLogicalNormalPosition(wm, aContainerSize);
6936 baseline += pos.B(wm);
6937 }
6938 if (aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6939 state |= ItemState::eEndSideBaseline;
6940 }
6941 auto descent =
6942 baseline + ((state & ItemState::eEndSideBaseline)
6943 ? (isInlineAxis ? m.IEnd(wm) : m.BEnd(wm))
6944 : (isInlineAxis ? m.IStart(wm) : m.BStart(wm)));
6945 auto alignSize =
6946 frameSize + (isInlineAxis ? m.IStartEnd(wm) : m.BStartEnd(wm));
6947 aLastBaselineItems.AppendElement(
6948 ItemBaselineData({baselineTrack, descent, alignSize, &gridItem}));
6949 } else {
6950 state &= ~ItemState::eAllBaselineBits;
6951 }
6952 }
6953 }
6954 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6955 (state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) !=do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6956 (ItemState::eFirstBaseline | ItemState::eLastBaseline),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6957 "first/last baseline bits are mutually exclusive")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((state & (ItemState::eFirstBaseline | ItemState::
eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
" (" "first/last baseline bits are mutually exclusive" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6958 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6961
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6961); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6959 (state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) !=do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6961
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6961); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6960 (ItemState::eSelfBaseline | ItemState::eContentBaseline),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6961
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6961); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6961 "*-self and *-content baseline bits are mutually exclusive")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((state & (ItemState::eSelfBaseline | ItemState::
eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::
eContentBaseline))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline)) != (ItemState::eSelfBaseline
| ItemState::eContentBaseline)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
" (" "*-self and *-content baseline bits are mutually exclusive"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6961
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6961); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6962 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6963 !(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6964 !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6965 "first/last bit requires self/content bit and vice versa")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(state & (ItemState::eFirstBaseline | ItemState
::eLastBaseline)) == !(state & (ItemState::eSelfBaseline |
ItemState::eContentBaseline)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(state & (ItemState::eFirstBaseline
| ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline
| ItemState::eContentBaseline))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
" (" "first/last bit requires self/content bit and vice versa"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 6965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) == !(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline))"
") (" "first/last bit requires self/content bit and vice versa"
")"); do { MOZ_CrashSequence(__null, 6965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6966 gridItem.mState[mAxis] |= state;
6967 gridItem.mBaselineOffset[mAxis] = nscoord(0);
6968 }
6969
6970 CalculateItemBaselines(aFirstBaselineItems, BaselineSharingGroup::First);
6971 CalculateItemBaselines(aLastBaselineItems, BaselineSharingGroup::Last);
6972
6973 // TODO: make sure the mBaselines (i.e. the baselines we export from
6974 // the grid container) are offset from the correct container edge.
6975 // Also, which of the baselines do we pick to export exactly?
6976
6977 MOZ_ASSERT(aFirstBaselineItems.Length() != 1 ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFirstBaselineItems.Length() != 1 || aFirstBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFirstBaselineItems.Length()
!= 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset
[mAxis] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6980); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6978 aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFirstBaselineItems.Length() != 1 || aFirstBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFirstBaselineItems.Length()
!= 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset
[mAxis] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6980); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6979 "a baseline group that contains only one item should not "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFirstBaselineItems.Length() != 1 || aFirstBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFirstBaselineItems.Length()
!= 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset
[mAxis] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6980); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6980 "produce a non-zero item baseline offset")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFirstBaselineItems.Length() != 1 || aFirstBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFirstBaselineItems.Length()
!= 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset
[mAxis] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFirstBaselineItems.Length() != 1 || aFirstBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6980); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6981 MOZ_ASSERT(aLastBaselineItems.Length() != 1 ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLastBaselineItems.Length() != 1 || aLastBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLastBaselineItems.Length() !=
1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis
] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6982 aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLastBaselineItems.Length() != 1 || aLastBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLastBaselineItems.Length() !=
1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis
] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6983 "a baseline group that contains only one item should not "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLastBaselineItems.Length() != 1 || aLastBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLastBaselineItems.Length() !=
1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis
] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6984 "produce a non-zero item baseline offset")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aLastBaselineItems.Length() != 1 || aLastBaselineItems
[0].mGridItem->mBaselineOffset[mAxis] == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aLastBaselineItems.Length() !=
1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis
] == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
" (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 6984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLastBaselineItems.Length() != 1 || aLastBaselineItems[0].mGridItem->mBaselineOffset[mAxis] == 0"
") (" "a baseline group that contains only one item should not "
"produce a non-zero item baseline offset" ")"); do { MOZ_CrashSequence
(__null, 6984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6985}
6986
6987void nsGridContainerFrame::Tracks::AlignBaselineSubtree(
6988 const GridItemInfo& aGridItem) const {
6989 if (mIsMasonry) {
6990 return;
6991 }
6992 auto state = aGridItem.mState[mAxis];
6993 if (!(state & ItemState::eIsBaselineAligned)) {
6994 return;
6995 }
6996 const GridArea& area = aGridItem.mArea;
6997 int32_t baselineTrack;
6998 const bool isFirstBaseline = state & ItemState::eFirstBaseline;
6999 if (isFirstBaseline) {
7000 baselineTrack =
7001 mAxis == LogicalAxis::Block ? area.mRows.mStart : area.mCols.mStart;
7002 } else {
7003 baselineTrack =
7004 (mAxis == LogicalAxis::Block ? area.mRows.mEnd : area.mCols.mEnd) - 1;
7005 }
7006 const TrackSize& sz = mSizes[baselineTrack];
7007 auto baselineGroup = isFirstBaseline ? BaselineSharingGroup::First
7008 : BaselineSharingGroup::Last;
7009 nscoord delta = sz.mBase - sz.mBaselineSubtreeSize[baselineGroup];
7010 const auto subtreeAlign = mBaselineSubtreeAlign[baselineGroup];
7011 if (subtreeAlign == StyleAlignFlags::START) {
7012 if (state & ItemState::eLastBaseline) {
7013 aGridItem.mBaselineOffset[mAxis] += delta;
7014 }
7015 } else if (subtreeAlign == StyleAlignFlags::END) {
7016 if (isFirstBaseline) {
7017 aGridItem.mBaselineOffset[mAxis] += delta;
7018 }
7019 } else if (subtreeAlign == StyleAlignFlags::CENTER) {
7020 aGridItem.mBaselineOffset[mAxis] += delta / 2;
7021 } else {
7022 MOZ_ASSERT_UNREACHABLE("unexpected baseline subtree alignment")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"unexpected baseline subtree alignment" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected baseline subtree alignment"
")"); do { MOZ_CrashSequence(__null, 7022); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7023 }
7024}
7025
7026bool nsGridContainerFrame::Tracks::GrowSizeForSpanningItems(
7027 TrackSizingStep aStep, TrackSizingPhase aPhase,
7028 nsTArray<SpanningItemData>::iterator aIter,
7029 nsTArray<SpanningItemData>::iterator aIterEnd, nsTArray<uint32_t>& aTracks,
7030 TrackPlan& aTrackPlan, ItemPlan& aItemPlan, SizingConstraint aConstraint,
7031 bool aIsGridIntrinsicSizing, const TrackSizingFunctions& aFunctions,
7032 const FitContentClamper& aFitContentClamper,
7033 bool aNeedInfinitelyGrowableFlag) {
7034 const bool isMaxSizingPhase = aPhase == TrackSizingPhase::IntrinsicMaximums ||
7035 aPhase == TrackSizingPhase::MaxContentMaximums;
7036 bool needToUpdateSizes = false;
7037 aTrackPlan.Initialize(aPhase, *this);
7038 for (; aIter != aIterEnd; ++aIter) {
7039 const SpanningItemData& item = *aIter;
7040 if (!(item.mState & SelectorForPhase(aPhase, aConstraint))) {
7041 continue;
7042 }
7043 if (isMaxSizingPhase) {
7044 for (auto i : item.mLineRange.Range()) {
7045 aTrackPlan[i].mState |= TrackSize::eModified;
7046 }
7047 }
7048 if (aStep == TrackSizingStep::Flex && aIsGridIntrinsicSizing) {
7049 // We could only ever grow flex tracks, and when measuring we shouldn't
7050 // grow flex tracks, so the remaining space will always be zero.
7051 continue;
7052 }
7053 nscoord space = item.SizeContributionForPhase(aPhase);
7054 if (space <= 0) {
7055 continue;
7056 }
7057 aTracks.ClearAndRetainStorage();
7058 space = CollectGrowable(aStep, aPhase, space, item.mLineRange, aConstraint,
7059 aTracks);
7060 if (space > 0) {
7061 DistributeToTrackSizes(aStep, aPhase, space, aTrackPlan, aItemPlan,
7062 aTracks, aConstraint, aFunctions,
7063 aFitContentClamper);
7064 needToUpdateSizes = true;
7065 }
7066 }
7067 if (isMaxSizingPhase) {
7068 needToUpdateSizes = true;
7069 }
7070 if (needToUpdateSizes) {
7071 CopyPlanToSize(aPhase, aTrackPlan, aNeedInfinitelyGrowableFlag);
7072 }
7073 return needToUpdateSizes;
7074}
7075
7076void nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
7077 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
7078 const TrackSizingFunctions& aFunctions, LineRange GridArea::* aRange,
7079 nscoord aPercentageBasis, SizingConstraint aConstraint) {
7080 // Intrinsic sizing algorithm 12.5 steps 2-5
7081 // https://drafts.csswg.org/css-grid-2/#algo-content
7082 //
7083 // We're also setting eIsFlexing on the item state here to speed up
7084 // FindUsedFlexFraction later.
7085
7086 // nonFlexSpanningItems has spanning items that do not span any flex tracks.
7087 // flexSpanningItems has spanning items that span one or more flex tracks.
7088 nsTArray<SpanningItemData> nonFlexSpanningItems, flexSpanningItems;
7089 // max span of items in `nonFlexSpanningItems` and `flexSpanningItems`.
7090 uint32_t maxSpan = 0;
7091
7092 const auto orthogonalAxis = GetOrthogonalAxis(mAxis);
7093 const bool isMasonryInOtherAxis = aGridRI.mFrame->IsMasonry(orthogonalAxis);
7094
7095 for (auto& gridItem : aGridItems) {
7096 MOZ_ASSERT(!(gridItem.mState[mAxis] &do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
" (" "Why are any of these bits set already?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7099); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7097 (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing |do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
" (" "Why are any of these bits set already?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7099); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7098 ItemState::eClampMarginBoxMinSize)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
" (" "Why are any of these bits set already?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7099); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7099 "Why are any of these bits set already?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize
| ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize)
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
" (" "Why are any of these bits set already?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7099); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7100
7101 const GridArea& area = gridItem.mArea;
7102 const LineRange& lineRange = area.*aRange;
7103 const TrackSize::StateBits state = StateBitsForRange(lineRange);
7104 // Set flex sizing flag as soon as possible to ensure
7105 // MinContributionDependsOnAutoMinSize will function properly.
7106 if (state & TrackSize::eFlexMaxSizing) {
7107 gridItem.mState[mAxis] |= ItemState::eIsFlexing;
7108 }
7109
7110 // If we have masonry layout in the other axis then skip this item unless
7111 // it's in the first masonry track, or has definite placement in this axis,
7112 // or spans all tracks in this axis (since that implies it will be placed
7113 // at line 1 regardless of layout results of other items).
7114 if (isMasonryInOtherAxis &&
7115 gridItem.mArea.LineRangeForAxis(orthogonalAxis).mStart != 0 &&
7116 (gridItem.mState[mAxis] & ItemState::eAutoPlacement) &&
7117 gridItem.mArea.LineRangeForAxis(mAxis).Extent() != mSizes.Length()) {
7118 continue;
7119 }
7120
7121 uint32_t span = lineRange.Extent();
7122 if (MOZ_UNLIKELY(gridItem.mState[mAxis] & ItemState::eIsSubgrid)(__builtin_expect(!!(gridItem.mState[mAxis] & ItemState::
eIsSubgrid), 0))
) {
7123 auto itemWM = gridItem.mFrame->GetWritingMode();
7124 auto percentageBasis = aGridRI.PercentageBasisFor(mAxis, gridItem);
7125
7126 if (percentageBasis.ISize(itemWM) == NS_UNCONSTRAINEDSIZE) {
7127 percentageBasis.ISize(itemWM) = nscoord(0);
7128 }
7129
7130 if (percentageBasis.BSize(itemWM) == NS_UNCONSTRAINEDSIZE) {
7131 percentageBasis.BSize(itemWM) = nscoord(0);
7132 }
7133
7134 const WritingMode wm = aGridRI.mWM;
7135 auto* subgrid =
7136 SubgridComputeMarginBorderPadding(gridItem, percentageBasis);
7137 LogicalMargin mbp = SubgridAccumulatedMarginBorderPadding(
7138 gridItem.SubgridFrame(), subgrid, wm, mAxis);
7139
7140 if (span == 1) {
7141 AddSubgridContribution(mSizes[lineRange.mStart],
7142 mbp.StartEnd(mAxis, wm));
7143 } else {
7144 AddSubgridContribution(mSizes[lineRange.mStart], mbp.Start(mAxis, wm));
7145 AddSubgridContribution(mSizes[lineRange.mEnd - 1], mbp.End(mAxis, wm));
7146 }
7147 continue;
7148 }
7149
7150 // Set eContentBasedAutoMinSize if and only if the grid item has
7151 // content-based automatic minimum size. This is the case if all of the
7152 // following are true of the item:
7153 // 1. its computed overflow is not a scrollable overflow value
7154 // 2. it spans at least one track in that axis whose min track sizing
7155 // function is auto
7156 // 3. if it spans more than one track in that axis, none of those tracks
7157 // are flexible
7158 // https://drafts.csswg.org/css-grid-2/#min-size-auto
7159 if (!gridItem.mFrame->StyleDisplay()->IsScrollableOverflow() &&
7160 state & TrackSize::eAutoMinSizing &&
7161 (span == 1 || !(state & TrackSize::eFlexMaxSizing))) {
7162 gridItem.mState[mAxis] |= ItemState::eContentBasedAutoMinSize;
7163 }
7164
7165 if (span == 1) {
7166 // Step 2. Size tracks to fit non-spanning items.
7167 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
7168 ResolveIntrinsicSizeForNonSpanningItems(aGridRI, aFunctions,
7169 aPercentageBasis, aConstraint,
7170 lineRange, gridItem);
7171 } else {
7172 // Collect information for step 3.
7173 // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
7174
7175 nsTArray<SpanningItemData>* items;
7176 if (state & TrackSize::eFlexMaxSizing) {
7177 // Set eIsFlexing on the item state here to speed up
7178 // FindUsedFlexFraction later.
7179 gridItem.mState[mAxis] |= ItemState::eIsFlexing;
7180 items = &flexSpanningItems;
7181 } else {
7182 items = &nonFlexSpanningItems;
7183 }
7184
7185 if (state &
7186 (TrackSize::eIntrinsicMinSizing | TrackSize::eIntrinsicMaxSizing)) {
7187 maxSpan = std::max(maxSpan, span);
7188 CachedIntrinsicSizes cache{gridItem, aGridRI, mAxis};
7189
7190 // Calculate data for "Automatic Minimum Size" clamping, if needed.
7191 if (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize) {
7192 if (const Maybe<nscoord> minSizeClamp = ComputeMinSizeClamp(
7193 aFunctions, aPercentageBasis, lineRange, state)) {
7194 cache.mMinSizeClamp = *minSizeClamp;
7195 gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
7196 }
7197 }
7198
7199 // Collect the various grid item size contributions we need.
7200 EnumSet<GridIntrinsicSizeType> sizeTypesToCalculate;
7201 // For 3.1
7202 TrackSize::StateBits selector =
7203 SelectorForPhase(TrackSizingPhase::IntrinsicMinimums, aConstraint);
7204
7205 if (state & selector) {
7206 sizeTypesToCalculate += GridIntrinsicSizeType::MinContribution;
7207 }
7208
7209 // For 3.2 and 3.5
7210 selector =
7211 SelectorForPhase(TrackSizingPhase::IntrinsicMaximums, aConstraint) |
7212 SelectorForPhase(TrackSizingPhase::ContentBasedMinimums,
7213 aConstraint);
7214 if (state & selector) {
7215 sizeTypesToCalculate += GridIntrinsicSizeType::MinContentContribution;
7216 }
7217
7218 // For 3.3 and 3.6
7219 selector =
7220 SelectorForPhase(TrackSizingPhase::MaxContentMinimums,
7221 aConstraint) |
7222 SelectorForPhase(TrackSizingPhase::MaxContentMaximums, aConstraint);
7223 if (state & selector) {
7224 sizeTypesToCalculate += GridIntrinsicSizeType::MaxContentContribution;
7225 }
7226
7227 cache.EnsureContributions(sizeTypesToCalculate, gridItem, aGridRI,
7228 mAxis);
7229 items->AppendElement(SpanningItemData(
7230 {span, state, lineRange, cache.SizesOrDefault(), gridItem.mFrame}));
7231 }
7232 }
7233
7234 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
" (" "clamping only applies to Automatic Minimum Size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7237); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7235 !(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
" (" "clamping only applies to Automatic Minimum Size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7237); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7236 (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
" (" "clamping only applies to Automatic Minimum Size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7237); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7237 "clamping only applies to Automatic Minimum Size")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize
) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
" (" "clamping only applies to Automatic Minimum Size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7237); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7238 }
7239
7240 MOZ_ASSERT(maxSpan != 1, "Should only count spans greater than 1")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(maxSpan != 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(maxSpan != 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("maxSpan != 1" " ("
"Should only count spans greater than 1" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxSpan != 1"
") (" "Should only count spans greater than 1" ")"); do { MOZ_CrashSequence
(__null, 7240); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7241 // Step 3 - Increase sizes to accommodate spanning items crossing
7242 // content-sized tracks.
7243 if (maxSpan) {
7244 auto fitContentClamper = [&aFunctions, aPercentageBasis](uint32_t aTrack,
7245 nscoord aMinSize,
7246 nscoord* aSize) {
7247 nscoord fitContentLimit = ::ResolveToDefiniteSize(
7248 aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
7249 if (*aSize > fitContentLimit) {
7250 *aSize = std::max(aMinSize, fitContentLimit);
7251 return true;
7252 }
7253 return false;
7254 };
7255
7256 // Step 3 should "Repeat incrementally for items with greater spans until
7257 // all items have been considered."
7258 // Sort the collected items on span length, shortest first. There's no need
7259 // for a stable sort here since the sizing isn't order dependent within
7260 // a group of items with the same span length.
7261 // We don't need to sort flexSpanningItems, those items are all considered
7262 // "together, rather than grouped by span size" for step 4.
7263 std::sort(nonFlexSpanningItems.begin(), nonFlexSpanningItems.end(),
7264 SpanningItemData::IsSpanLessThan);
7265
7266 nsTArray<uint32_t> tracks(maxSpan);
7267 TrackPlan plan(mSizes.Length());
7268 plan.SetLength(mSizes.Length());
7269 ItemPlan itemPlan(mSizes.Length());
7270 itemPlan.SetLength(mSizes.Length());
7271
7272 // Start / end iterator for items of the same span length:
7273 auto spanGroupStart = nonFlexSpanningItems.begin();
7274 auto spanGroupEnd = spanGroupStart;
7275 const auto end = nonFlexSpanningItems.end();
7276
7277 // nonFlexSpanningItems is sorted by span size. Each iteration will process
7278 // one span size.
7279 for (; spanGroupStart != end; spanGroupStart = spanGroupEnd) {
7280 const uint32_t span = spanGroupStart->mSpan;
7281 TrackSize::StateBits stateBitsForSpan = TrackSize::StateBits::eNone;
7282 MOZ_ASSERT(spanGroupEnd == spanGroupStart)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(spanGroupEnd == spanGroupStart)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(spanGroupEnd == spanGroupStart
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"spanGroupEnd == spanGroupStart", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7282); AnnotateMozCrashReason("MOZ_ASSERT" "(" "spanGroupEnd == spanGroupStart"
")"); do { MOZ_CrashSequence(__null, 7282); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7283 // Find the end of this group if items with the same span size.
7284 // Accumulate state bits for the items with this span size to avoid
7285 // calculations below that are not applicable to any of those items.
7286 do {
7287 stateBitsForSpan |= StateBitsForRange(spanGroupEnd->mLineRange);
7288 } while (++spanGroupEnd != end && spanGroupEnd->mSpan == span);
7289 MOZ_ASSERT(!(stateBitsForSpan & TrackSize::eFlexMaxSizing),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(stateBitsForSpan & TrackSize::eFlexMaxSizing))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(stateBitsForSpan & TrackSize::eFlexMaxSizing))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
" (" "Non-flex spanning items should not include any flex tracks"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 7290
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
") (" "Non-flex spanning items should not include any flex tracks"
")"); do { MOZ_CrashSequence(__null, 7290); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7290 "Non-flex spanning items should not include any flex tracks")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(stateBitsForSpan & TrackSize::eFlexMaxSizing))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(stateBitsForSpan & TrackSize::eFlexMaxSizing))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
" (" "Non-flex spanning items should not include any flex tracks"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 7290
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
") (" "Non-flex spanning items should not include any flex tracks"
")"); do { MOZ_CrashSequence(__null, 7290); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7291 bool updatedBase = false; // Did we update any mBase in step 3.1..3.3?
7292 TrackSizingPhase phase = TrackSizingPhase::IntrinsicMinimums;
7293 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7294 // Step 3.1 MinSize to intrinsic min-sizing.
7295 updatedBase = GrowSizeForSpanningItems(
7296 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7297 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7298 aFunctions);
7299 }
7300
7301 phase = TrackSizingPhase::ContentBasedMinimums;
7302 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7303 // Step 3.2 MinContentContribution to min-/max-content (and 'auto' when
7304 // sizing under a min-content constraint) min-sizing.
7305 updatedBase |= GrowSizeForSpanningItems(
7306 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7307 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7308 aFunctions);
7309 }
7310
7311 phase = TrackSizingPhase::MaxContentMinimums;
7312 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7313 // Step 3.3 MaxContentContribution to max-content (and 'auto' when
7314 // sizing under a max-content constraint) min-sizing.
7315 updatedBase |= GrowSizeForSpanningItems(
7316 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7317 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7318 aFunctions);
7319 }
7320
7321 if (updatedBase) {
7322 // Step 3.4
7323 for (TrackSize& sz : mSizes) {
7324 if (sz.mBase > sz.mLimit) {
7325 sz.mLimit = sz.mBase;
7326 }
7327 }
7328 }
7329
7330 phase = TrackSizingPhase::IntrinsicMaximums;
7331 bool willRunStep3_6 = false;
7332 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7333 willRunStep3_6 =
7334 stateBitsForSpan & TrackSize::eAutoOrMaxContentMaxSizing;
7335 // Step 3.5 MinContentContribution to intrinsic max-sizing.
7336 GrowSizeForSpanningItems(
7337 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7338 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7339 aFunctions, fitContentClamper, willRunStep3_6);
7340 }
7341 if (willRunStep3_6) {
7342 // Step 2.6 MaxContentContribution to max-content max-sizing.
7343 phase = TrackSizingPhase::MaxContentMaximums;
7344 GrowSizeForSpanningItems(
7345 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7346 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7347 aFunctions, fitContentClamper);
7348 }
7349 }
7350
7351 // Step 4
7352 TrackSize::StateBits stateBitsForSpan = TrackSize::StateBits::eNone;
7353 for (const SpanningItemData& spanningData : flexSpanningItems) {
7354 const TrackSize::StateBits bits =
7355 StateBitsForRange(spanningData.mLineRange);
7356 MOZ_ASSERT(bits & TrackSize::eFlexMaxSizing,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bits & TrackSize::eFlexMaxSizing)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bits & TrackSize::eFlexMaxSizing
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"bits & TrackSize::eFlexMaxSizing" " (" "All flex spanning items should have at least one flex track"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 7357
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bits & TrackSize::eFlexMaxSizing"
") (" "All flex spanning items should have at least one flex track"
")"); do { MOZ_CrashSequence(__null, 7357); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7357 "All flex spanning items should have at least one flex track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bits & TrackSize::eFlexMaxSizing)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bits & TrackSize::eFlexMaxSizing
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"bits & TrackSize::eFlexMaxSizing" " (" "All flex spanning items should have at least one flex track"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 7357
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bits & TrackSize::eFlexMaxSizing"
") (" "All flex spanning items should have at least one flex track"
")"); do { MOZ_CrashSequence(__null, 7357); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7358 stateBitsForSpan |= bits;
7359 }
7360 bool updatedBase = false; // Did we update any mBase in step 4.1..4.3?
7361 TrackSizingPhase phase = TrackSizingPhase::IntrinsicMinimums;
7362 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7363 // Step 4.1 MinSize to intrinsic min-sizing.
7364 updatedBase = GrowSizeForSpanningItems(
7365 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7366 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7367 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7368 }
7369
7370 phase = TrackSizingPhase::ContentBasedMinimums;
7371 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7372 // Step 4.2 MinContentContribution to min-/max-content (and 'auto' when
7373 // sizing under a min-content constraint) min-sizing.
7374 updatedBase |= GrowSizeForSpanningItems(
7375 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7376 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7377 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7378 }
7379
7380 phase = TrackSizingPhase::MaxContentMinimums;
7381 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7382 // Step 4.3 MaxContentContribution to max-content (and 'auto' when
7383 // sizing under a max-content constraint) min-sizing.
7384 updatedBase |= GrowSizeForSpanningItems(
7385 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7386 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7387 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7388 }
7389
7390 if (updatedBase) {
7391 // Step 4.4
7392 for (TrackSize& sz : mSizes) {
7393 if (sz.mBase > sz.mLimit) {
7394 sz.mLimit = sz.mBase;
7395 }
7396 }
7397 }
7398 }
7399
7400 // Step 5 - If any track still has an infinite growth limit, set its growth
7401 // limit to its base size.
7402 for (TrackSize& sz : mSizes) {
7403 if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
7404 sz.mLimit = sz.mBase;
7405 }
7406 }
7407}
7408
7409float nsGridContainerFrame::Tracks::FindFrUnitSize(
7410 const LineRange& aRange, const nsTArray<uint32_t>& aFlexTracks,
7411 const TrackSizingFunctions& aFunctions, nscoord aSpaceToFill) const {
7412 MOZ_ASSERT(aSpaceToFill > 0 && !aFlexTracks.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSpaceToFill > 0 && !aFlexTracks.IsEmpty(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aSpaceToFill > 0 && !aFlexTracks.IsEmpty(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aSpaceToFill > 0 && !aFlexTracks.IsEmpty()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7412); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSpaceToFill > 0 && !aFlexTracks.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 7412); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7413 float flexFactorSum = 0.0f;
7414 nscoord leftOverSpace = aSpaceToFill;
7415 for (auto i : aRange.Range()) {
7416 const TrackSize& sz = mSizes[i];
7417 if (sz.mState & TrackSize::eFlexMaxSizing) {
7418 flexFactorSum += aFunctions.MaxSizingFor(i).AsFlex()._0;
7419 } else {
7420 leftOverSpace -= sz.mBase;
7421 if (leftOverSpace <= 0) {
7422 return 0.0f;
7423 }
7424 }
7425 }
7426 bool restart;
7427 float hypotheticalFrSize;
7428 nsTArray<uint32_t> flexTracks(aFlexTracks.Clone());
7429 uint32_t numFlexTracks = flexTracks.Length();
7430 do {
7431 restart = false;
7432
7433 // 12.7.1.2: If flexFactorSum is less than 1, set it to 1 instead.
7434 hypotheticalFrSize = leftOverSpace / std::max(flexFactorSum, 1.0f);
7435 for (uint32_t& track : flexTracks) {
7436 if (track == kAutoLine) {
7437 continue; // Track marked as inflexible in a prev. iter of this loop.
7438 }
7439 float flexFactor = aFunctions.MaxSizingFor(track).AsFlex()._0;
7440 const nscoord base = mSizes[track].mBase;
7441 if (flexFactor * hypotheticalFrSize < base) {
7442 // 12.7.1.4: Treat this track as inflexible.
7443 track = kAutoLine;
7444 flexFactorSum -= flexFactor;
7445 leftOverSpace -= base;
7446 --numFlexTracks;
7447 if (numFlexTracks == 0 || leftOverSpace <= 0) {
7448 return 0.0f;
7449 }
7450 restart = true;
7451 // break; XXX (bug 1176621 comment 16) measure which is more common
7452 }
7453 }
7454 } while (restart);
7455 return hypotheticalFrSize;
7456}
7457
7458float nsGridContainerFrame::Tracks::FindUsedFlexFraction(
7459 GridReflowInput& aGridRI, const nsTArray<GridItemInfo>& aGridItems,
7460 const nsTArray<uint32_t>& aFlexTracks,
7461 const TrackSizingFunctions& aFunctions, nscoord aAvailableSize) const {
7462 if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
7463 // Use all of the grid tracks and a 'space to fill' of the available space.
7464 const TranslatedLineRange range(0, mSizes.Length());
7465 return FindFrUnitSize(range, aFlexTracks, aFunctions, aAvailableSize);
7466 }
7467
7468 // The used flex fraction is the maximum of:
7469 // ... each flexible track's base size divided by its flex factor (which is
7470 // floored at 1).
7471 float fr = 0.0f;
7472 for (uint32_t track : aFlexTracks) {
7473 float flexFactor = aFunctions.MaxSizingFor(track).AsFlex()._0;
7474 float possiblyDividedBaseSize = (flexFactor > 1.0f)
7475 ? mSizes[track].mBase / flexFactor
7476 : mSizes[track].mBase;
7477 fr = std::max(fr, possiblyDividedBaseSize);
7478 }
7479 // ... the result of 'finding the size of an fr' for each item that spans
7480 // a flex track with its max-content contribution as 'space to fill'
7481 for (const GridItemInfo& item : aGridItems) {
7482 if (item.mState[mAxis] & ItemState::eIsFlexing) {
7483 // XXX optimize: bug 1194446
7484 const auto percentageBasis = aGridRI.PercentageBasisFor(mAxis, item);
7485 nscoord spaceToFill = ContentContribution(
7486 item, aGridRI, mAxis, percentageBasis, IntrinsicISizeType::PrefISize);
7487 const LineRange& range =
7488 mAxis == LogicalAxis::Inline ? item.mArea.mCols : item.mArea.mRows;
7489 MOZ_ASSERT(range.Extent() >= 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(range.Extent() >= 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(range.Extent() >= 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("range.Extent() >= 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 7489)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "range.Extent() >= 1"
")"); do { MOZ_CrashSequence(__null, 7489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7490 const auto spannedGaps = range.Extent() - 1;
7491 if (spannedGaps > 0) {
7492 spaceToFill -= mGridGap * spannedGaps;
7493 }
7494 if (spaceToFill <= 0) {
7495 continue;
7496 }
7497 // ... and all its spanned tracks as input.
7498 nsTArray<uint32_t> itemFlexTracks;
7499 for (auto i : range.Range()) {
7500 if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
7501 itemFlexTracks.AppendElement(i);
7502 }
7503 }
7504 float itemFr =
7505 FindFrUnitSize(range, itemFlexTracks, aFunctions, spaceToFill);
7506 fr = std::max(fr, itemFr);
7507 }
7508 }
7509 return fr;
7510}
7511
7512void nsGridContainerFrame::Tracks::StretchFlexibleTracks(
7513 GridReflowInput& aGridRI, const nsTArray<GridItemInfo>& aGridItems,
7514 const TrackSizingFunctions& aFunctions, nscoord aAvailableSize) {
7515 if (aAvailableSize <= 0) {
7516 return;
7517 }
7518 nsTArray<uint32_t> flexTracks(mSizes.Length());
7519 for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
7520 if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
7521 flexTracks.AppendElement(i);
7522 }
7523 }
7524 if (flexTracks.IsEmpty()) {
7525 return;
7526 }
7527 nscoord minSize = 0;
7528 nscoord maxSize = NS_UNCONSTRAINEDSIZE;
7529 if (aGridRI.mReflowInput) {
7530 auto* ri = aGridRI.mReflowInput;
7531 minSize = mAxis == LogicalAxis::Block ? ri->ComputedMinBSize()
7532 : ri->ComputedMinISize();
7533 maxSize = mAxis == LogicalAxis::Block ? ri->ComputedMaxBSize()
7534 : ri->ComputedMaxISize();
7535 }
7536 Maybe<TrackPlan> origSizes;
7537 bool applyMinMax = (minSize != 0 || maxSize != NS_UNCONSTRAINEDSIZE) &&
7538 aAvailableSize == NS_UNCONSTRAINEDSIZE;
7539 // We iterate twice at most. The 2nd time if the grid size changed after
7540 // applying a min/max-size (can only occur if aAvailableSize is indefinite).
7541 while (true) {
7542 float fr = FindUsedFlexFraction(aGridRI, aGridItems, flexTracks, aFunctions,
7543 aAvailableSize);
7544 if (fr != 0.0f) {
7545 for (uint32_t i : flexTracks) {
7546 float flexFactor = aFunctions.MaxSizingFor(i).AsFlex()._0;
7547 nscoord flexLength = NSToCoordRound(flexFactor * fr);
7548 nscoord& base = mSizes[i].mBase;
7549 if (flexLength > base) {
7550 if (applyMinMax && origSizes.isNothing()) {
7551 origSizes.emplace(mSizes);
7552 }
7553 base = flexLength;
7554 }
7555 }
7556 }
7557 if (applyMinMax) {
7558 applyMinMax = false;
7559 // https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
7560 // "If using this flex fraction would cause the grid to be smaller than
7561 // the grid container’s min-width/height (or larger than the grid
7562 // container’s max-width/height), then redo this step, treating the free
7563 // space as definite [...]"
7564 const auto sumOfGridGaps = SumOfGridGaps();
7565 nscoord newSize = SumOfGridTracks() + sumOfGridGaps;
7566 if (newSize > maxSize) {
7567 aAvailableSize = maxSize;
7568 } else if (newSize < minSize) {
7569 aAvailableSize = minSize;
7570 }
7571 if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
7572 aAvailableSize = std::max(0, aAvailableSize - sumOfGridGaps);
7573 // Restart with the original track sizes and definite aAvailableSize.
7574 if (origSizes.isSome()) {
7575 mSizes = std::move(*origSizes);
7576 origSizes.reset();
7577 } // else, no mSizes[].mBase were changed above so it's still correct
7578 if (aAvailableSize == 0) {
7579 break; // zero available size wouldn't change any sizes though...
7580 }
7581 continue;
7582 }
7583 }
7584 break;
7585 }
7586}
7587
7588void nsGridContainerFrame::Tracks::AlignJustifyContent(
7589 const nsStylePosition* aStyle, StyleContentDistribution aAligmentStyleValue,
7590 WritingMode aWM, nscoord aContentBoxSize, bool aIsSubgriddedAxis) {
7591 const bool isAlign = mAxis == LogicalAxis::Block;
7592 // Align-/justify-content doesn't apply in a subgridded axis.
7593 // Gap properties do apply though so we need to stretch/position the tracks
7594 // to center-align the gaps with the parent's gaps.
7595 if (MOZ_UNLIKELY(aIsSubgriddedAxis)(__builtin_expect(!!(aIsSubgriddedAxis), 0))) {
7596 auto& gap = isAlign ? aStyle->mRowGap : aStyle->mColumnGap;
7597 if (gap.IsNormal()) {
7598 return;
7599 }
7600 auto len = mSizes.Length();
7601 if (len <= 1) {
7602 return;
7603 }
7604 // This stores the gap deltas between the subgrid gap and the gaps in
7605 // the used track sizes (as encoded in its tracks' mPosition):
7606 nsTArray<nscoord> gapDeltas;
7607 const size_t numGaps = len - 1;
7608 gapDeltas.SetLength(numGaps);
7609 for (size_t i = 0; i < numGaps; ++i) {
7610 TrackSize& sz1 = mSizes[i];
7611 TrackSize& sz2 = mSizes[i + 1];
7612 nscoord currentGap = sz2.mPosition - (sz1.mPosition + sz1.mBase);
7613 gapDeltas[i] = mGridGap - currentGap;
7614 }
7615 // Recompute the tracks' size/position so that they end up with
7616 // a subgrid-gap centered on the original track gap.
7617 nscoord currentPos = mSizes[0].mPosition;
7618 nscoord lastHalfDelta(0);
7619 for (size_t i = 0; i < numGaps; ++i) {
7620 TrackSize& sz = mSizes[i];
7621 nscoord delta = gapDeltas[i];
7622 nscoord halfDelta;
7623 nscoord roundingError = NSCoordDivRem(delta, 2, &halfDelta);
7624 auto newSize = sz.mBase - (halfDelta + roundingError) - lastHalfDelta;
7625 lastHalfDelta = halfDelta;
7626 // If the gap delta (in particular 'halfDelta + lastHalfDelta') is larger
7627 // than the current track size, newSize can be negative. Don't let the new
7628 // track size (mBase) be negative.
7629 sz.mBase = std::max(newSize, 0);
7630 sz.mPosition = currentPos;
7631 currentPos += newSize + mGridGap;
7632 }
7633 auto& lastTrack = mSizes.LastElement();
7634 auto newSize = lastTrack.mBase - lastHalfDelta;
7635 lastTrack.mBase = std::max(newSize, 0);
7636 lastTrack.mPosition = currentPos;
7637 return;
7638 }
7639
7640 if (mSizes.IsEmpty()) {
7641 return;
7642 }
7643
7644 bool overflowSafe;
7645 auto alignment = ::GetAlignJustifyValue(aAligmentStyleValue.primary, aWM,
7646 isAlign, &overflowSafe);
7647 if (alignment == StyleAlignFlags::NORMAL) {
7648 alignment = StyleAlignFlags::STRETCH;
7649 // we may need a fallback for 'stretch' below
7650 aAligmentStyleValue = {alignment};
7651 }
7652
7653 // Compute the free space and count auto-sized tracks.
7654 size_t numAutoTracks = 0;
7655 nscoord space;
7656 if (alignment != StyleAlignFlags::START) {
7657 nscoord trackSizeSum = 0;
7658 if (aIsSubgriddedAxis) {
7659 numAutoTracks = mSizes.Length();
7660 } else {
7661 for (const TrackSize& sz : mSizes) {
7662 trackSizeSum += sz.mBase;
7663 if (sz.mState & TrackSize::eAutoMaxSizing) {
7664 ++numAutoTracks;
7665 }
7666 }
7667 }
7668 space = aContentBoxSize - trackSizeSum - SumOfGridGaps();
7669 // Use the fallback value instead when applicable.
7670 if (space < 0 ||
7671 (alignment == StyleAlignFlags::SPACE_BETWEEN && mSizes.Length() == 1)) {
7672 auto fallback = GetAlignJustifyDistributionFallback(aAligmentStyleValue,
7673 &overflowSafe);
7674 if (fallback) {
7675 alignment = *fallback;
7676 }
7677 }
7678 if (space == 0 || (space < 0 && overflowSafe)) {
7679 // XXX check that this makes sense also for [last ]baseline (bug 1151204).
7680 alignment = StyleAlignFlags::START;
7681 }
7682 }
7683
7684 // Optimize the cases where we just need to set each track's position.
7685 nscoord pos = 0;
7686 bool distribute = true;
7687 if (alignment == StyleAlignFlags::BASELINE ||
7688 alignment == StyleAlignFlags::LAST_BASELINE) {
7689 NS_WARNING("NYI: 'first/last baseline' (bug 1151204)")NS_DebugBreak(NS_DEBUG_WARNING, "NYI: 'first/last baseline' (bug 1151204)"
, nullptr, "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7689)
; // XXX
7690 alignment = StyleAlignFlags::START;
7691 }
7692 if (alignment == StyleAlignFlags::START) {
7693 distribute = false;
7694 } else if (alignment == StyleAlignFlags::END) {
7695 pos = space;
7696 distribute = false;
7697 } else if (alignment == StyleAlignFlags::CENTER) {
7698 pos = space / 2;
7699 distribute = false;
7700 } else if (alignment == StyleAlignFlags::STRETCH) {
7701 distribute = numAutoTracks != 0;
7702 }
7703 if (!distribute) {
7704 for (TrackSize& sz : mSizes) {
7705 sz.mPosition = pos;
7706 pos += sz.mBase + mGridGap;
7707 }
7708 return;
7709 }
7710
7711 // Distribute free space to/between tracks and set their position.
7712 MOZ_ASSERT(space > 0, "should've handled that on the fallback path above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(space > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(space > 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("space > 0" " ("
"should've handled that on the fallback path above" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7712); AnnotateMozCrashReason("MOZ_ASSERT" "(" "space > 0"
") (" "should've handled that on the fallback path above" ")"
); do { MOZ_CrashSequence(__null, 7712); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7713 nscoord between, roundingError;
7714 if (alignment == StyleAlignFlags::STRETCH) {
7715 MOZ_ASSERT(numAutoTracks > 0, "we handled numAutoTracks == 0 above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numAutoTracks > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(numAutoTracks > 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("numAutoTracks > 0"
" (" "we handled numAutoTracks == 0 above" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7715); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numAutoTracks > 0"
") (" "we handled numAutoTracks == 0 above" ")"); do { MOZ_CrashSequence
(__null, 7715); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7716 // The outer loop typically only runs once - it repeats only in a masonry
7717 // axis when some stretchable items reach their `max-size`.
7718 // It's O(n^2) worst case; if all items are stretchable with a `max-size`
7719 // and exactly one item reaches its `max-size` each round.
7720 while (space) {
7721 pos = 0;
7722 nscoord spacePerTrack;
7723 roundingError = NSCoordDivRem(space, numAutoTracks, &spacePerTrack);
7724 space = 0;
7725 for (TrackSize& sz : mSizes) {
7726 sz.mPosition = pos;
7727 if (!(sz.mState & TrackSize::eAutoMaxSizing)) {
7728 pos += sz.mBase + mGridGap;
7729 continue;
7730 }
7731 nscoord stretch = spacePerTrack;
7732 if (roundingError) {
7733 roundingError -= 1;
7734 stretch += 1;
7735 }
7736 nscoord newBase = sz.mBase + stretch;
7737 if (mIsMasonry && (sz.mState & TrackSize::eClampToLimit)) {
7738 auto clampedSize = std::min(newBase, sz.mLimit);
7739 auto sizeOverLimit = newBase - clampedSize;
7740 if (sizeOverLimit > 0) {
7741 newBase = clampedSize;
7742 sz.mState &= ~(sz.mState & TrackSize::eAutoMaxSizing);
7743 // This repeats the outer loop to distribute the superfluous space:
7744 space += sizeOverLimit;
7745 if (--numAutoTracks == 0) {
7746 // ... except if we don't have any stretchable items left.
7747 space = 0;
7748 }
7749 }
7750 }
7751 sz.mBase = newBase;
7752 pos += newBase + mGridGap;
7753 }
7754 }
7755 MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!roundingError)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!roundingError))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!roundingError"
" (" "we didn't distribute all rounding error?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!roundingError"
") (" "we didn't distribute all rounding error?" ")"); do { MOZ_CrashSequence
(__null, 7755); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7756 return;
7757 }
7758 if (alignment == StyleAlignFlags::SPACE_BETWEEN) {
7759 MOZ_ASSERT(mSizes.Length() > 1, "should've used a fallback above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSizes.Length() > 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSizes.Length() > 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mSizes.Length() > 1"
" (" "should've used a fallback above" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSizes.Length() > 1"
") (" "should've used a fallback above" ")"); do { MOZ_CrashSequence
(__null, 7759); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7760 roundingError = NSCoordDivRem(space, mSizes.Length() - 1, &between);
7761 } else if (alignment == StyleAlignFlags::SPACE_AROUND) {
7762 roundingError = NSCoordDivRem(space, mSizes.Length(), &between);
7763 pos = between / 2;
7764 } else if (alignment == StyleAlignFlags::SPACE_EVENLY) {
7765 roundingError = NSCoordDivRem(space, mSizes.Length() + 1, &between);
7766 pos = between;
7767 } else {
7768 MOZ_ASSERT_UNREACHABLE("unknown align-/justify-content value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"unknown align-/justify-content value" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7768); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown align-/justify-content value"
")"); do { MOZ_CrashSequence(__null, 7768); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7769 between = 0; // just to avoid a compiler warning
7770 roundingError = 0; // just to avoid a compiler warning
7771 }
7772 between += mGridGap;
7773 for (TrackSize& sz : mSizes) {
7774 sz.mPosition = pos;
7775 nscoord spacing = between;
7776 if (roundingError) {
7777 roundingError -= 1;
7778 spacing += 1;
7779 }
7780 pos += sz.mBase + spacing;
7781 }
7782 MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!roundingError)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!roundingError))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!roundingError"
" (" "we didn't distribute all rounding error?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!roundingError"
") (" "we didn't distribute all rounding error?" ")"); do { MOZ_CrashSequence
(__null, 7782); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7783}
7784
7785nscoord nsGridContainerFrame::Tracks::TotalTrackSizeWithoutAlignment(
7786 const nsGridContainerFrame* aGridContainerFrame) const {
7787 if (aGridContainerFrame->IsSubgrid(mAxis)) {
7788 // TODO: Investigate whether GridLineEdge here may include extra packing
7789 // space introduced by align-content or justify-content, and if that could
7790 // lead to inconsistent metrics vs. the non-subgrid path.
7791 return GridLineEdge(mSizes.Length(), GridLineSide::BeforeGridGap);
7792 }
7793
7794 // This method allows for the possibility that AlignJustifyContent() might not
7795 // be called yet. Therefore, we can't use GridLineEdge() here, as mPosition
7796 // may not be calculated.
7797 return SumOfGridTracksAndGaps();
7798}
7799
7800void nsGridContainerFrame::LineRange::ToPositionAndLength(
7801 const TrackPlan& aTrackSizes, nscoord* aPos, nscoord* aLength) const {
7802 MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart != kAutoLine && mEnd != kAutoLine)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mStart != kAutoLine && mEnd != kAutoLine))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mStart != kAutoLine && mEnd != kAutoLine"
" (" "expected a definite LineRange" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7803); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7803); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7803 "expected a definite LineRange")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart != kAutoLine && mEnd != kAutoLine)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mStart != kAutoLine && mEnd != kAutoLine))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mStart != kAutoLine && mEnd != kAutoLine"
" (" "expected a definite LineRange" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7803); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7803); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7804 MOZ_ASSERT(mStart < mEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart < mEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStart < mEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mStart < mEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 7804)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart < mEnd" ")"
); do { MOZ_CrashSequence(__null, 7804); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7805 nscoord startPos = aTrackSizes[mStart].mPosition;
7806 const TrackSize& sz = aTrackSizes[mEnd - 1];
7807 *aPos = startPos;
7808 *aLength = (sz.mPosition + sz.mBase) - startPos;
7809}
7810
7811nscoord nsGridContainerFrame::LineRange::ToLength(
7812 const TrackPlan& aTrackSizes) const {
7813 MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart != kAutoLine && mEnd != kAutoLine)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mStart != kAutoLine && mEnd != kAutoLine))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mStart != kAutoLine && mEnd != kAutoLine"
" (" "expected a definite LineRange" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7814); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7814 "expected a definite LineRange")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart != kAutoLine && mEnd != kAutoLine)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mStart != kAutoLine && mEnd != kAutoLine))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mStart != kAutoLine && mEnd != kAutoLine"
" (" "expected a definite LineRange" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7814); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7815 MOZ_ASSERT(mStart < mEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStart < mEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStart < mEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mStart < mEnd"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 7815)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart < mEnd" ")"
); do { MOZ_CrashSequence(__null, 7815); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7816 nscoord startPos = aTrackSizes[mStart].mPosition;
7817 const TrackSize& sz = aTrackSizes[mEnd - 1];
7818 return (sz.mPosition + sz.mBase) - startPos;
7819}
7820
7821void nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos(
7822 const Tracks& aTracks, nscoord aGridOrigin, nscoord* aPos,
7823 nscoord* aLength) const {
7824 // kAutoLine for abspos children contributes the corresponding edge
7825 // of the grid container's padding-box.
7826 if (mEnd == kAutoLine) {
7827 if (mStart == kAutoLine) {
7828 // done
7829 } else {
7830 const nscoord endPos = *aPos + *aLength;
7831 auto side = mStart == aTracks.mSizes.Length()
7832 ? GridLineSide::BeforeGridGap
7833 : GridLineSide::AfterGridGap;
7834 nscoord startPos = aTracks.GridLineEdge(mStart, side);
7835 *aPos = aGridOrigin + startPos;
7836 *aLength = std::max(endPos - *aPos, 0);
7837 }
7838 } else {
7839 if (mStart == kAutoLine) {
7840 auto side =
7841 mEnd == 0 ? GridLineSide::AfterGridGap : GridLineSide::BeforeGridGap;
7842 nscoord endPos = aTracks.GridLineEdge(mEnd, side);
7843 *aLength = std::max(aGridOrigin + endPos, 0);
7844 } else if (MOZ_LIKELY(mStart != mEnd)(__builtin_expect(!!(mStart != mEnd), 1))) {
7845 nscoord pos;
7846 ToPositionAndLength(aTracks.mSizes, &pos, aLength);
7847 *aPos = aGridOrigin + pos;
7848 } else {
7849 // The grid area only covers removed 'auto-fit' tracks.
7850 nscoord pos = aTracks.GridLineEdge(mStart, GridLineSide::BeforeGridGap);
7851 *aPos = aGridOrigin + pos;
7852 *aLength = nscoord(0);
7853 }
7854 }
7855}
7856
7857LogicalSize nsGridContainerFrame::GridReflowInput::PercentageBasisFor(
7858 LogicalAxis aAxis, const GridItemInfo& aGridItem) const {
7859 auto wm = aGridItem.mFrame->GetWritingMode();
7860 const auto* itemParent = aGridItem.mFrame->GetParent();
7861 if (MOZ_UNLIKELY(itemParent != mFrame)(__builtin_expect(!!(itemParent != mFrame), 0))) {
7862 // The item comes from a descendant subgrid. Use the subgrid's
7863 // used track sizes to resolve the grid area size, if present.
7864 MOZ_ASSERT(itemParent->IsGridContainerFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(itemParent->IsGridContainerFrame())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(itemParent->IsGridContainerFrame()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("itemParent->IsGridContainerFrame()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 7864)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "itemParent->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 7864); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7865 auto* subgridFrame = static_cast<const nsGridContainerFrame*>(itemParent);
7866 MOZ_ASSERT(subgridFrame->IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(subgridFrame->IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(subgridFrame->IsSubgrid()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"subgridFrame->IsSubgrid()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7866); AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgridFrame->IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 7866); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7867 if (auto* uts = subgridFrame->GetUsedTrackSizes()) {
7868 auto subgridWM = subgridFrame->GetWritingMode();
7869 LogicalSize cbSize(subgridWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
7870 if (!subgridFrame->IsColSubgrid() &&
7871 uts->mCanResolveLineRangeSize[LogicalAxis::Inline]) {
7872 // NOTE: At this point aGridItem.mArea is in this->mFrame coordinates
7873 // and thus may have been transposed. The range values in a non-
7874 // subgridded axis still has its original values in subgridFrame's
7875 // coordinates though.
7876 const auto subgridIAxisInGridWM =
7877 subgridWM.ConvertAxisTo(LogicalAxis::Inline, mWM);
7878 const auto& range =
7879 aGridItem.mArea.LineRangeForAxis(subgridIAxisInGridWM);
7880 cbSize.ISize(subgridWM) =
7881 range.ToLength(uts->mTrackPlans[LogicalAxis::Inline]);
7882 }
7883 if (!subgridFrame->IsRowSubgrid() &&
7884 uts->mCanResolveLineRangeSize[LogicalAxis::Block]) {
7885 const auto subgridBAxisInGridWM =
7886 subgridWM.ConvertAxisTo(LogicalAxis::Block, mWM);
7887 const auto& range =
7888 aGridItem.mArea.LineRangeForAxis(subgridBAxisInGridWM);
7889 cbSize.BSize(subgridWM) =
7890 range.ToLength(uts->mTrackPlans[LogicalAxis::Block]);
7891 }
7892 return cbSize.ConvertTo(wm, subgridWM);
7893 }
7894
7895 return LogicalSize(wm, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
7896 }
7897
7898 // Get row size and column size for the grid area occupied by aGridItem.
7899 const nscoord colSize = mCols.mCanResolveLineRangeSize
7900 ? mCols.ResolveSize(aGridItem.mArea.mCols)
7901 : NS_UNCONSTRAINEDSIZE;
7902 const nscoord rowSize = mRows.mCanResolveLineRangeSize
7903 ? mRows.ResolveSize(aGridItem.mArea.mRows)
7904 : NS_UNCONSTRAINEDSIZE;
7905 return !wm.IsOrthogonalTo(mWM) ? LogicalSize(wm, colSize, rowSize)
7906 : LogicalSize(wm, rowSize, colSize);
7907}
7908
7909LogicalRect nsGridContainerFrame::GridReflowInput::ContainingBlockFor(
7910 const GridArea& aArea) const {
7911 nscoord i, b, iSize, bSize;
7912 MOZ_ASSERT(aArea.mCols.Extent() > 0, "grid items cover at least one track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea.mCols.Extent() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea.mCols.Extent() > 0)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aArea.mCols.Extent() > 0"
" (" "grid items cover at least one track" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea.mCols.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 7912); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7913 MOZ_ASSERT(aArea.mRows.Extent() > 0, "grid items cover at least one track")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aArea.mRows.Extent() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aArea.mRows.Extent() > 0)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aArea.mRows.Extent() > 0"
" (" "grid items cover at least one track" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea.mRows.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 7913); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7914 aArea.mCols.ToPositionAndLength(mCols.mSizes, &i, &iSize);
7915 aArea.mRows.ToPositionAndLength(mRows.mSizes, &b, &bSize);
7916 return LogicalRect(mWM, i, b, iSize, bSize);
7917}
7918
7919LogicalRect nsGridContainerFrame::GridReflowInput::ContainingBlockForAbsPos(
7920 const GridArea& aArea, const LogicalPoint& aGridOrigin,
7921 const LogicalRect& aGridCB) const {
7922 nscoord i = aGridCB.IStart(mWM);
7923 nscoord b = aGridCB.BStart(mWM);
7924 nscoord iSize = aGridCB.ISize(mWM);
7925 nscoord bSize = aGridCB.BSize(mWM);
7926 aArea.mCols.ToPositionAndLengthForAbsPos(mCols, aGridOrigin.I(mWM), &i,
7927 &iSize);
7928 aArea.mRows.ToPositionAndLengthForAbsPos(mRows, aGridOrigin.B(mWM), &b,
7929 &bSize);
7930 return LogicalRect(mWM, i, b, iSize, bSize);
7931}
7932
7933void nsGridContainerFrame::GridReflowInput::AlignJustifyContentInMasonryAxis(
7934 nscoord aMasonryBoxSize, nscoord aContentBoxSize) {
7935 if (aContentBoxSize == NS_UNCONSTRAINEDSIZE) {
7936 aContentBoxSize = aMasonryBoxSize;
7937 }
7938 auto& masonryAxisTracks = mRows.mIsMasonry ? mRows : mCols;
7939 MOZ_ASSERT(masonryAxisTracks.mSizes.Length() == 2,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonryAxisTracks.mSizes.Length() == 2)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(masonryAxisTracks.mSizes.Length() == 2))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("masonryAxisTracks.mSizes.Length() == 2"
" (" "unexpected masonry axis tracks" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7940); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7940 "unexpected masonry axis tracks")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonryAxisTracks.mSizes.Length() == 2)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(masonryAxisTracks.mSizes.Length() == 2))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("masonryAxisTracks.mSizes.Length() == 2"
" (" "unexpected masonry axis tracks" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7940); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7941 const auto masonryAxis = masonryAxisTracks.mAxis;
7942 const auto contentAlignment = mGridStyle->UsedContentAlignment(masonryAxis);
7943 if (contentAlignment.primary == StyleAlignFlags::NORMAL ||
7944 contentAlignment.primary == StyleAlignFlags::STRETCH) {
7945 // Stretch the "masonry box" to the full content box if it's smaller.
7946 nscoord cbSize = std::max(aMasonryBoxSize, aContentBoxSize);
7947 for (auto& sz : masonryAxisTracks.mSizes) {
7948 sz.mBase = cbSize;
7949 }
7950 return;
7951 }
7952
7953 // Save our current track sizes; replace them with one track sized to
7954 // the masonry box and align that within our content box.
7955 auto savedTrackSizes(std::move(masonryAxisTracks.mSizes));
7956 masonryAxisTracks.mSizes.AppendElement(savedTrackSizes[0]);
7957 masonryAxisTracks.mSizes[0].mBase = aMasonryBoxSize;
7958 masonryAxisTracks.AlignJustifyContent(mGridStyle, contentAlignment, mWM,
7959 aContentBoxSize, false);
7960 nscoord masonryBoxOffset = masonryAxisTracks.mSizes[0].mPosition;
7961 // Restore the original track sizes...
7962 masonryAxisTracks.mSizes = std::move(savedTrackSizes);
7963 // ...then reposition and resize all of them to the aligned result.
7964 for (auto& sz : masonryAxisTracks.mSizes) {
7965 sz.mPosition = masonryBoxOffset;
7966 sz.mBase = aMasonryBoxSize;
7967 }
7968}
7969
7970// XXX This function was gutted when the 'align-tracks' and 'justify-tracks'
7971// properties were removed in
7972// https://bugzilla.mozilla.org/show_bug.cgi?id=1900195
7973// Possibly the current design of the Masonry code doesn't make much sense now
7974// without those properties, or at the very least this function should be
7975// renamed?
7976//
7977// Note: this is called after all items have been positioned/reflowed.
7978// The masonry-axis tracks have the size of the "masonry box" at this point
7979// and are positioned according to 'align/justify-content'.
7980void nsGridContainerFrame::GridReflowInput::AlignJustifyTracksInMasonryAxis(
7981 const LogicalSize& aContentSize, const nsSize& aContainerSize) {
7982 auto& masonryAxisTracks = mRows.mIsMasonry ? mRows : mCols;
7983 MOZ_ASSERT(masonryAxisTracks.mSizes.Length() == 2,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonryAxisTracks.mSizes.Length() == 2)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(masonryAxisTracks.mSizes.Length() == 2))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("masonryAxisTracks.mSizes.Length() == 2"
" (" "unexpected masonry axis tracks" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7984 "unexpected masonry axis tracks")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonryAxisTracks.mSizes.Length() == 2)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(masonryAxisTracks.mSizes.Length() == 2))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("masonryAxisTracks.mSizes.Length() == 2"
" (" "unexpected masonry axis tracks" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7985 // The offset to the "masonry box" from our content-box start edge.
7986 const nscoord masonryBoxOffset = masonryAxisTracks.mSizes[0].mPosition;
7987 if (masonryBoxOffset == 0) {
7988 return;
7989 }
7990
7991 const auto masonryAxis = masonryAxisTracks.mAxis;
7992 auto gridAxis = GetOrthogonalAxis(masonryAxis);
7993 auto& gridAxisTracks = TracksFor(gridAxis);
7994 auto wm = mWM;
7995
7996 for (auto i : IntegerRange(gridAxisTracks.mSizes.Length())) {
7997 // TODO move placeholders too
7998 auto delta = masonryBoxOffset;
7999 LogicalPoint logicalDelta(wm);
8000 logicalDelta.Pos(masonryAxis, wm) = delta;
8001 for (const auto& item : mGridItems) {
8002 if (item.mArea.LineRangeForAxis(gridAxis).mStart != i) {
8003 continue;
8004 }
8005 item.mFrame->MovePositionBy(wm, logicalDelta);
8006 }
8007 }
8008}
8009
8010/**
8011 * Return a Fragmentainer object if we have a fragmentainer frame in our
8012 * ancestor chain of containing block (CB) reflow inputs. We'll only
8013 * continue traversing the ancestor chain as long as the CBs have
8014 * the same writing-mode and have overflow:visible.
8015 */
8016Maybe<nsGridContainerFrame::Fragmentainer>
8017nsGridContainerFrame::GetNearestFragmentainer(
8018 const GridReflowInput& aGridRI) const {
8019 Maybe<nsGridContainerFrame::Fragmentainer> data;
8020 const ReflowInput* gridRI = aGridRI.mReflowInput;
8021 if (!gridRI->IsInFragmentedContext()) {
8022 return data;
8023 }
8024 WritingMode wm = aGridRI.mWM;
8025 const ReflowInput* cbRI = gridRI->mCBReflowInput;
8026 for (; cbRI; cbRI = cbRI->mCBReflowInput) {
8027 ScrollContainerFrame* sf = do_QueryFrame(cbRI->mFrame);
8028 if (sf) {
8029 break;
8030 }
8031 if (wm.IsOrthogonalTo(cbRI->GetWritingMode())) {
8032 break;
8033 }
8034 LayoutFrameType frameType = cbRI->mFrame->Type();
8035 if ((frameType == LayoutFrameType::Canvas &&
8036 PresContext()->IsPaginated()) ||
8037 frameType == LayoutFrameType::ColumnSet) {
8038 data.emplace();
8039 data->mIsTopOfPage = gridRI->mFlags.mIsTopOfPage;
8040 if (gridRI->AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
8041 data->mToFragmentainerEnd = aGridRI.mFragBStart +
8042 gridRI->AvailableBSize() -
8043 aGridRI.mBorderPadding.BStart(wm);
8044 } else {
8045 // This occurs when nsColumnSetFrame reflows its last column in
8046 // unconstrained available block-size.
8047 data->mToFragmentainerEnd = NS_UNCONSTRAINEDSIZE;
8048 }
8049 const auto numRows = aGridRI.mRows.mSizes.Length();
8050 data->mCanBreakAtStart =
8051 numRows > 0 && aGridRI.mRows.mSizes[0].mPosition > 0;
8052 nscoord bSize = gridRI->ComputedBSize();
8053 data->mIsAutoBSize = bSize == NS_UNCONSTRAINEDSIZE;
8054 if (data->mIsAutoBSize) {
8055 bSize = gridRI->ComputedMinBSize();
8056 } else {
8057 bSize = gridRI->ApplyMinMaxBSize(bSize);
8058 }
8059 nscoord gridEnd =
8060 aGridRI.mRows.GridLineEdge(numRows, GridLineSide::BeforeGridGap);
8061 data->mCanBreakAtEnd = bSize > gridEnd && bSize > aGridRI.mFragBStart;
8062 break;
8063 }
8064 }
8065 return data;
8066}
8067
8068void nsGridContainerFrame::ReflowInFlowChild(
8069 nsIFrame* aChild, const GridItemInfo* aGridItemInfo, nsSize aContainerSize,
8070 const Maybe<nscoord>& aStretchBSize, const Fragmentainer* aFragmentainer,
8071 const GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8072 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus) {
8073 nsPresContext* pc = PresContext();
8074 ComputedStyle* containerSC = Style();
8075 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
8076 const bool isGridItem = !!aGridItemInfo;
8077 MOZ_ASSERT(isGridItem == !aChild->IsPlaceholderFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isGridItem == !aChild->IsPlaceholderFrame())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(isGridItem == !aChild->IsPlaceholderFrame()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("isGridItem == !aChild->IsPlaceholderFrame()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8077)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "isGridItem == !aChild->IsPlaceholderFrame()"
")"); do { MOZ_CrashSequence(__null, 8077); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8078 LogicalRect cb(wm);
8079 WritingMode childWM = aChild->GetWritingMode();
8080 bool isConstrainedBSize = false;
8081 nscoord toFragmentainerEnd;
8082 // The part of the child's grid area that's in previous container fragments.
8083 nscoord consumedGridAreaBSize = 0;
8084 if (MOZ_LIKELY(isGridItem)(__builtin_expect(!!(isGridItem), 1))) {
8085 MOZ_ASSERT(aGridItemInfo->mFrame == aChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridItemInfo->mFrame == aChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridItemInfo->mFrame == aChild
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aGridItemInfo->mFrame == aChild", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItemInfo->mFrame == aChild"
")"); do { MOZ_CrashSequence(__null, 8085); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8086 const GridArea& area = aGridItemInfo->mArea;
8087 MOZ_ASSERT(area.IsDefinite())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(area.IsDefinite())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(area.IsDefinite()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("area.IsDefinite()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8087)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "area.IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 8087); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8088 cb = aGridRI.ContainingBlockFor(area);
8089 if (aFragmentainer && !wm.IsOrthogonalTo(childWM)) {
8090 // |gridAreaBOffset| is the offset of the child's grid area in this
8091 // container fragment (if negative, that distance is the child CB size
8092 // consumed in previous container fragments). Note that cb.BStart
8093 // (initially) and aState.mFragBStart are in "global" grid coordinates
8094 // (like all track positions).
8095 nscoord gridAreaBOffset = cb.BStart(wm) - aGridRI.mFragBStart;
8096 consumedGridAreaBSize = std::max(0, -gridAreaBOffset);
8097 cb.BStart(wm) = std::max(0, gridAreaBOffset);
8098 if (aFragmentainer->mToFragmentainerEnd != NS_UNCONSTRAINEDSIZE) {
8099 toFragmentainerEnd = aFragmentainer->mToFragmentainerEnd -
8100 aGridRI.mFragBStart - cb.BStart(wm);
8101 toFragmentainerEnd = std::max(toFragmentainerEnd, 0);
8102 isConstrainedBSize = true;
8103 }
8104 }
8105 cb += aContentArea.Origin(wm);
8106 aGridRI.mRows.AlignBaselineSubtree(*aGridItemInfo);
8107 aGridRI.mCols.AlignBaselineSubtree(*aGridItemInfo);
8108 // Setup [align|justify]-content:[last ]baseline related frame properties.
8109 // These are added to the padding in SizeComputationInput::InitOffsets.
8110 // (a negative value signals the value is for 'last baseline' and should be
8111 // added to the (logical) end padding)
8112 typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
8113 auto SetProp = [aGridItemInfo, aChild](LogicalAxis aGridAxis, Prop aProp) {
8114 auto state = aGridItemInfo->mState[aGridAxis];
8115 auto baselineAdjust = (state & ItemState::eContentBaseline)
8116 ? aGridItemInfo->mBaselineOffset[aGridAxis]
8117 : nscoord(0);
8118 if (baselineAdjust < nscoord(0)) {
8119 // This happens when the subtree overflows its track.
8120 // XXX spec issue? it's unclear how to handle this.
8121 baselineAdjust = nscoord(0);
8122 } else if (state & ItemState::eLastBaseline) {
8123 // FIXME: We're not setting the ItemState::eEndSideBaseline flag any
8124 // more as the new baseline sharing group calculation handles most of
8125 // the cases we need. For non-masonry grids this flag was always set
8126 // for LAST_BASELINE items, so we're just mimicking that behavior here.
8127 // That said, masonry grids might not work 100% any more..
8128 baselineAdjust = -baselineAdjust;
8129 }
8130 if (baselineAdjust != nscoord(0)) {
8131 aChild->SetProperty(aProp, baselineAdjust);
8132 } else {
8133 aChild->RemoveProperty(aProp);
8134 }
8135 };
8136 const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
8137 SetProp(LogicalAxis::Block,
8138 isOrthogonal ? IBaselinePadProperty() : BBaselinePadProperty());
8139 SetProp(LogicalAxis::Inline,
8140 isOrthogonal ? BBaselinePadProperty() : IBaselinePadProperty());
8141 } else {
8142 // By convention, for frames that perform CSS Box Alignment, we position
8143 // placeholder children at the start corner of their alignment container,
8144 // and in this case that's usually the grid's content-box.
8145 // ("Usually" - the exception is when the grid *also* forms the
8146 // abs.pos. containing block. In that case, the alignment container isn't
8147 // the content-box -- it's some grid area instead. But that case doesn't
8148 // require any special handling here, because we handle it later using a
8149 // special flag (ReflowInput::InitFlag::StaticPosIsCBOrigin) which will make
8150 // us ignore the placeholder's position entirely.)
8151 cb = aContentArea;
8152 aChild->AddStateBits(PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN);
8153 }
8154
8155 LogicalSize reflowSize(cb.Size(wm));
8156 if (isConstrainedBSize) {
8157 reflowSize.BSize(wm) = toFragmentainerEnd;
8158 }
8159 LogicalSize childCBSize = reflowSize.ConvertTo(childWM, wm);
8160
8161 // Setup the ClampMarginBoxMinSize reflow flags and property, if needed.
8162 ComputeSizeFlags csFlags;
8163 if (aGridItemInfo) {
8164 const auto childIAxisInWM = childWM.ConvertAxisTo(LogicalAxis::Inline, wm);
8165 // Clamp during reflow if we're stretching in that axis.
8166 if (GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
8167 if (aGridItemInfo->mState[childIAxisInWM] &
8168 ItemState::eClampMarginBoxMinSize) {
8169 csFlags += ComputeSizeFlag::IClampMarginBoxMinSize;
8170 }
8171 } else {
8172 csFlags += ComputeSizeFlag::ShrinkWrap;
8173 }
8174
8175 const auto childBAxisInWM = GetOrthogonalAxis(childIAxisInWM);
8176 if (GridItemShouldStretch(aChild, LogicalAxis::Block) &&
8177 aGridItemInfo->mState[childBAxisInWM] &
8178 ItemState::eClampMarginBoxMinSize) {
8179 csFlags += ComputeSizeFlag::BClampMarginBoxMinSize;
8180 aChild->SetProperty(BClampMarginBoxMinSizeProperty(),
8181 childCBSize.BSize(childWM));
8182 } else {
8183 aChild->RemoveProperty(BClampMarginBoxMinSizeProperty());
8184 }
8185
8186 if ((aGridItemInfo->mState[childIAxisInWM] &
8187 ItemState::eContentBasedAutoMinSize)) {
8188 csFlags += ComputeSizeFlag::IApplyAutoMinSize;
8189 }
8190 }
8191
8192 if (!isConstrainedBSize) {
8193 childCBSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
8194 }
8195 LogicalSize percentBasis(cb.Size(wm).ConvertTo(childWM, wm));
8196 ReflowInput childRI(pc, *aGridRI.mReflowInput, aChild, childCBSize,
8197 Some(percentBasis), {}, {}, csFlags);
8198 childRI.mFlags.mIsTopOfPage =
8199 aFragmentainer ? aFragmentainer->mIsTopOfPage : false;
8200
8201 // FIXME (perf): It would be faster to do this only if the previous reflow of
8202 // the child was a measuring reflow, and only if the child does some of the
8203 // things that are affected by ComputeSizeFlag::IsGridMeasuringReflow.
8204 childRI.SetBResize(true);
8205 childRI.SetBResizeForPercentages(true);
8206
8207 // If the child is stretching in its block axis, and we might be fragmenting
8208 // it in that axis, then setup a frame property to tell
8209 // nsBlockFrame::ComputeFinalSize the size.
8210 if (isConstrainedBSize && !wm.IsOrthogonalTo(childWM)) {
8211 const bool stretch =
8212 childRI.mStylePosition
8213 ->BSize(childWM, AnchorPosResolutionParams::From(&childRI))
8214 ->IsAuto() &&
8215 GridItemShouldStretch(aChild, LogicalAxis::Block);
8216 if (stretch) {
8217 aChild->SetProperty(FragStretchBSizeProperty(), *aStretchBSize);
8218 } else {
8219 aChild->RemoveProperty(FragStretchBSizeProperty());
8220 }
8221 }
8222
8223 // We need the width of the child before we can correctly convert
8224 // the writing-mode of its origin, so we reflow at (0, 0) using a dummy
8225 // aContainerSize, and then pass the correct position to FinishReflowChild.
8226 ReflowOutput childSize(childRI);
8227 const nsSize dummyContainerSize;
8228
8229 ReflowChild(aChild, pc, childSize, childRI, childWM, LogicalPoint(childWM),
8230 dummyContainerSize, ReflowChildFlags::Default, aStatus);
8231
8232 // childPos here initially represents the position that the child would have
8233 // (expressed as an istart,bstart corner *in its own writing-mode*) if it
8234 // were placed at the cb origin:
8235 LogicalPoint childPos = cb.Origin(wm).ConvertRectOriginTo(
8236 childWM, wm, childSize.PhysicalSize(), aContainerSize);
8237
8238 // Apply align/justify-self and reflow again if that affects the size.
8239 if (MOZ_LIKELY(isGridItem)(__builtin_expect(!!(isGridItem), 1))) {
8240 LogicalSize size = childSize.Size(childWM); // from the ReflowChild()
8241 auto applyItemSelfAlignment = [&](LogicalAxis aAxis, nscoord aCBSize) {
8242 auto align =
8243 childRI.mStylePosition->UsedSelfAlignment(aAxis, containerSC);
8244 auto state = aGridItemInfo->mState[aAxis];
8245 AlignJustifyFlags flags;
8246 if (IsMasonry(aAxis)) {
8247 // In a masonry axis, we inhibit applying 'stretch' and auto-margins
8248 // here since AlignJustifyTracksInMasonryAxis deals with that.
8249 // The only other {align,justify}-{self,content} values that have an
8250 // effect are '[last] baseline', the rest behave as 'start'.
8251 if (MOZ_LIKELY(!(state & ItemState::eSelfBaseline))(__builtin_expect(!!(!(state & ItemState::eSelfBaseline))
, 1))
) {
8252 align = {StyleAlignFlags::START};
8253 } else {
8254 auto group = (state & ItemState::eFirstBaseline)
8255 ? BaselineSharingGroup::First
8256 : BaselineSharingGroup::Last;
8257 auto itemStart = aGridItemInfo->mArea.LineRangeForAxis(aAxis).mStart;
8258 aCBSize = aGridRI.TracksFor(aAxis)
8259 .mSizes[itemStart]
8260 .mBaselineSubtreeSize[group];
8261 }
8262 flags += AlignJustifyFlag::IgnoreAutoMargins;
8263 } else if (state & ItemState::eContentBaseline) {
8264 align = {(state & ItemState::eFirstBaseline)
8265 ? StyleAlignFlags::SELF_START
8266 : StyleAlignFlags::SELF_END};
8267 }
8268 if (aAxis == LogicalAxis::Block) {
8269 AlignSelf(*aGridItemInfo, align, aCBSize, wm, childRI, size, flags,
8270 &childPos);
8271 } else {
8272 JustifySelf(*aGridItemInfo, align, aCBSize, wm, childRI, size, flags,
8273 &childPos);
8274 }
8275 };
8276 if (aStatus.IsComplete()) {
8277 applyItemSelfAlignment(LogicalAxis::Block,
8278 cb.BSize(wm) - consumedGridAreaBSize);
8279 }
8280 applyItemSelfAlignment(LogicalAxis::Inline, cb.ISize(wm));
8281 } // else, AbsoluteContainingBlock.cpp will handle align/justify-self.
8282
8283 FinishReflowChild(aChild, pc, childSize, &childRI, childWM, childPos,
8284 aContainerSize, ReflowChildFlags::ApplyRelativePositioning);
8285 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, aChild);
8286}
8287
8288nscoord nsGridContainerFrame::ReflowInFragmentainer(
8289 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8290 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
8291 Fragmentainer& aFragmentainer, const nsSize& aContainerSize) {
8292 MOZ_ASSERT(aStatus.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aStatus.IsEmpty()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8292)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 8292); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8293 MOZ_ASSERT(aGridRI.mReflowInput)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mReflowInput)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridRI.mReflowInput))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aGridRI.mReflowInput"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8293)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mReflowInput"
")"); do { MOZ_CrashSequence(__null, 8293); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8294
8295 // Collect our grid items and sort them in row order. Collect placeholders
8296 // and put them in a separate array.
8297 nsTArray<const GridItemInfo*> sortedItems(aGridRI.mGridItems.Length());
8298 nsTArray<nsIFrame*> placeholders(aGridRI.mAbsPosItems.Length());
8299 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
8300 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
8301 nsIFrame* child = *aGridRI.mIter;
8302 if (!child->IsPlaceholderFrame()) {
8303 const GridItemInfo* info = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
8304 sortedItems.AppendElement(info);
8305 } else {
8306 placeholders.AppendElement(child);
8307 }
8308 }
8309 // NOTE: We don't need stable_sort here, except in Masonry layout. There are
8310 // no dependencies on having content order between items on the same row in
8311 // the code below in the non-Masonry case.
8312 if (IsMasonry()) {
8313 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8314 GridItemInfo::IsStartRowLessThan);
8315 } else {
8316 std::sort(sortedItems.begin(), sortedItems.end(),
8317 GridItemInfo::IsStartRowLessThan);
8318 }
8319
8320 // Reflow our placeholder children; they must all be complete.
8321 for (auto child : placeholders) {
8322 nsReflowStatus childStatus;
8323 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(),
8324 &aFragmentainer, aGridRI, aContentArea, aDesiredSize,
8325 childStatus);
8326 MOZ_ASSERT(childStatus.IsComplete(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsComplete())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsComplete()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("childStatus.IsComplete()"
" (" "nsPlaceholderFrame should never need to be fragmented"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8327
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "nsPlaceholderFrame should never need to be fragmented"
")"); do { MOZ_CrashSequence(__null, 8327); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8327 "nsPlaceholderFrame should never need to be fragmented")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsComplete())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsComplete()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("childStatus.IsComplete()"
" (" "nsPlaceholderFrame should never need to be fragmented"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8327
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "nsPlaceholderFrame should never need to be fragmented"
")"); do { MOZ_CrashSequence(__null, 8327); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8328 }
8329
8330 // The available size for children - we'll set this to the edge of the last
8331 // row in most cases below, but for now use the full size.
8332 nscoord childAvailableSize = aFragmentainer.mToFragmentainerEnd;
8333 const uint32_t startRow = aGridRI.mStartRow;
8334 const uint32_t numRows = aGridRI.mRows.mSizes.Length();
8335 bool isBDBClone = aGridRI.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
8336 StyleBoxDecorationBreak::Clone;
8337 nscoord bpBEnd = aGridRI.mBorderPadding.BEnd(aGridRI.mWM);
8338
8339 // Set |endRow| to the first row that doesn't fit.
8340 uint32_t endRow = numRows;
8341 if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8342 for (uint32_t row = startRow; row < numRows; ++row) {
8343 auto& sz = aGridRI.mRows.mSizes[row];
8344 const nscoord bEnd = sz.mPosition + sz.mBase;
8345 nscoord remainingAvailableSize = childAvailableSize - bEnd;
8346 if (remainingAvailableSize < 0 ||
8347 (isBDBClone && remainingAvailableSize < bpBEnd)) {
8348 endRow = row;
8349 break;
8350 }
8351 }
8352 }
8353
8354 // Check for forced breaks on the items if available block-size for children
8355 // is constrained. That is, ignore forced breaks if available block-size for
8356 // children is unconstrained since our parent expected us to be fully
8357 // complete.
8358 bool isForcedBreak = false;
8359 const bool avoidBreakInside = ShouldAvoidBreakInside(*aGridRI.mReflowInput);
8360 if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8361 const bool isTopOfPage = aFragmentainer.mIsTopOfPage;
8362 for (const GridItemInfo* info : sortedItems) {
8363 uint32_t itemStartRow = info->mArea.mRows.mStart;
8364 if (itemStartRow == endRow) {
8365 break;
8366 }
8367 const auto* disp = info->mFrame->StyleDisplay();
8368 if (disp->BreakBefore()) {
8369 // Propagate break-before on the first row to the container unless we're
8370 // already at top-of-page.
8371 if ((itemStartRow == 0 && !isTopOfPage) || avoidBreakInside) {
8372 aStatus.SetInlineLineBreakBeforeAndReset();
8373 return aGridRI.mFragBStart;
8374 }
8375 if ((itemStartRow > startRow ||
8376 (itemStartRow == startRow && !isTopOfPage)) &&
8377 itemStartRow < endRow) {
8378 endRow = itemStartRow;
8379 isForcedBreak = true;
8380 // reset any BREAK_AFTER we found on an earlier item
8381 aStatus.Reset();
8382 break; // we're done since the items are sorted in row order
8383 }
8384 }
8385 uint32_t itemEndRow = info->mArea.mRows.mEnd;
8386 if (disp->BreakAfter()) {
8387 if (itemEndRow != numRows) {
8388 if (itemEndRow > startRow && itemEndRow < endRow) {
8389 endRow = itemEndRow;
8390 isForcedBreak = true;
8391 // No "break;" here since later items with break-after may have
8392 // a shorter span.
8393 }
8394 } else {
8395 // Propagate break-after on the last row to the container, we may
8396 // still find a break-before on this row though (and reset aStatus).
8397 aStatus.SetInlineLineBreakAfter(); // tentative
8398 }
8399 }
8400 }
8401
8402 // Consume at least one row in each fragment until we have consumed them
8403 // all. Except for the first row if there's a break opportunity before it.
8404 if (startRow == endRow && startRow != numRows &&
8405 (startRow != 0 || !aFragmentainer.mCanBreakAtStart)) {
8406 ++endRow;
8407 }
8408
8409 // Honor break-inside:avoid if we can't fit all rows.
8410 if (avoidBreakInside && endRow < numRows) {
8411 aStatus.SetInlineLineBreakBeforeAndReset();
8412 return aGridRI.mFragBStart;
8413 }
8414 }
8415
8416 // Calculate the block-size including this fragment.
8417 nscoord bEndRow =
8418 aGridRI.mRows.GridLineEdge(endRow, GridLineSide::BeforeGridGap);
8419 nscoord bSize;
8420 if (aFragmentainer.mIsAutoBSize) {
8421 // We only apply min-bsize once all rows are complete (when bsize is auto).
8422 if (endRow < numRows) {
8423 bSize = bEndRow;
8424 auto clampedBSize = ClampToCSSMaxBSize(bSize, aGridRI.mReflowInput);
8425 if (MOZ_UNLIKELY(clampedBSize != bSize)(__builtin_expect(!!(clampedBSize != bSize), 0))) {
8426 // We apply max-bsize in all fragments though.
8427 bSize = clampedBSize;
8428 } else if (!isBDBClone) {
8429 // The max-bsize won't make this fragment COMPLETE, so the block-end
8430 // border will be in a later fragment.
8431 bpBEnd = 0;
8432 }
8433 } else {
8434 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(bEndRow);
8435 }
8436 } else {
8437 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(
8438 aGridRI.mReflowInput->ComputedBSize());
8439 }
8440
8441 // Check for overflow and set aStatus INCOMPLETE if so. Note that we should
8442 // not overflow an unconstrained available block-size.
8443 const bool overflow = childAvailableSize != NS_UNCONSTRAINEDSIZE &&
8444 bSize + bpBEnd > childAvailableSize;
8445 if (overflow) {
8446 if (avoidBreakInside) {
8447 aStatus.SetInlineLineBreakBeforeAndReset();
8448 return aGridRI.mFragBStart;
8449 }
8450 bool breakAfterLastRow = endRow == numRows && aFragmentainer.mCanBreakAtEnd;
8451 if (breakAfterLastRow) {
8452 MOZ_ASSERT(bEndRow < bSize, "bogus aFragmentainer.mCanBreakAtEnd")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bEndRow < bSize)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bEndRow < bSize))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("bEndRow < bSize"
" (" "bogus aFragmentainer.mCanBreakAtEnd" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bEndRow < bSize"
") (" "bogus aFragmentainer.mCanBreakAtEnd" ")"); do { MOZ_CrashSequence
(__null, 8452); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8453 nscoord availableSize = childAvailableSize;
8454 if (isBDBClone) {
8455 availableSize -= bpBEnd;
8456 }
8457 // Pretend we have at least 1px available size, otherwise we'll never make
8458 // progress in consuming our bSize.
8459 availableSize =
8460 std::max(availableSize, aGridRI.mFragBStart + AppUnitsPerCSSPixel());
8461 // Fill the fragmentainer, but not more than our desired block-size and
8462 // at least to the size of the last row (even if that overflows).
8463 nscoord newBSize = std::min(bSize, availableSize);
8464 newBSize = std::max(newBSize, bEndRow);
8465 // If it's just the border+padding that is overflowing and we have
8466 // box-decoration-break:clone then we are technically COMPLETE. There's
8467 // no point in creating another zero-bsize fragment in this case.
8468 if (newBSize < bSize || !isBDBClone) {
8469 aStatus.SetIncomplete();
8470 }
8471 bSize = newBSize;
8472 } else if (bSize <= bEndRow && startRow + 1 < endRow) {
8473 if (endRow == numRows) {
8474 // We have more than one row in this fragment, so we can break before
8475 // the last row instead.
8476 --endRow;
8477 bEndRow =
8478 aGridRI.mRows.GridLineEdge(endRow, GridLineSide::BeforeGridGap);
8479 bSize = bEndRow;
8480 if (aFragmentainer.mIsAutoBSize) {
8481 bSize = ClampToCSSMaxBSize(bSize, aGridRI.mReflowInput);
8482 }
8483 }
8484 aStatus.SetIncomplete();
8485 } else if (endRow < numRows) {
8486 bSize = ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8487 } // else - no break opportunities.
8488 } else {
8489 // Even though our block-size fits we need to honor forced breaks, or if
8490 // a row doesn't fit in an auto-sized container (unless it's constrained
8491 // by a max-bsize which make us overflow-incomplete).
8492 if (endRow < numRows &&
8493 (isForcedBreak || (aFragmentainer.mIsAutoBSize && bEndRow == bSize))) {
8494 bSize = ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8495 }
8496 }
8497
8498 // If we can't fit all rows then we're at least overflow-incomplete.
8499 if (endRow < numRows) {
8500 childAvailableSize = bEndRow;
8501 if (aStatus.IsComplete()) {
8502 aStatus.SetOverflowIncomplete();
8503 aStatus.SetNextInFlowNeedsReflow();
8504 }
8505 } else if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8506 // Children always have the full size of the rows in this fragment.
8507 childAvailableSize = std::max(childAvailableSize, bEndRow);
8508 }
8509
8510 return ReflowRowsInFragmentainer(aGridRI, aContentArea, aDesiredSize, aStatus,
8511 aFragmentainer, aContainerSize, sortedItems,
8512 startRow, endRow, bSize, childAvailableSize);
8513}
8514
8515nscoord nsGridContainerFrame::ReflowRowsInFragmentainer(
8516 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8517 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
8518 Fragmentainer& aFragmentainer, const nsSize& aContainerSize,
8519 const nsTArray<const GridItemInfo*>& aSortedItems, uint32_t aStartRow,
8520 uint32_t aEndRow, nscoord aBSize, nscoord aAvailableSize) {
8521 FrameHashtable pushedItems;
8522 FrameHashtable incompleteItems;
8523 FrameHashtable overflowIncompleteItems;
8524 Maybe<nsTArray<nscoord>> masonryAxisPos;
8525 const auto rowCount = aGridRI.mRows.mSizes.Length();
8526 nscoord masonryAxisGap = 0;
8527 const auto wm = aGridRI.mWM;
8528 const bool isColMasonry = IsColMasonry();
8529 if (isColMasonry) {
8530 for (auto& sz : aGridRI.mCols.mSizes) {
8531 sz.mPosition = 0;
8532 }
8533 masonryAxisGap = nsLayoutUtils::ResolveGapToLength(
8534 aGridRI.mGridStyle->mColumnGap, aContentArea.ISize(wm));
8535 aGridRI.mCols.mGridGap = masonryAxisGap;
8536 masonryAxisPos.emplace(rowCount);
8537 masonryAxisPos->SetLength(rowCount);
8538 PodZero(masonryAxisPos->Elements(), rowCount);
8539 }
8540 bool isBDBClone = aGridRI.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
8541 StyleBoxDecorationBreak::Clone;
8542 bool didGrowRow = false;
8543 // As we walk across rows, we track whether the current row is at the top
8544 // of its grid-fragment, to help decide whether we can break before it. When
8545 // this function starts, our row is at the top of the current fragment if:
8546 // - we're starting with a nonzero row (i.e. we're a continuation)
8547 // OR:
8548 // - we're starting with the first row, & we're not allowed to break before
8549 // it (which makes it effectively at the top of its grid-fragment).
8550 bool isRowTopOfPage = aStartRow != 0 || !aFragmentainer.mCanBreakAtStart;
8551 const bool isStartRowTopOfPage = isRowTopOfPage;
8552 // Save our full available size for later.
8553 const nscoord gridAvailableSize = aFragmentainer.mToFragmentainerEnd;
8554 // Propagate the constrained size to our children.
8555 aFragmentainer.mToFragmentainerEnd = aAvailableSize;
8556 // Reflow the items in row order up to |aEndRow| and push items after that.
8557 uint32_t row = 0;
8558 // |i| is intentionally signed, so we can set it to -1 to restart the loop.
8559 for (int32_t i = 0, len = aSortedItems.Length(); i < len; ++i) {
8560 const GridItemInfo* const info = aSortedItems[i];
8561 nsIFrame* child = info->mFrame;
8562 row = info->mArea.mRows.mStart;
8563 MOZ_ASSERT(child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(child->GetPrevInFlow() ? row < aStartRow : row
>= aStartRow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(child->GetPrevInFlow() ? row
< aStartRow : row >= aStartRow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
" (" "unexpected child start row" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
") (" "unexpected child start row" ")"); do { MOZ_CrashSequence
(__null, 8564); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8564 "unexpected child start row")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(child->GetPrevInFlow() ? row < aStartRow : row
>= aStartRow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(child->GetPrevInFlow() ? row
< aStartRow : row >= aStartRow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
" (" "unexpected child start row" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
") (" "unexpected child start row" ")"); do { MOZ_CrashSequence
(__null, 8564); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8565 if (row >= aEndRow) {
8566 pushedItems.Insert(child);
8567 continue;
8568 }
8569
8570 bool rowCanGrow = false;
8571 nscoord maxRowSize = 0;
8572 if (row >= aStartRow) {
8573 if (row > aStartRow) {
8574 isRowTopOfPage = false;
8575 }
8576 // Can we grow this row? Only consider span=1 items per spec...
8577 rowCanGrow = !didGrowRow && info->mArea.mRows.Extent() == 1;
8578 if (rowCanGrow) {
8579 auto& sz = aGridRI.mRows.mSizes[row];
8580 // and only min-/max-content rows or flex rows in an auto-sized
8581 // container
8582 rowCanGrow = (sz.mState & TrackSize::eMinOrMaxContentMinSizing) ||
8583 ((sz.mState & TrackSize::eFlexMaxSizing) &&
8584 aFragmentainer.mIsAutoBSize);
8585 if (rowCanGrow) {
8586 if (isBDBClone) {
8587 maxRowSize = gridAvailableSize - aGridRI.mBorderPadding.BEnd(wm);
8588 } else {
8589 maxRowSize = gridAvailableSize;
8590 }
8591 maxRowSize -= sz.mPosition;
8592 // ...and only if there is space for it to grow.
8593 rowCanGrow = maxRowSize > sz.mBase;
8594 }
8595 }
8596 }
8597
8598 if (isColMasonry) {
8599 const auto& cols = info->mArea.mCols;
8600 MOZ_ASSERT((cols.mStart == 0 || cols.mStart == 1) && cols.Extent() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((cols.mStart == 0 || cols.mStart == 1) && cols
.Extent() == 1)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((cols.mStart == 0 || cols.mStart
== 1) && cols.Extent() == 1))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("(cols.mStart == 0 || cols.mStart == 1) && cols.Extent() == 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8600)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(cols.mStart == 0 || cols.mStart == 1) && cols.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 8600); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8601 aGridRI.mCols.mSizes[cols.mStart].mPosition = masonryAxisPos.ref()[row];
8602 }
8603
8604 // aFragmentainer.mIsTopOfPage is propagated to the child reflow input.
8605 // When it's false the child may request InlineBreak::Before. We set it
8606 // to false when the row is growable (as determined in the CSS Grid
8607 // Fragmentation spec) and there is a non-zero space between it and the
8608 // fragmentainer end (that can be used to grow it). If the child reports
8609 // a forced break in this case, we grow this row to fill the fragment and
8610 // restart the loop. We also restart the loop with |aEndRow = row|
8611 // (but without growing any row) for a InlineBreak::Before child if it spans
8612 // beyond the last row in this fragment. This is to avoid fragmenting it.
8613 // We only restart the loop once.
8614 aFragmentainer.mIsTopOfPage = isRowTopOfPage && !rowCanGrow;
8615 nsReflowStatus childStatus;
8616 // Pass along how much to stretch this fragment, in case it's needed.
8617 nscoord bSize =
8618 aGridRI.mRows.GridLineEdge(std::min(aEndRow, info->mArea.mRows.mEnd),
8619 GridLineSide::BeforeGridGap) -
8620 aGridRI.mRows.GridLineEdge(std::max(aStartRow, row),
8621 GridLineSide::AfterGridGap);
8622 ReflowInFlowChild(child, info, aContainerSize, Some(bSize), &aFragmentainer,
8623 aGridRI, aContentArea, aDesiredSize, childStatus);
8624 MOZ_ASSERT(childStatus.IsInlineBreakBefore() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete
() || !child->GetNextInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsInlineBreakBefore
() || !childStatus.IsFullyComplete() || !child->GetNextInFlow
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
" (" "fully-complete reflow should destroy any NIFs" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8626); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8625 !childStatus.IsFullyComplete() || !child->GetNextInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete
() || !child->GetNextInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsInlineBreakBefore
() || !childStatus.IsFullyComplete() || !child->GetNextInFlow
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
" (" "fully-complete reflow should destroy any NIFs" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8626); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8626 "fully-complete reflow should destroy any NIFs")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete
() || !child->GetNextInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsInlineBreakBefore
() || !childStatus.IsFullyComplete() || !child->GetNextInFlow
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
" (" "fully-complete reflow should destroy any NIFs" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8626); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8627
8628 if (childStatus.IsInlineBreakBefore()) {
8629 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrevInFlow()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrevInFlow()"
" (" "continuations should never report InlineBreak::Before status"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8631
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8631); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8630 !child->GetPrevInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrevInFlow()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrevInFlow()"
" (" "continuations should never report InlineBreak::Before status"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8631
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8631); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8631 "continuations should never report InlineBreak::Before status")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrevInFlow()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrevInFlow()"
" (" "continuations should never report InlineBreak::Before status"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8631
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8631); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8632 MOZ_ASSERT(!aFragmentainer.mIsTopOfPage,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFragmentainer.mIsTopOfPage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFragmentainer.mIsTopOfPage
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFragmentainer.mIsTopOfPage" " (" "got IsInlineBreakBefore() at top of page"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8633
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFragmentainer.mIsTopOfPage"
") (" "got IsInlineBreakBefore() at top of page" ")"); do { MOZ_CrashSequence
(__null, 8633); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8633 "got IsInlineBreakBefore() at top of page")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFragmentainer.mIsTopOfPage)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFragmentainer.mIsTopOfPage
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFragmentainer.mIsTopOfPage" " (" "got IsInlineBreakBefore() at top of page"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8633
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFragmentainer.mIsTopOfPage"
") (" "got IsInlineBreakBefore() at top of page" ")"); do { MOZ_CrashSequence
(__null, 8633); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8634 if (!didGrowRow) {
8635 if (rowCanGrow) {
8636 // Grow this row and restart with the next row as |aEndRow|.
8637 aGridRI.mRows.ResizeRow(row, maxRowSize);
8638 if (aGridRI.mSharedGridData) {
8639 aGridRI.mSharedGridData->mRows.ResizeRow(row, maxRowSize);
8640 }
8641 didGrowRow = true;
8642 aEndRow = row + 1; // growing this row makes the next one not fit
8643 i = -1; // i == 0 after the next loop increment
8644 isRowTopOfPage = isStartRowTopOfPage;
8645 overflowIncompleteItems.Clear();
8646 incompleteItems.Clear();
8647 nscoord bEndRow =
8648 aGridRI.mRows.GridLineEdge(aEndRow, GridLineSide::BeforeGridGap);
8649 aFragmentainer.mToFragmentainerEnd = bEndRow;
8650 if (aFragmentainer.mIsAutoBSize) {
8651 aBSize =
8652 ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8653 } else if (aStatus.IsIncomplete()) {
8654 aBSize = aGridRI.mReflowInput->ApplyMinMaxBSize(
8655 aGridRI.mReflowInput->ComputedBSize());
8656 aBSize = std::min(bEndRow, aBSize);
8657 }
8658 continue;
8659 }
8660
8661 if (!isRowTopOfPage) {
8662 // We can break before this row - restart with it as the new end row.
8663 aEndRow = row;
8664 aBSize =
8665 aGridRI.mRows.GridLineEdge(aEndRow, GridLineSide::BeforeGridGap);
8666 i = -1; // i == 0 after the next loop increment
8667 isRowTopOfPage = isStartRowTopOfPage;
8668 overflowIncompleteItems.Clear();
8669 incompleteItems.Clear();
8670 aStatus.SetIncomplete();
8671 continue;
8672 }
8673 NS_ERROR("got InlineBreak::Before at top-of-page")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "got InlineBreak::Before at top-of-page"
, "Error", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8673); MOZ_PretendNoReturn(); } while (0)
;
8674 childStatus.Reset();
8675 } else {
8676 // We got InlineBreak::Before again after growing the row - this can
8677 // happen if the child isn't splittable, e.g. some form controls.
8678 childStatus.Reset();
8679 if (child->GetNextInFlow()) {
8680 // The child already has a fragment, so we know it's splittable.
8681 childStatus.SetIncomplete();
8682 } // else, report that it's complete
8683 }
8684 } else if (childStatus.IsInlineBreakAfter()) {
8685 MOZ_ASSERT_UNREACHABLE("unexpected child reflow status")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"unexpected child reflow status" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected child reflow status" ")"
); do { MOZ_CrashSequence(__null, 8685); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8686 }
8687
8688 MOZ_ASSERT(!childStatus.IsInlineBreakBefore(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!childStatus.IsInlineBreakBefore())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!childStatus.IsInlineBreakBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!childStatus.IsInlineBreakBefore()" " (" "should've handled InlineBreak::Before above"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8689
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childStatus.IsInlineBreakBefore()"
") (" "should've handled InlineBreak::Before above" ")"); do
{ MOZ_CrashSequence(__null, 8689); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8689 "should've handled InlineBreak::Before above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!childStatus.IsInlineBreakBefore())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!childStatus.IsInlineBreakBefore
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!childStatus.IsInlineBreakBefore()" " (" "should've handled InlineBreak::Before above"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8689
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childStatus.IsInlineBreakBefore()"
") (" "should've handled InlineBreak::Before above" ")"); do
{ MOZ_CrashSequence(__null, 8689); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8690 if (childStatus.IsIncomplete()) {
8691 incompleteItems.Insert(child);
8692 } else if (!childStatus.IsFullyComplete()) {
8693 overflowIncompleteItems.Insert(child);
8694 }
8695 if (isColMasonry) {
8696 auto childWM = child->GetWritingMode();
8697 const auto childAxis = wm.ConvertAxisTo(LogicalAxis::Inline, childWM);
8698 auto normalPos = child->GetLogicalNormalPosition(wm, aContainerSize);
8699 auto sz =
8700 childAxis == LogicalAxis::Block ? child->BSize() : child->ISize();
8701 auto pos = normalPos.Pos(LogicalAxis::Inline, wm) + sz +
8702 child->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
8703 masonryAxisPos.ref()[row] =
8704 pos + masonryAxisGap - aContentArea.Start(LogicalAxis::Inline, wm);
8705 }
8706 }
8707
8708 // Record a break before |aEndRow|.
8709 aGridRI.mNextFragmentStartRow = aEndRow;
8710 if (aEndRow < rowCount) {
8711 aGridRI.mRows.BreakBeforeRow(aEndRow);
8712 if (aGridRI.mSharedGridData) {
8713 aGridRI.mSharedGridData->mRows.BreakBeforeRow(aEndRow);
8714 }
8715 }
8716
8717 const bool childrenMoved = PushIncompleteChildren(
8718 pushedItems, incompleteItems, overflowIncompleteItems);
8719 if (childrenMoved && aStatus.IsComplete()) {
8720 aStatus.SetOverflowIncomplete();
8721 aStatus.SetNextInFlowNeedsReflow();
8722 }
8723 if (!pushedItems.IsEmpty()) {
8724 AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
8725 // NOTE since we messed with our child list here, we intentionally
8726 // make aState.mIter invalid to avoid any use of it after this point.
8727 aGridRI.mIter.Invalidate();
8728 }
8729 if (!incompleteItems.IsEmpty()) {
8730 // NOTE since we messed with our child list here, we intentionally
8731 // make aState.mIter invalid to avoid any use of it after this point.
8732 aGridRI.mIter.Invalidate();
8733 }
8734
8735 if (isColMasonry) {
8736 nscoord maxSize = 0;
8737 for (auto pos : masonryAxisPos.ref()) {
8738 maxSize = std::max(maxSize, pos);
8739 }
8740 maxSize = std::max(nscoord(0), maxSize - masonryAxisGap);
8741 aGridRI.AlignJustifyContentInMasonryAxis(maxSize, aContentArea.ISize(wm));
8742 }
8743
8744 return aBSize;
8745}
8746
8747// Here's a brief overview of how Masonry layout is implemented:
8748// We setup two synthetic tracks in the Masonry axis so that the Reflow code
8749// can treat it the same as for normal grid layout. The first track is
8750// fixed (during item placement/layout) at the content box start and contains
8751// the start items for each grid-axis track. The second track contains
8752// all other items and is moved to the position where we want to position
8753// the currently laid out item (like a sliding window as we place items).
8754// Once item layout is done, the tracks are resized to be the size of
8755// the "masonry box", which is the offset from the content box start to
8756// the margin-box end of the item that is furthest away (this happens in
8757// AlignJustifyContentInMasonryAxis() called at the end of this method).
8758// This is to prepare for AlignJustifyTracksInMasonryAxis, which is called
8759// later by our caller.
8760// Both tracks store their first-/last-baseline group offsets as usual.
8761// The first-baseline of the start track, and the last-baseline of the last
8762// track (if they exist) are exported as the grid container's baselines, or
8763// we fall back to picking an item's baseline (all this is per normal grid
8764// layout). There's a slight difference in which items belongs to which
8765// group though - see InitializeItemBaselinesInMasonryAxis for details.
8766// This method returns the "masonry box" size (in the masonry axis).
8767nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aGridRI,
8768 const LogicalRect& aContentArea,
8769 SizingConstraint aConstraint,
8770 ReflowOutput& aDesiredSize,
8771 nsReflowStatus& aStatus,
8772 Fragmentainer* aFragmentainer,
8773 const nsSize& aContainerSize) {
8774 using BaselineAlignmentSet = Tracks::BaselineAlignmentSet;
8775
8776 auto recordAutoPlacement = [this, &aGridRI](GridItemInfo* aItem,
8777 LogicalAxis aGridAxis) {
8778 // When we're auto-placing an item in a continuation we need to record
8779 // the placement in mSharedGridData.
8780 if (MOZ_UNLIKELY(aGridRI.mSharedGridData && GetPrevInFlow())(__builtin_expect(!!(aGridRI.mSharedGridData && GetPrevInFlow
()), 0))
&&
8781 (aItem->mState[aGridAxis] & ItemState::eAutoPlacement)) {
8782 auto* child = aItem->mFrame;
8783 MOZ_RELEASE_ASSERT(!child->GetPrevInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrevInFlow()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrevInFlow()"
" (" "continuations should never be auto-placed" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8784); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never be auto-placed" ")"); do {
MOZ_CrashSequence(__null, 8784); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8784 "continuations should never be auto-placed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrevInFlow()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrevInFlow()"
" (" "continuations should never be auto-placed" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8784); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never be auto-placed" ")"); do {
MOZ_CrashSequence(__null, 8784); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8785 for (auto& sharedItem : aGridRI.mSharedGridData->mGridItems) {
8786 if (sharedItem.mFrame == child) {
8787 sharedItem.mArea.LineRangeForAxis(aGridAxis) =
8788 aItem->mArea.LineRangeForAxis(aGridAxis);
8789 MOZ_ASSERT(sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8789)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement"
")"); do { MOZ_CrashSequence(__null, 8789); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8790 sharedItem.mState[aGridAxis] &= ~ItemState::eAutoPlacement;
8791 break;
8792 }
8793 }
8794 }
8795 aItem->mState[aGridAxis] &= ~ItemState::eAutoPlacement;
8796 };
8797
8798 // Collect our grid items and sort them in grid order.
8799 nsTArray<GridItemInfo*> sortedItems(aGridRI.mGridItems.Length());
8800 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
8801 const LogicalAxis masonryAxis =
8802 IsMasonry(LogicalAxis::Block) ? LogicalAxis::Block : LogicalAxis::Inline;
8803 const auto wm = aGridRI.mWM;
8804 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
8805 nsIFrame* child = *aGridRI.mIter;
8806 if (MOZ_LIKELY(!child->IsPlaceholderFrame())(__builtin_expect(!!(!child->IsPlaceholderFrame()), 1))) {
8807 GridItemInfo* item = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
8808 sortedItems.AppendElement(item);
8809 } else if (aConstraint == SizingConstraint::NoConstraint) {
8810 // (we only collect placeholders in the NoConstraint case since they
8811 // don't affect intrinsic sizing in any way)
8812 GridItemInfo* item = nullptr;
8813 auto* ph = static_cast<nsPlaceholderFrame*>(child);
8814 auto* oof = ph->GetOutOfFlowFrame();
8815 if (oof && oof->GetParent() == this) {
8816 // mAbsPosItems can include descendants whose placeholders are nested
8817 // inside grid items and aren't visited by mIter. Search by frame since
8818 // the array indices need not match the order of placeholders we visit.
8819 for (auto& absPosItem : aGridRI.mAbsPosItems) {
8820 if (absPosItem.mFrame == oof) {
8821 item = &absPosItem;
8822 break;
8823 }
8824 }
8825 MOZ_RELEASE_ASSERT(item)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(item))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("item", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8825); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "item"
")"); do { MOZ_CrashSequence(__null, 8825); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8826 auto masonryStart = item->mArea.LineRangeForAxis(masonryAxis).mStart;
8827 // If the item was placed by the author at line 1 (masonryStart == 0)
8828 // then include it to be placed at the masonry-box start. If it's
8829 // auto-placed and has an `auto` inset value in the masonry axis then
8830 // we include it to be placed after the last grid item with the same
8831 // grid-axis start track.
8832 // XXXmats this is all a bit experimental at this point, pending a spec
8833 const auto masonrySide = masonryAxis == LogicalAxis::Inline
8834 ? LogicalSide::IStart
8835 : LogicalSide::BStart;
8836 if (masonryStart == 0 ||
8837 (masonryStart == kAutoLine &&
8838 item->mFrame->StylePosition()
8839 ->GetAnchorResolvedInset(
8840 masonrySide, wm,
8841 AnchorPosOffsetResolutionParams::UseCBFrameSize(
8842 AnchorPosResolutionParams::From(item->mFrame)))
8843 ->IsAuto())) {
8844 sortedItems.AppendElement(item);
8845 } else {
8846 item = nullptr;
8847 }
8848 }
8849 if (!item) {
8850 // It wasn't included above - just reflow it and be done with it.
8851 nsReflowStatus childStatus;
8852 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(), nullptr,
8853 aGridRI, aContentArea, aDesiredSize, childStatus);
8854 }
8855 }
8856 }
8857 if (masonryAxis == LogicalAxis::Block) {
8858 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8859 GridItemInfo::RowMasonryDefiniteFirst);
8860 } else {
8861 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8862 GridItemInfo::ColMasonryDefiniteFirst);
8863 }
8864
8865 FrameHashtable pushedItems;
8866 FrameHashtable incompleteItems;
8867 FrameHashtable overflowIncompleteItems;
8868 nscoord toFragmentainerEnd = nscoord_MAX;
8869 nscoord fragStartPos = aGridRI.mFragBStart;
8870 const bool avoidBreakInside =
8871 aFragmentainer && ShouldAvoidBreakInside(*aGridRI.mReflowInput);
8872 const bool isTopOfPageAtStart =
8873 aFragmentainer && aFragmentainer->mIsTopOfPage;
8874 if (aFragmentainer) {
8875 toFragmentainerEnd = std::max(0, aFragmentainer->mToFragmentainerEnd);
8876 }
8877 const LogicalAxis gridAxis = GetOrthogonalAxis(masonryAxis);
8878 const auto gridAxisTrackCount = aGridRI.TracksFor(gridAxis).mSizes.Length();
8879 auto& masonryTracks = aGridRI.TracksFor(masonryAxis);
8880 auto& masonrySizes = masonryTracks.mSizes;
8881 MOZ_ASSERT(masonrySizes.Length() == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonrySizes.Length() == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(masonrySizes.Length() == 2))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("masonrySizes.Length() == 2"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8881)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonrySizes.Length() == 2"
")"); do { MOZ_CrashSequence(__null, 8881); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8882 for (auto& sz : masonrySizes) {
8883 sz.mPosition = fragStartPos;
8884 }
8885 // The current running position for each grid-axis track where the next item
8886 // should be positioned. When an item is placed we'll update the tracks it
8887 // spans to the end of its margin box + 'gap'.
8888 nsTArray<nscoord> currentPos(gridAxisTrackCount);
8889 currentPos.SetLength(gridAxisTrackCount);
8890 for (auto& sz : currentPos) {
8891 sz = fragStartPos;
8892 }
8893 nsTArray<nscoord> lastPos(currentPos.Clone());
8894 nsTArray<GridItemInfo*> lastItems(gridAxisTrackCount);
8895 lastItems.SetLength(gridAxisTrackCount);
8896 PodZero(lastItems.Elements(), gridAxisTrackCount);
8897 const nscoord gap = nsLayoutUtils::ResolveGapToLength(
8898 masonryAxis == LogicalAxis::Block ? aGridRI.mGridStyle->mRowGap
8899 : aGridRI.mGridStyle->mColumnGap,
8900 masonryTracks.mContentBoxSize);
8901 masonryTracks.mGridGap = gap;
8902 const auto containerToMasonryBoxOffset =
8903 fragStartPos - aContentArea.Start(masonryAxis, wm);
8904 bool didAlignStartAlignedFirstItems = false;
8905
8906 // Return true if any of the lastItems in aRange are baseline-aligned in
8907 // the masonry axis.
8908 auto lastItemHasBaselineAlignment = [&](const LineRange& aRange) {
8909 for (auto i : aRange.Range()) {
8910 if (auto* child = lastItems[i] ? lastItems[i]->mFrame : nullptr) {
8911 const auto& pos = child->StylePosition();
8912 auto selfAlignment = pos->UsedSelfAlignment(masonryAxis, this->Style());
8913 if (selfAlignment == StyleAlignFlags::BASELINE ||
8914 selfAlignment == StyleAlignFlags::LAST_BASELINE) {
8915 return true;
8916 }
8917 auto childAxis = masonryAxis;
8918 if (child->GetWritingMode().IsOrthogonalTo(wm)) {
8919 childAxis = gridAxis;
8920 }
8921 auto contentAlignment = pos->UsedContentAlignment(childAxis).primary;
8922 if (contentAlignment == StyleAlignFlags::BASELINE ||
8923 contentAlignment == StyleAlignFlags::LAST_BASELINE) {
8924 return true;
8925 }
8926 }
8927 }
8928 return false;
8929 };
8930
8931 // Resolve aItem's placement, unless it's definite already. Return its
8932 // masonry axis position with that placement.
8933 auto placeItem = [&](GridItemInfo* aItem) -> nscoord {
8934 auto& masonryAxisRange = aItem->mArea.LineRangeForAxis(masonryAxis);
8935 MOZ_ASSERT(masonryAxisRange.mStart != 0, "item placement is already final")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(masonryAxisRange.mStart != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(masonryAxisRange.mStart != 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"masonryAxisRange.mStart != 0" " (" "item placement is already final"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 8935
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisRange.mStart != 0"
") (" "item placement is already final" ")"); do { MOZ_CrashSequence
(__null, 8935); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8936 auto& gridAxisRange = aItem->mArea.LineRangeForAxis(gridAxis);
8937 bool isAutoPlaced = aItem->mState[gridAxis] & ItemState::eAutoPlacement;
8938 uint32_t start = isAutoPlaced ? 0 : gridAxisRange.mStart;
8939 const uint32_t extent = gridAxisRange.Extent();
8940 if (start + extent > gridAxisTrackCount) {
8941 // Note that this will only happen to auto-placed items since the grid is
8942 // always wide enough to fit other items.
8943 start = 0;
8944 }
8945 // This keeps track of the smallest `maxPosForRange` value that
8946 // we discover in the loop below:
8947 nscoord minPos = nscoord_MAX;
8948 MOZ_ASSERT(extent <= gridAxisTrackCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(extent <= gridAxisTrackCount)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(extent <= gridAxisTrackCount
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"extent <= gridAxisTrackCount", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 8948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "extent <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 8948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8949 const uint32_t iEnd = gridAxisTrackCount + 1 - extent;
8950 for (uint32_t i = start; i < iEnd; ++i) {
8951 // Find the max `currentPos` value for the tracks that we would span
8952 // if we were to use `i` as our start track:
8953 nscoord maxPosForRange = 0;
8954 for (auto j = i, jEnd = j + extent; j < jEnd; ++j) {
8955 maxPosForRange = std::max(currentPos[j], maxPosForRange);
8956 }
8957 if (maxPosForRange < minPos) {
8958 minPos = maxPosForRange;
8959 start = i;
8960 }
8961 if (!isAutoPlaced) {
8962 break;
8963 }
8964 }
8965 gridAxisRange.mStart = start;
8966 gridAxisRange.mEnd = start + extent;
8967 bool isFirstItem = true;
8968 for (uint32_t i : gridAxisRange.Range()) {
8969 if (lastItems[i]) {
8970 isFirstItem = false;
8971 break;
8972 }
8973 }
8974 // If this is the first item in its spanned grid tracks, then place it in
8975 // the first masonry track. Otherwise, place it in the second masonry track.
8976 masonryAxisRange.mStart = isFirstItem ? 0 : 1;
8977 masonryAxisRange.mEnd = masonryAxisRange.mStart + 1;
8978 return minPos;
8979 };
8980
8981 // Handle the resulting reflow status after reflowing aItem.
8982 // This may set aStatus to BreakBefore which the caller is expected
8983 // to handle by returning from MasonryLayout.
8984 // @return true if this item should consume all remaining space
8985 auto handleChildStatus = [&](GridItemInfo* aItem,
8986 const nsReflowStatus& aChildStatus) {
8987 bool result = false;
8988 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
8989 auto* child = aItem->mFrame;
8990 if (!aChildStatus.IsComplete() || aChildStatus.IsInlineBreakBefore() ||
8991 aChildStatus.IsInlineBreakAfter() ||
8992 child->StyleDisplay()->BreakAfter()) {
8993 if (!isTopOfPageAtStart && avoidBreakInside) {
8994 aStatus.SetInlineLineBreakBeforeAndReset();
8995 return result;
8996 }
8997 result = true;
8998 }
8999 if (aChildStatus.IsInlineBreakBefore()) {
9000 aStatus.SetIncomplete();
9001 pushedItems.Insert(child);
9002 } else if (aChildStatus.IsIncomplete()) {
9003 recordAutoPlacement(aItem, gridAxis);
9004 aStatus.SetIncomplete();
9005 incompleteItems.Insert(child);
9006 } else if (!aChildStatus.IsFullyComplete()) {
9007 recordAutoPlacement(aItem, gridAxis);
9008 overflowIncompleteItems.Insert(child);
9009 }
9010 }
9011 return result;
9012 };
9013
9014 // @return the distance from the masonry-box start to the end of the margin-
9015 // box of aChild
9016 auto offsetToMarginBoxEnd = [&](nsIFrame* aChild) {
9017 auto childWM = aChild->GetWritingMode();
9018 auto childAxis = !childWM.IsOrthogonalTo(wm) ? masonryAxis : gridAxis;
9019 auto normalPos = aChild->GetLogicalNormalPosition(wm, aContainerSize);
9020 auto sz =
9021 childAxis == LogicalAxis::Block ? aChild->BSize() : aChild->ISize();
9022 return containerToMasonryBoxOffset + normalPos.Pos(masonryAxis, wm) + sz +
9023 aChild->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
9024 };
9025
9026 // Apply baseline alignment to items belonging to the given set.
9027 nsTArray<Tracks::ItemBaselineData> firstBaselineItems;
9028 nsTArray<Tracks::ItemBaselineData> lastBaselineItems;
9029 auto applyBaselineAlignment = [&](BaselineAlignmentSet aSet) {
9030 firstBaselineItems.ClearAndRetainStorage();
9031 lastBaselineItems.ClearAndRetainStorage();
9032 masonryTracks.InitializeItemBaselinesInMasonryAxis(
9033 aGridRI, aGridRI.mGridItems, aSet, aContainerSize, currentPos,
9034 firstBaselineItems, lastBaselineItems);
9035
9036 bool didBaselineAdjustment = false;
9037 nsTArray<Tracks::ItemBaselineData>* baselineItems[] = {&firstBaselineItems,
9038 &lastBaselineItems};
9039 for (const auto* items : baselineItems) {
9040 for (const auto& data : *items) {
9041 GridItemInfo* item = data.mGridItem;
9042 MOZ_ASSERT((item->mState[masonryAxis] & ItemState::eIsBaselineAligned))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((item->mState[masonryAxis] & ItemState::eIsBaselineAligned
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((item->mState[masonryAxis] & ItemState::eIsBaselineAligned
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(item->mState[masonryAxis] & ItemState::eIsBaselineAligned)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9042)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item->mState[masonryAxis] & ItemState::eIsBaselineAligned)"
")"); do { MOZ_CrashSequence(__null, 9042); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9043 nscoord baselineOffset = item->mBaselineOffset[masonryAxis];
9044 if (baselineOffset == nscoord(0)) {
9045 continue; // no adjustment needed for this item
9046 }
9047 didBaselineAdjustment = true;
9048 auto* child = item->mFrame;
9049 auto masonryAxisStart =
9050 item->mArea.LineRangeForAxis(masonryAxis).mStart;
9051 auto gridAxisRange = item->mArea.LineRangeForAxis(gridAxis);
9052 masonrySizes[masonryAxisStart].mPosition =
9053 aSet.mItemSet == BaselineAlignmentSet::LastItems
9054 ? lastPos[gridAxisRange.mStart]
9055 : fragStartPos;
9056 bool consumeAllSpace = false;
9057 const auto state = item->mState[masonryAxis];
9058 if ((state & ItemState::eContentBaseline) ||
9059 MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9060 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9061 aFragmentainer->mIsTopOfPage =
9062 isTopOfPageAtStart &&
9063 masonrySizes[masonryAxisStart].mPosition == fragStartPos;
9064 }
9065 nsReflowStatus childStatus;
9066 ReflowInFlowChild(child, item, aContainerSize, Nothing(),
9067 aFragmentainer, aGridRI, aContentArea, aDesiredSize,
9068 childStatus);
9069 consumeAllSpace = handleChildStatus(item, childStatus);
9070 if (aStatus.IsInlineBreakBefore()) {
9071 return false;
9072 }
9073 } else if (!(state & ItemState::eEndSideBaseline)) {
9074 // `align/justify-self` baselines on the start side can be handled by
9075 // just moving the frame (except in a fragmentainer in which case we
9076 // reflow it above instead since it might make it INCOMPLETE).
9077 LogicalPoint logicalDelta(wm);
9078 logicalDelta.Pos(masonryAxis, wm) = baselineOffset;
9079 child->MovePositionBy(wm, logicalDelta);
9080 }
9081 if ((state & ItemState::eEndSideBaseline) && !consumeAllSpace) {
9082 // Account for an end-side baseline adjustment.
9083 for (uint32_t i : gridAxisRange.Range()) {
9084 currentPos[i] += baselineOffset;
9085 }
9086 } else {
9087 nscoord pos = consumeAllSpace ? toFragmentainerEnd
9088 : offsetToMarginBoxEnd(child);
9089 pos += gap;
9090 for (uint32_t i : gridAxisRange.Range()) {
9091 currentPos[i] = pos;
9092 }
9093 }
9094 }
9095 }
9096 return didBaselineAdjustment;
9097 };
9098
9099 // Place and reflow items. We'll use two fake tracks in the masonry axis.
9100 // The first contains items that were placed there by the regular grid
9101 // placement algo (PlaceGridItems) and we may add some items here if there
9102 // are still empty slots. The second track contains all other items.
9103 // Both tracks always have the size of the content box in the masonry axis.
9104 // The position of the first track is always at the start. The position
9105 // of the second track is updated as we go to a position where we want
9106 // the current item to be positioned.
9107 for (GridItemInfo* item : sortedItems) {
9108 auto* child = item->mFrame;
9109 auto& masonryRange = item->mArea.LineRangeForAxis(masonryAxis);
9110 auto& gridRange = item->mArea.LineRangeForAxis(gridAxis);
9111 nsReflowStatus childStatus;
9112 if (MOZ_UNLIKELY(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))(__builtin_expect(!!(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)), 0))
) {
9113 auto contentArea = aContentArea;
9114 nscoord pos = nscoord_MAX;
9115 // XXXmats take mEnd into consideration...
9116 if (gridRange.mStart == kAutoLine) {
9117 for (auto p : currentPos) {
9118 pos = std::min(p, pos);
9119 }
9120 } else if (gridRange.mStart < currentPos.Length()) {
9121 pos = currentPos[gridRange.mStart];
9122 } else if (currentPos.Length() > 0) {
9123 pos = currentPos.LastElement();
9124 }
9125 if (pos == nscoord_MAX) {
9126 pos = nscoord(0);
9127 }
9128 contentArea.Start(masonryAxis, wm) = pos;
9129 child = child->GetPlaceholderFrame();
9130 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(), nullptr,
9131 aGridRI, contentArea, aDesiredSize, childStatus);
9132 } else {
9133 MOZ_ASSERT(gridRange.Extent() > 0 &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gridRange.Extent() > 0 && gridRange.Extent
() <= gridAxisTrackCount)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gridRange.Extent() > 0 &&
gridRange.Extent() <= gridAxisTrackCount))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9134)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 9134); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9134 gridRange.Extent() <= gridAxisTrackCount)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gridRange.Extent() > 0 && gridRange.Extent
() <= gridAxisTrackCount)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gridRange.Extent() > 0 &&
gridRange.Extent() <= gridAxisTrackCount))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9134)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 9134); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9135 MOZ_ASSERT((masonryRange.mStart == 0 || masonryRange.mStart == 1) &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((masonryRange.mStart == 0 || masonryRange.mStart == 1
) && masonryRange.Extent() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((masonryRange.mStart == 0 ||
masonryRange.mStart == 1) && masonryRange.Extent() ==
1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9136)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 9136); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9136 masonryRange.Extent() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((masonryRange.mStart == 0 || masonryRange.mStart == 1
) && masonryRange.Extent() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((masonryRange.mStart == 0 ||
masonryRange.mStart == 1) && masonryRange.Extent() ==
1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9136)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 9136); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9137 if (masonryRange.mStart != 0) {
9138 masonrySizes[1].mPosition = placeItem(item);
9139 }
9140
9141 // If this is the first item NOT in the first track and if any of
9142 // the grid-axis tracks we span has a baseline-aligned item then we
9143 // need to do that baseline alignment now since it may affect
9144 // the placement of this and later items.
9145 if (!didAlignStartAlignedFirstItems &&
9146 aConstraint == SizingConstraint::NoConstraint &&
9147 masonryRange.mStart != 0 && lastItemHasBaselineAlignment(gridRange)) {
9148 didAlignStartAlignedFirstItems = true;
9149 if (applyBaselineAlignment({BaselineAlignmentSet::FirstItems,
9150 BaselineAlignmentSet::StartStretch})) {
9151 // Baseline alignment resized some items - redo our placement.
9152 masonrySizes[1].mPosition = placeItem(item);
9153 }
9154 if (aStatus.IsInlineBreakBefore()) {
9155 return fragStartPos;
9156 }
9157 }
9158
9159 for (uint32_t i : gridRange.Range()) {
9160 lastItems[i] = item;
9161 }
9162 nscoord pos;
9163 if (aConstraint == SizingConstraint::NoConstraint) {
9164 const auto* disp = child->StyleDisplay();
9165 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9166 aFragmentainer->mIsTopOfPage =
9167 isTopOfPageAtStart &&
9168 masonrySizes[masonryRange.mStart].mPosition == fragStartPos;
9169 if (!aFragmentainer->mIsTopOfPage &&
9170 (disp->BreakBefore() ||
9171 masonrySizes[masonryRange.mStart].mPosition >=
9172 toFragmentainerEnd)) {
9173 childStatus.SetInlineLineBreakBeforeAndReset();
9174 }
9175 }
9176 if (!childStatus.IsInlineBreakBefore()) {
9177 ReflowInFlowChild(child, item, aContainerSize, Nothing(),
9178 aFragmentainer, aGridRI, aContentArea, aDesiredSize,
9179 childStatus);
9180 }
9181 bool consumeAllSpace = handleChildStatus(item, childStatus);
9182 if (aStatus.IsInlineBreakBefore()) {
9183 return fragStartPos;
9184 }
9185 pos =
9186 consumeAllSpace ? toFragmentainerEnd : offsetToMarginBoxEnd(child);
9187 } else {
9188 LogicalSize percentBasis(
9189 aGridRI.PercentageBasisFor(LogicalAxis::Inline, *item));
9190 IntrinsicISizeType type = aConstraint == SizingConstraint::MaxContent
9191 ? IntrinsicISizeType::PrefISize
9192 : IntrinsicISizeType::MinISize;
9193 auto sz = ::ContentContribution(*item, aGridRI, masonryAxis,
9194 percentBasis, type);
9195 pos = sz + masonrySizes[masonryRange.mStart].mPosition;
9196 }
9197 pos += gap;
9198 for (uint32_t i : gridRange.Range()) {
9199 lastPos[i] = currentPos[i];
9200 currentPos[i] = pos;
9201 }
9202 }
9203 }
9204
9205 // Do the remaining baseline alignment sets.
9206 if (aConstraint == SizingConstraint::NoConstraint) {
9207 for (auto*& item : lastItems) {
9208 if (item) {
9209 item->mState[masonryAxis] |= ItemState::eIsLastItemInMasonryTrack;
9210 }
9211 }
9212 BaselineAlignmentSet baselineSets[] = {
9213 {BaselineAlignmentSet::FirstItems, BaselineAlignmentSet::StartStretch},
9214 {BaselineAlignmentSet::FirstItems, BaselineAlignmentSet::EndStretch},
9215 {BaselineAlignmentSet::LastItems, BaselineAlignmentSet::StartStretch},
9216 {BaselineAlignmentSet::LastItems, BaselineAlignmentSet::EndStretch},
9217 };
9218 for (uint32_t i = 0; i < std::size(baselineSets); ++i) {
9219 if (i == 0 && didAlignStartAlignedFirstItems) {
9220 continue;
9221 }
9222 applyBaselineAlignment(baselineSets[i]);
9223 }
9224 }
9225
9226 const bool childrenMoved = PushIncompleteChildren(
9227 pushedItems, incompleteItems, overflowIncompleteItems);
9228 if (childrenMoved && aStatus.IsComplete()) {
9229 aStatus.SetOverflowIncomplete();
9230 aStatus.SetNextInFlowNeedsReflow();
9231 }
9232 if (!pushedItems.IsEmpty()) {
9233 AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
9234 // NOTE since we messed with our child list here, we intentionally
9235 // make aState.mIter invalid to avoid any use of it after this point.
9236 aGridRI.mIter.Invalidate();
9237 }
9238 if (!incompleteItems.IsEmpty()) {
9239 // NOTE since we messed with our child list here, we intentionally
9240 // make aState.mIter invalid to avoid any use of it after this point.
9241 aGridRI.mIter.Invalidate();
9242 }
9243
9244 nscoord masonryBoxSize = 0;
9245 for (auto pos : currentPos) {
9246 masonryBoxSize = std::max(masonryBoxSize, pos);
9247 }
9248 masonryBoxSize = std::max(nscoord(0), masonryBoxSize - gap);
9249 if (aConstraint == SizingConstraint::NoConstraint) {
9250 aGridRI.AlignJustifyContentInMasonryAxis(masonryBoxSize,
9251 masonryTracks.mContentBoxSize);
9252 }
9253 return masonryBoxSize;
9254}
9255
9256nsGridContainerFrame* nsGridContainerFrame::ParentGridContainerForSubgrid()
9257 const {
9258 MOZ_ASSERT(IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSubgrid()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsSubgrid()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9258); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9259 nsIFrame* p = GetParent();
9260 while (p->GetContent() == GetContent()) {
9261 p = p->GetParent();
9262 }
9263 MOZ_ASSERT(p->IsGridContainerFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(p->IsGridContainerFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p->IsGridContainerFrame()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"p->IsGridContainerFrame()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 9263); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9264 auto* parent = static_cast<nsGridContainerFrame*>(p);
9265 MOZ_ASSERT(parent->HasSubgridItems())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->HasSubgridItems())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parent->HasSubgridItems()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"parent->HasSubgridItems()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent->HasSubgridItems()"
")"); do { MOZ_CrashSequence(__null, 9265); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9266 return parent;
9267}
9268
9269nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aGridRI,
9270 const LogicalRect& aContentArea,
9271 const nsSize& aContainerSize,
9272 ReflowOutput& aDesiredSize,
9273 nsReflowStatus& aStatus) {
9274 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
9275 nscoord bSize = aContentArea.BSize(wm);
9276 MOZ_ASSERT(aGridRI.mReflowInput)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mReflowInput)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGridRI.mReflowInput))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aGridRI.mReflowInput"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9276)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mReflowInput"
")"); do { MOZ_CrashSequence(__null, 9276); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9277 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aStatus.IsEmpty()"
" (" "Caller should pass a fresh reflow status!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
MOZ_CrashSequence(__null, 9277); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9278 if (HidesContentForLayout()) {
9279 return bSize;
9280 }
9281
9282 OverflowAreas ocBounds;
9283 nsReflowStatus ocStatus;
9284 if (GetPrevInFlow()) {
9285 ReflowOverflowContainerChildren(PresContext(), *aGridRI.mReflowInput,
9286 ocBounds, ReflowChildFlags::Default,
9287 ocStatus, MergeSortedFrameListsFor);
9288 }
9289
9290 Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aGridRI);
9291 // MasonryLayout() can only handle fragmentation in the masonry-axis,
9292 // so we let ReflowInFragmentainer() deal with grid-axis fragmentation
9293 // in the else-clause below.
9294 if (IsMasonry() && !(IsColMasonry() && fragmentainer.isSome())) {
9295 aGridRI.mInFragmentainer = fragmentainer.isSome();
9296 nscoord sz = MasonryLayout(
9297 aGridRI, aContentArea, SizingConstraint::NoConstraint, aDesiredSize,
9298 aStatus, fragmentainer.ptrOr(nullptr), aContainerSize);
9299 if (IsRowMasonry()) {
9300 bSize = aGridRI.mReflowInput->ComputedBSize();
9301 if (bSize == NS_UNCONSTRAINEDSIZE) {
9302 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(sz);
9303 }
9304 }
9305 } else if (MOZ_UNLIKELY(fragmentainer.isSome())(__builtin_expect(!!(fragmentainer.isSome()), 0))) {
9306 if (IsColMasonry() && !GetPrevInFlow()) {
9307 // First we do an unconstrained reflow to resolve the item placement
9308 // which is then kept as-is in the constrained reflow below.
9309 MasonryLayout(aGridRI, aContentArea, SizingConstraint::NoConstraint,
9310 aDesiredSize, aStatus, nullptr, aContainerSize);
9311 }
9312 aGridRI.mInFragmentainer = true;
9313 bSize = ReflowInFragmentainer(aGridRI, aContentArea, aDesiredSize, aStatus,
9314 *fragmentainer, aContainerSize);
9315 } else {
9316 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
9317 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
9318 nsIFrame* child = *aGridRI.mIter;
9319 const GridItemInfo* info = nullptr;
9320 if (!child->IsPlaceholderFrame()) {
9321 info = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
9322 }
9323 nsReflowStatus childStatus;
9324 ReflowInFlowChild(child, info, aContainerSize, Nothing(), nullptr,
9325 aGridRI, aContentArea, aDesiredSize, childStatus);
9326 MOZ_ASSERT(childStatus.IsComplete(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsComplete())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsComplete()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("childStatus.IsComplete()"
" (" "child should be complete in unconstrained reflow" ")",
"./../../../layout/generic/nsGridContainerFrame.cpp", 9327);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "child should be complete in unconstrained reflow" ")"
); do { MOZ_CrashSequence(__null, 9327); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9327 "child should be complete in unconstrained reflow")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childStatus.IsComplete())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childStatus.IsComplete()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("childStatus.IsComplete()"
" (" "child should be complete in unconstrained reflow" ")",
"./../../../layout/generic/nsGridContainerFrame.cpp", 9327);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "child should be complete in unconstrained reflow" ")"
); do { MOZ_CrashSequence(__null, 9327); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9328 aStatus.MergeCompletionStatusFrom(childStatus);
9329 }
9330 }
9331
9332 // Merge overflow container bounds and status.
9333 aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
9334 aStatus.MergeCompletionStatusFrom(ocStatus);
9335
9336 return bSize;
9337}
9338
9339void nsGridContainerFrame::ReflowAbsoluteChildren(
9340 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
9341 nscoord aContentBSize, ReflowOutput& aDesiredSize,
9342 nsReflowStatus& aStatus) {
9343 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
9344 auto* absoluteContainer = GetAbsoluteContainingBlock();
9345 // We have prepared the absolute frames in Grid::PlaceGridItems() or in
9346 // GridReflowInput::InitializeForContinuation().
9347 if (!absoluteContainer || !absoluteContainer->HasAbsoluteFrames()) {
9348 return;
9349 }
9350 // 'gridOrigin' is the origin of the grid (the start of the first track),
9351 // with respect to the grid container's padding-box (CB).
9352 LogicalMargin pad(aGridRI.mReflowInput->ComputedLogicalPadding(wm));
9353 const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
9354 const nscoord gridContentBSize =
9355 (aGridRI.mInFragmentainer && !aGridRI.mRows.mSizes.IsEmpty())
9356 ? aGridRI.mRows.GridLineEdge(aGridRI.mRows.mSizes.Length(),
9357 GridLineSide::BeforeGridGap)
9358 : aContentBSize;
9359 const LogicalRect gridCB(wm, 0, 0, aContentArea.ISize(wm) + pad.IStartEnd(wm),
9360 gridContentBSize + pad.BStartEnd(wm));
9361 const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
9362 size_t i = 0;
9363 for (nsIFrame* child : absoluteContainer->GetChildList()) {
9364 MOZ_ASSERT(i < aGridRI.mAbsPosItems.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(i < aGridRI.mAbsPosItems.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(i < aGridRI.mAbsPosItems.
Length()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("i < aGridRI.mAbsPosItems.Length()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "i < aGridRI.mAbsPosItems.Length()"
")"); do { MOZ_CrashSequence(__null, 9364); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9365 MOZ_ASSERT(aGridRI.mAbsPosItems[i].mFrame == child)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGridRI.mAbsPosItems[i].mFrame == child)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aGridRI.mAbsPosItems[i].mFrame == child))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aGridRI.mAbsPosItems[i].mFrame == child"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9365)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mAbsPosItems[i].mFrame == child"
")"); do { MOZ_CrashSequence(__null, 9365); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9366 GridArea& area = aGridRI.mAbsPosItems[i].mArea;
9367 LogicalRect itemCB =
9368 aGridRI.ContainingBlockForAbsPos(area, gridOrigin, gridCB);
9369 // AbsoluteContainingBlock::Reflow uses physical coordinates.
9370 nsRect* cb =
9371 child->GetOrCreateDeletableProperty(GridItemContainingBlockRect());
9372 *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize);
9373 ++i;
9374 }
9375 const auto border = aGridRI.mReflowInput->ComputedPhysicalBorder();
9376 const nsPoint borderShift{border.left, border.top};
9377 const nsRect paddingRect(borderShift, gridCBPhysicalSize);
9378 // XXX: To optimize the performance, set the flags only when the CB width
9379 // or height actually changes.
9380 AbsPosReflowFlags flags{
9381 AbsPosReflowFlag::AllowFragmentation, AbsPosReflowFlag::CBWidthChanged,
9382 AbsPosReflowFlag::CBHeightChanged, AbsPosReflowFlag::IsGridContainerCB};
9383 nsReflowStatus absposStatus;
9384 absoluteContainer->Reflow(this, PresContext(), *aGridRI.mReflowInput,
9385 absposStatus, paddingRect, flags,
9386 &aDesiredSize.mOverflowAreas);
9387 aStatus.MergeCompletionStatusFrom(absposStatus);
9388}
9389
9390nscoord nsGridContainerFrame::ComputeBSizeForResolvingRowSizes(
9391 GridReflowInput& aGridRI, nscoord aComputedBSize,
9392 const Maybe<nscoord>& aContainIntrinsicBSize) const {
9393 if (aComputedBSize != NS_UNCONSTRAINEDSIZE) {
9394 // We don't need to apply the min/max constraints to the computed block-size
9395 // because ReflowInput (specifically when computing the block-size in
9396 // nsIFrame::ComputeSize()) has already clamped the block-size.
9397 return aComputedBSize;
9398 }
9399
9400 if (aContainIntrinsicBSize) {
9401 // We have an unconstrained block-size, but we also have a specified
9402 // 'contain-intrinsic-block-size'. We apply the min/max constraints to the
9403 // value, and use that for track sizing.
9404 return aGridRI.mReflowInput->ApplyMinMaxBSize(*aContainIntrinsicBSize);
9405 }
9406
9407 return NS_UNCONSTRAINEDSIZE;
9408}
9409
9410nscoord nsGridContainerFrame::ComputeIntrinsicContentBSize(
9411 const GridReflowInput& aGridRI, nscoord aComputedBSize,
9412 nscoord aBSizeForResolvingRowSizes,
9413 const Maybe<nscoord>& aContainIntrinsicBSize) const {
9414 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput
->ShouldApplyAutomaticMinimumOnBlockAxis())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aComputedBSize == NS_UNCONSTRAINEDSIZE
|| aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
" (" "Why call this method when intrinsic content block-size is not needed?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 9417
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
") (" "Why call this method when intrinsic content block-size is not needed?"
")"); do { MOZ_CrashSequence(__null, 9417); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9415 aComputedBSize == NS_UNCONSTRAINEDSIZE ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput
->ShouldApplyAutomaticMinimumOnBlockAxis())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aComputedBSize == NS_UNCONSTRAINEDSIZE
|| aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
" (" "Why call this method when intrinsic content block-size is not needed?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 9417
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
") (" "Why call this method when intrinsic content block-size is not needed?"
")"); do { MOZ_CrashSequence(__null, 9417); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9416 aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput
->ShouldApplyAutomaticMinimumOnBlockAxis())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aComputedBSize == NS_UNCONSTRAINEDSIZE
|| aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
" (" "Why call this method when intrinsic content block-size is not needed?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 9417
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
") (" "Why call this method when intrinsic content block-size is not needed?"
")"); do { MOZ_CrashSequence(__null, 9417); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9417 "Why call this method when intrinsic content block-size is not needed?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput
->ShouldApplyAutomaticMinimumOnBlockAxis())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aComputedBSize == NS_UNCONSTRAINEDSIZE
|| aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
" (" "Why call this method when intrinsic content block-size is not needed?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 9417
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedBSize == NS_UNCONSTRAINEDSIZE || aGridRI.mReflowInput->ShouldApplyAutomaticMinimumOnBlockAxis()"
") (" "Why call this method when intrinsic content block-size is not needed?"
")"); do { MOZ_CrashSequence(__null, 9417); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9418
9419 if (aComputedBSize == NS_UNCONSTRAINEDSIZE) {
9420 // When we have an unconstrained block-size, the intrinsic content
9421 // block-size would have been determined after we resolved the row sizes the
9422 // first time. Just return that value.
9423 return aBSizeForResolvingRowSizes;
9424 }
9425
9426 if (aContainIntrinsicBSize) {
9427 // We have a specified 'contain-intrinsic-block-size' which we need to
9428 // honor.
9429 return *aContainIntrinsicBSize;
9430 }
9431
9432 if (IsRowMasonry()) {
9433 // There aren't any tracks to derive a block-size from, if we're doing
9434 // masonry rather than forming rows in the block direction.
9435 return aBSizeForResolvingRowSizes;
9436 }
9437
9438 return aGridRI.mRows.TotalTrackSizeWithoutAlignment(this);
9439}
9440
9441void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
9442 ReflowOutput& aDesiredSize,
9443 const ReflowInput& aReflowInput,
9444 nsReflowStatus& aStatus) {
9445 NormalizeChildLists();
9446
9447 if (IsHiddenByContentVisibilityOfInFlowParentForLayout()) {
9448 return;
9449 }
9450
9451 MarkInReflow();
9452 DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame")aPresContext->CountReflows(("nsGridContainerFrame"), (nsIFrame
*)this);
;
9453 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aStatus.IsEmpty()"
" (" "Caller should pass a fresh reflow status!" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
MOZ_CrashSequence(__null, 9453); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9454
9455 GRID_LOG("Reflow grid container frame %p", this)do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Reflow grid container frame %p", this); }
} while (0);
;
9456
9457 if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
9458 return;
9459 }
9460
9461#ifdef DEBUG1
9462 mDidPushItemsBitMayLie = false;
9463 SanityCheckChildListsBeforeReflow();
9464#endif // DEBUG
9465
9466 for (auto& perAxisBaseline : mBaseline) {
9467 for (auto& baseline : perAxisBaseline) {
9468 baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
9469 }
9470 }
9471
9472 const nsStylePosition* stylePos = aReflowInput.mStylePosition;
9473 auto prevInFlow = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
9474 if (MOZ_LIKELY(!prevInFlow)(__builtin_expect(!!(!prevInFlow), 1))) {
9475 InitImplicitNamedAreas(stylePos);
9476 } else {
9477 MOZ_ASSERT(prevInFlow->HasAnyStateBits(kIsSubgridBits) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits
(kIsSubgridBits))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevInFlow->HasAnyStateBits
(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
" (" "continuations should have same kIsSubgridBits" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9479); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9479); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9478 HasAnyStateBits(kIsSubgridBits),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits
(kIsSubgridBits))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevInFlow->HasAnyStateBits
(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
" (" "continuations should have same kIsSubgridBits" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9479); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9479); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9479 "continuations should have same kIsSubgridBits")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits
(kIsSubgridBits))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevInFlow->HasAnyStateBits
(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
" (" "continuations should have same kIsSubgridBits" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9479); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9479); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9480 }
9481 GridReflowInput gridRI(this, aReflowInput);
9482 if (gridRI.mIter.ItemsAreAlreadyInOrder()) {
9483 AddStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
9484 } else {
9485 RemoveStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
9486 }
9487 if (gridRI.mIter.AtEnd() || aReflowInput.mStyleDisplay->IsContainLayout()) {
9488 // We have no grid items, or we're layout-contained. So, we have no
9489 // baseline, and our parent should synthesize a baseline if needed.
9490 AddStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
9491 } else {
9492 RemoveStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
9493 }
9494 const nscoord computedBSize = aReflowInput.ComputedBSize();
9495 const nscoord computedISize = aReflowInput.ComputedISize();
9496
9497 // XXX Technically incorrect: 'contain-intrinsic-block-size: none' is
9498 // treated as 0, ignoring our row sizes, when really we should use them but
9499 // *they* should be computed as if we had no children. To be fixed in bug
9500 // 1488878.
9501 const Maybe<nscoord> containIntrinsicBSize =
9502 aReflowInput.mFrame->ContainIntrinsicBSize();
9503 const WritingMode& wm = gridRI.mWM;
9504
9505 nscoord consumedBSize = 0;
9506 nscoord contentBSize = 0;
9507 if (MOZ_LIKELY(!prevInFlow)(__builtin_expect(!!(!prevInFlow), 1))) {
9508 Grid grid;
9509 if (MOZ_LIKELY(!IsSubgrid())(__builtin_expect(!!(!IsSubgrid()), 1))) {
9510 RepeatTrackSizingInput repeatSizing(aReflowInput.ComputedMinSize(),
9511 aReflowInput.ComputedSize(),
9512 aReflowInput.ComputedMaxSize());
9513 grid.PlaceGridItems(gridRI, repeatSizing);
9514 } else {
9515 auto* subgrid = GetProperty(Subgrid::Prop());
9516 MOZ_ASSERT(subgrid, "an ancestor forgot to call PlaceGridItems?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(subgrid)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(subgrid))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("subgrid" " (" "an ancestor forgot to call PlaceGridItems?"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 9516
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgrid" ") (" "an ancestor forgot to call PlaceGridItems?"
")"); do { MOZ_CrashSequence(__null, 9516); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9517 gridRI.mGridItems = subgrid->mGridItems.Clone();
9518 gridRI.mAbsPosItems = subgrid->mAbsPosItems.Clone();
9519 grid.mGridColEnd = subgrid->mGridColEnd;
9520 grid.mGridRowEnd = subgrid->mGridRowEnd;
9521 }
9522
9523 // Resolve the column sizes with the grid container's inline size.
9524 // 12.1.1: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9525 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid, computedISize,
9526 SizingConstraint::NoConstraint);
9527
9528 nscoord bSizeForResolvingRowSizes = ComputeBSizeForResolvingRowSizes(
9529 gridRI, computedBSize, containIntrinsicBSize);
9530
9531 // Resolve the row sizes with the determined bSizeForResolvingRowSizes.
9532 // 12.1.2: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9533 //
9534 // If bSizeForResolvingRowSizes is unconstrained, that's fine. It forces
9535 // percent-valued row sizes to be treated as 'auto', yielding an intrinsic
9536 // content block-size needed later to *actually* resolve percent-valued row
9537 // gaps and row sizes.
9538 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid,
9539 bSizeForResolvingRowSizes,
9540 SizingConstraint::NoConstraint);
9541
9542 // Invalidate the column sizes before re-resolving them.
9543 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Inline);
9544
9545 // Re-resolve the column sizes.
9546 // 12.1.3: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9547 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid, computedISize,
9548 SizingConstraint::NoConstraint);
9549
9550 // If our bSizeForResolvingRowSizes is still indefinite, replace it with
9551 // the sum of the row sizes we just resolved, then re-resolve the row
9552 // sizes against that value. We skip this for masonry, which doesn't need
9553 // two-pass row sizes resolution.
9554 if (bSizeForResolvingRowSizes == NS_UNCONSTRAINEDSIZE && !IsRowMasonry()) {
9555 bSizeForResolvingRowSizes =
9556 std::max(gridRI.mRows.TotalTrackSizeWithoutAlignment(this),
9557 gridRI.mReflowInput->ComputedMinBSize());
9558
9559 NS_ASSERTION(bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE,do { if (!(bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE)
) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The block-size for re-resolving the row sizes should be "
"definite in non-masonry layout!", "bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9561)
; MOZ_PretendNoReturn(); } } while (0)
9560 "The block-size for re-resolving the row sizes should be "do { if (!(bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE)
) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The block-size for re-resolving the row sizes should be "
"definite in non-masonry layout!", "bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9561)
; MOZ_PretendNoReturn(); } } while (0)
9561 "definite in non-masonry layout!")do { if (!(bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE)
) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The block-size for re-resolving the row sizes should be "
"definite in non-masonry layout!", "bSizeForResolvingRowSizes != NS_UNCONSTRAINEDSIZE"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9561)
; MOZ_PretendNoReturn(); } } while (0)
;
9562
9563 // Invalidate the row sizes before re-resolving them.
9564 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Block);
9565
9566 // Re-resolve the row sizes.
9567 // 12.1.4: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9568 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid,
9569 bSizeForResolvingRowSizes,
9570 SizingConstraint::NoConstraint);
9571 }
9572
9573 if (computedBSize == NS_UNCONSTRAINEDSIZE ||
9574 aReflowInput.ShouldApplyAutomaticMinimumOnBlockAxis()) {
9575 // We either have an unconstrained block-size, or we have a definite
9576 // block-size derived from the inline-size (transferred via aspect-ratio)
9577 // and need to apply the automatic content-based minimum sizes on the
9578 // block-axis. In both case, we need to compute the intrinsic
9579 // content block-size.
9580 contentBSize = ComputeIntrinsicContentBSize(gridRI, computedBSize,
9581 bSizeForResolvingRowSizes,
9582 containIntrinsicBSize);
9583 }
9584 } else {
9585 consumedBSize = CalcAndCacheConsumedBSize();
9586 gridRI.InitializeForContinuation(this, consumedBSize);
9587 if (containIntrinsicBSize) {
9588 contentBSize = *containIntrinsicBSize;
9589 } else {
9590 const uint32_t numRows = gridRI.mRows.mSizes.Length();
9591 contentBSize =
9592 gridRI.mRows.GridLineEdge(numRows, GridLineSide::AfterGridGap);
9593 }
9594 }
9595 if (computedBSize == NS_UNCONSTRAINEDSIZE) {
9596 contentBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
9597 } else if (aReflowInput.ShouldApplyAutomaticMinimumOnBlockAxis()) {
9598 contentBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
9599 contentBSize = std::max(contentBSize, computedBSize);
9600 } else {
9601 contentBSize = computedBSize;
9602 }
9603 if (contentBSize != NS_UNCONSTRAINEDSIZE) {
9604 contentBSize = std::max(contentBSize - consumedBSize, 0);
9605 }
9606 auto& bp = gridRI.mBorderPadding;
9607 LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm), computedISize,
9608 contentBSize);
9609
9610 if (!prevInFlow) {
9611 const auto& rowSizes = gridRI.mRows.mSizes;
9612 if (!IsRowSubgrid()) {
9613 if (!gridRI.mRows.mIsMasonry) {
9614 // Apply 'align-content' to the grid.
9615 auto alignment = stylePos->mAlignContent;
9616 gridRI.mRows.AlignJustifyContent(stylePos, alignment, wm, contentBSize,
9617 false);
9618 }
9619 } else {
9620 if (computedBSize == NS_UNCONSTRAINEDSIZE) {
9621 contentBSize = gridRI.mRows.GridLineEdge(rowSizes.Length(),
9622 GridLineSide::BeforeGridGap);
9623 contentArea.BSize(wm) = std::max(contentBSize, nscoord(0));
9624 }
9625 }
9626 // Save the final row sizes for use by subgrids, if needed.
9627 if (HasSubgridItems() || IsSubgrid()) {
9628 StoreUsedTrackSizes(LogicalAxis::Block, rowSizes);
9629 }
9630 }
9631
9632 nsSize containerSize = contentArea.Size(wm).GetPhysicalSize(wm);
9633 bool repositionChildren = false;
9634 if (containerSize.width == NS_UNCONSTRAINEDSIZE && wm.IsVerticalRL()) {
9635 // Note that writing-mode:vertical-rl is the only case where the block
9636 // logical direction progresses in a negative physical direction, and
9637 // therefore block-dir coordinate conversion depends on knowing the width
9638 // of the coordinate space in order to translate between the logical and
9639 // physical origins.
9640 //
9641 // A masonry axis size may be unconstrained, otherwise in a regular grid
9642 // our intrinsic size is always known by now. We'll re-position
9643 // the children below once our size is known.
9644 repositionChildren = true;
9645 containerSize.width = 0;
9646 }
9647 containerSize.width += bp.LeftRight(wm);
9648 containerSize.height += bp.TopBottom(wm);
9649
9650 contentBSize =
9651 ReflowChildren(gridRI, contentArea, containerSize, aDesiredSize, aStatus);
9652 if (Style()->GetPseudoType() == PseudoStyleType::MozScrolledContent) {
9653 // Per spec, the grid area is included in a grid container's scrollable
9654 // overflow region [1], as well as the padding on the end-edge sides that
9655 // would satisfy the requirements of 'place-content: end' alignment [2].
9656 //
9657 // Note that we include the padding from all sides of the grid area, not
9658 // just the end sides; this is fine because the grid area is relative to our
9659 // content-box origin. The inflated bounds won't go beyond our padding-box
9660 // edges on the start sides.
9661 //
9662 // The margin areas of grid item boxes are also included in the scrollable
9663 // overflow region [2].
9664 //
9665 // [1] https://drafts.csswg.org/css-grid-2/#overflow
9666 // [2] https://drafts.csswg.org/css-overflow-3/#scrollable
9667
9668 // Synthesize a grid area covering all columns and rows, and compute its
9669 // rect relative to our border-box.
9670 //
9671 // Note: the grid columns and rows exist only if there is an explicit grid;
9672 // or when an implicit grid is needed to place any grid items. See
9673 // nsGridContainerFrame::Grid::PlaceGridItems().
9674 const auto numCols = static_cast<int32_t>(gridRI.mCols.mSizes.Length());
9675 const auto numRows = static_cast<int32_t>(gridRI.mRows.mSizes.Length());
9676 if (numCols > 0 && numRows > 0) {
9677 const GridArea gridArea(LineRange(0, numCols), LineRange(0, numRows));
9678 const LogicalRect gridAreaRect =
9679 gridRI.ContainingBlockFor(gridArea) +
9680 LogicalPoint(wm, bp.IStart(wm), bp.BStart(wm));
9681
9682 MOZ_ASSERT(bp == aReflowInput.ComputedLogicalPadding(wm),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bp == aReflowInput.ComputedLogicalPadding(wm))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(bp == aReflowInput.ComputedLogicalPadding(wm)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("bp == aReflowInput.ComputedLogicalPadding(wm)"
" (" "A scrolled inner frame shouldn't have any border!" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9683)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "bp == aReflowInput.ComputedLogicalPadding(wm)"
") (" "A scrolled inner frame shouldn't have any border!" ")"
); do { MOZ_CrashSequence(__null, 9683); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9683 "A scrolled inner frame shouldn't have any border!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bp == aReflowInput.ComputedLogicalPadding(wm))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(bp == aReflowInput.ComputedLogicalPadding(wm)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("bp == aReflowInput.ComputedLogicalPadding(wm)"
" (" "A scrolled inner frame shouldn't have any border!" ")"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9683)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "bp == aReflowInput.ComputedLogicalPadding(wm)"
") (" "A scrolled inner frame shouldn't have any border!" ")"
); do { MOZ_CrashSequence(__null, 9683); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9684 const LogicalMargin& padding = bp;
9685 nsRect physicalGridAreaRectWithPadding =
9686 gridAreaRect.GetPhysicalRect(wm, containerSize);
9687 physicalGridAreaRectWithPadding.Inflate(padding.GetPhysicalMargin(wm));
9688 aDesiredSize.mOverflowAreas.UnionAllWith(physicalGridAreaRectWithPadding);
9689 }
9690
9691 nsRect gridItemMarginBoxBounds;
9692 for (const auto& item : gridRI.mGridItems) {
9693 gridItemMarginBoxBounds =
9694 gridItemMarginBoxBounds.Union(item.mFrame->GetMarginRect());
9695 }
9696 aDesiredSize.mOverflowAreas.UnionAllWith(gridItemMarginBoxBounds);
9697 }
9698 ReflowAbsoluteChildren(gridRI, contentArea, contentBSize, aDesiredSize,
9699 aStatus);
9700 contentBSize = std::max(contentBSize - consumedBSize, 0);
9701
9702 // Skip our block-end border if we're INCOMPLETE.
9703 if (!aStatus.IsComplete() && !gridRI.mSkipSides.BEnd() &&
9704 StyleBorder()->mBoxDecorationBreak != StyleBoxDecorationBreak::Clone) {
9705 bp.BEnd(wm) = nscoord(0);
9706 }
9707
9708 LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
9709 contentBSize + bp.BStartEnd(wm));
9710 aDesiredSize.SetSize(wm, desiredSize);
9711 nsRect frameRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
9712 aDesiredSize.mOverflowAreas.UnionAllWith(frameRect);
9713
9714 if (repositionChildren) {
9715 nsPoint physicalDelta(aDesiredSize.Width() - bp.LeftRight(wm), 0);
9716 for (const auto& item : gridRI.mGridItems) {
9717 auto* child = item.mFrame;
9718 child->MovePositionBy(physicalDelta);
9719 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
9720 }
9721 }
9722
9723 // TODO: fix align-tracks alignment in fragments
9724 if ((IsRowMasonry() && !prevInFlow) || IsColMasonry()) {
9725 gridRI.AlignJustifyTracksInMasonryAxis(contentArea.Size(wm),
9726 aDesiredSize.PhysicalSize());
9727 }
9728
9729 // Convert INCOMPLETE -> OVERFLOW_INCOMPLETE and zero bsize if we're an OC.
9730 if (HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER)) {
9731 if (!aStatus.IsComplete()) {
9732 aStatus.SetOverflowIncomplete();
9733 aStatus.SetNextInFlowNeedsReflow();
9734 }
9735 contentBSize = 0;
9736 desiredSize.BSize(wm) = contentBSize + bp.BStartEnd(wm);
9737 aDesiredSize.SetSize(wm, desiredSize);
9738 }
9739
9740 if (!gridRI.mInFragmentainer) {
9741 MOZ_ASSERT(gridRI.mIter.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gridRI.mIter.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gridRI.mIter.IsValid()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("gridRI.mIter.IsValid()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 9741)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRI.mIter.IsValid()"
")"); do { MOZ_CrashSequence(__null, 9741); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9742 auto sz = frameRect.Size();
9743 CalculateBaselines(BaselineSet::eBoth, &gridRI.mIter, &gridRI.mGridItems,
9744 gridRI.mCols, 0, gridRI.mCols.mSizes.Length(), wm, sz,
9745 bp.IStart(wm), bp.IEnd(wm), desiredSize.ISize(wm));
9746 CalculateBaselines(BaselineSet::eBoth, &gridRI.mIter, &gridRI.mGridItems,
9747 gridRI.mRows, 0, gridRI.mRows.mSizes.Length(), wm, sz,
9748 bp.BStart(wm), bp.BEnd(wm), desiredSize.BSize(wm));
9749 } else {
9750 // Only compute 'first baseline' if this fragment contains the first track.
9751 // XXXmats maybe remove this condition? bug 1306499
9752 BaselineSet baselines = BaselineSet::eNone;
9753 if (gridRI.mStartRow == 0 &&
9754 gridRI.mStartRow != gridRI.mNextFragmentStartRow) {
9755 baselines = BaselineSet::eFirst;
9756 }
9757 // Only compute 'last baseline' if this fragment contains the last track.
9758 // XXXmats maybe remove this condition? bug 1306499
9759 uint32_t len = gridRI.mRows.mSizes.Length();
9760 if (gridRI.mStartRow != len && gridRI.mNextFragmentStartRow == len) {
9761 baselines = BaselineSet(baselines | BaselineSet::eLast);
9762 }
9763 Maybe<CSSOrderAwareFrameIterator> iter;
9764 Maybe<nsTArray<GridItemInfo>> gridItems;
9765 if (baselines != BaselineSet::eNone) {
9766 // We need to create a new iterator and GridItemInfo array because we
9767 // might have pushed some children at this point.
9768 // Even if gridRI.mIter is invalid, we can reuse its
9769 // state about order to optimize initialization of the new iterator.
9770 // An ordered child list can't become unordered by pushing frames.
9771 // An unordered list can become ordered in a number of cases, but we
9772 // ignore that here and guess that the child list is still unordered.
9773 // XXX this is O(n^2) in the number of items in this fragment: bug 1306705
9774 using Filter = CSSOrderAwareFrameIterator::ChildFilter;
9775 using Order = CSSOrderAwareFrameIterator::OrderState;
9776 bool ordered = gridRI.mIter.ItemsAreAlreadyInOrder();
9777 auto orderState = ordered ? Order::Ordered : Order::Unordered;
9778 iter.emplace(this, FrameChildListID::Principal, Filter::SkipPlaceholders,
9779 orderState);
9780 gridItems.emplace();
9781 for (; !iter->AtEnd(); iter->Next()) {
9782 auto child = **iter;
9783 for (const auto& info : gridRI.mGridItems) {
9784 if (info.mFrame == child) {
9785 gridItems->AppendElement(info);
9786 }
9787 }
9788 }
9789 }
9790 auto sz = frameRect.Size();
9791 CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
9792 gridRI.mCols, 0, gridRI.mCols.mSizes.Length(), wm, sz,
9793 bp.IStart(wm), bp.IEnd(wm), desiredSize.ISize(wm));
9794 CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
9795 gridRI.mRows, gridRI.mStartRow,
9796 gridRI.mNextFragmentStartRow, wm, sz, bp.BStart(wm),
9797 bp.BEnd(wm), desiredSize.BSize(wm));
9798 }
9799
9800 if (HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO)) {
9801 // This state bit will never be cleared, since reflow can be called
9802 // multiple times in fragmented grids, and it's challenging to scope
9803 // the bit to only that sequence of calls. This is relatively harmless
9804 // since this bit is only set by accessing a ChromeOnly property, and
9805 // therefore can't unduly slow down normal web browsing.
9806
9807 // Clear our GridFragmentInfo property, which might be holding a stale
9808 // dom::Grid object built from previously-computed info. This will
9809 // ensure that the next call to GetGridFragments will create a new one.
9810 if (mozilla::dom::Grid* grid = TakeProperty(GridFragmentInfo())) {
9811 grid->ForgetFrame();
9812 }
9813
9814 // Now that we know column and row sizes and positions, set
9815 // the ComputedGridTrackInfo and related properties
9816
9817 const auto* subgrid = GetProperty(Subgrid::Prop());
9818 const auto* subgridColRange =
9819 subgrid && IsColSubgrid() ? &subgrid->SubgridCols() : nullptr;
9820
9821 LineNameMap colLineNameMap(gridRI.mGridStyle, GetImplicitNamedAreas(),
9822 gridRI.mColFunctions, nullptr, subgridColRange);
9823 uint32_t colTrackCount = gridRI.mCols.mSizes.Length();
9824 nsTArray<nscoord> colTrackPositions(colTrackCount);
9825 nsTArray<nscoord> colTrackSizes(colTrackCount);
9826 nsTArray<uint32_t> colTrackStates(colTrackCount);
9827 nsTArray<bool> colRemovedRepeatTracks(
9828 gridRI.mColFunctions.mRemovedRepeatTracks.Clone());
9829 uint32_t col = 0;
9830 for (const TrackSize& sz : gridRI.mCols.mSizes) {
9831 colTrackPositions.AppendElement(sz.mPosition);
9832 colTrackSizes.AppendElement(sz.mBase);
9833 bool isRepeat = ((col >= gridRI.mColFunctions.mRepeatAutoStart) &&
9834 (col < gridRI.mColFunctions.mRepeatAutoEnd));
9835 colTrackStates.AppendElement(
9836 isRepeat ? (uint32_t)mozilla::dom::GridTrackState::Repeat
9837 : (uint32_t)mozilla::dom::GridTrackState::Static);
9838
9839 col++;
9840 }
9841 // Get the number of explicit tracks first. The order of argument evaluation
9842 // is implementation-defined. We should be OK here because colTrackSizes is
9843 // taken by rvalue, but computing the size first prevents any changes in the
9844 // argument types of the constructor from breaking this.
9845 const uint32_t numColExplicitTracks =
9846 IsColSubgrid() ? colTrackSizes.Length()
9847 : gridRI.mColFunctions.NumExplicitTracks();
9848 ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
9849 gridRI.mColFunctions.mExplicitGridOffset, numColExplicitTracks, 0, col,
9850 std::move(colTrackPositions), std::move(colTrackSizes),
9851 std::move(colTrackStates), std::move(colRemovedRepeatTracks),
9852 gridRI.mColFunctions.mRepeatAutoStart,
9853 colLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
9854 IsColSubgrid(), IsColMasonry());
9855 SetProperty(GridColTrackInfo(), colInfo);
9856
9857 const auto* subgridRowRange =
9858 subgrid && IsRowSubgrid() ? &subgrid->SubgridRows() : nullptr;
9859 LineNameMap rowLineNameMap(gridRI.mGridStyle, GetImplicitNamedAreas(),
9860 gridRI.mRowFunctions, nullptr, subgridRowRange);
9861 uint32_t rowTrackCount = gridRI.mRows.mSizes.Length();
9862 nsTArray<nscoord> rowTrackPositions(rowTrackCount);
9863 nsTArray<nscoord> rowTrackSizes(rowTrackCount);
9864 nsTArray<uint32_t> rowTrackStates(rowTrackCount);
9865 nsTArray<bool> rowRemovedRepeatTracks(
9866 gridRI.mRowFunctions.mRemovedRepeatTracks.Clone());
9867 uint32_t row = 0;
9868 for (const TrackSize& sz : gridRI.mRows.mSizes) {
9869 rowTrackPositions.AppendElement(sz.mPosition);
9870 rowTrackSizes.AppendElement(sz.mBase);
9871 bool isRepeat = ((row >= gridRI.mRowFunctions.mRepeatAutoStart) &&
9872 (row < gridRI.mRowFunctions.mRepeatAutoEnd));
9873 rowTrackStates.AppendElement(
9874 isRepeat ? (uint32_t)mozilla::dom::GridTrackState::Repeat
9875 : (uint32_t)mozilla::dom::GridTrackState::Static);
9876
9877 row++;
9878 }
9879 // Get the number of explicit tracks first. The order of argument evaluation
9880 // is implementation-defined. We should be OK here because colTrackSizes is
9881 // taken by rvalue, but computing the size first prevents any changes in the
9882 // argument types of the constructor from breaking this.
9883 const uint32_t numRowExplicitTracks =
9884 IsRowSubgrid() ? rowTrackSizes.Length()
9885 : gridRI.mRowFunctions.NumExplicitTracks();
9886 // Row info has to accommodate fragmentation of the grid, which may happen
9887 // in later calls to Reflow. For now, presume that no more fragmentation
9888 // will occur.
9889 ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
9890 gridRI.mRowFunctions.mExplicitGridOffset, numRowExplicitTracks,
9891 gridRI.mStartRow, row, std::move(rowTrackPositions),
9892 std::move(rowTrackSizes), std::move(rowTrackStates),
9893 std::move(rowRemovedRepeatTracks),
9894 gridRI.mRowFunctions.mRepeatAutoStart,
9895 rowLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
9896 IsRowSubgrid(), IsRowMasonry());
9897 SetProperty(GridRowTrackInfo(), rowInfo);
9898
9899 if (prevInFlow) {
9900 // This frame is fragmenting rows from a previous frame, so patch up
9901 // the prior GridRowTrackInfo with a new end row.
9902
9903 // FIXME: This can be streamlined and/or removed when bug 1151204 lands.
9904
9905 ComputedGridTrackInfo* priorRowInfo =
9906 prevInFlow->GetProperty(GridRowTrackInfo());
9907
9908 // Adjust track positions based on the first track in this fragment.
9909 if (priorRowInfo->mPositions.Length() >
9910 priorRowInfo->mStartFragmentTrack) {
9911 nscoord delta =
9912 priorRowInfo->mPositions[priorRowInfo->mStartFragmentTrack];
9913 for (nscoord& pos : priorRowInfo->mPositions) {
9914 pos -= delta;
9915 }
9916 }
9917
9918 ComputedGridTrackInfo* revisedPriorRowInfo = new ComputedGridTrackInfo(
9919 priorRowInfo->mNumLeadingImplicitTracks,
9920 priorRowInfo->mNumExplicitTracks, priorRowInfo->mStartFragmentTrack,
9921 gridRI.mStartRow, std::move(priorRowInfo->mPositions),
9922 std::move(priorRowInfo->mSizes), std::move(priorRowInfo->mStates),
9923 std::move(priorRowInfo->mRemovedRepeatTracks),
9924 priorRowInfo->mRepeatFirstTrack,
9925 std::move(priorRowInfo->mResolvedLineNames), priorRowInfo->mIsSubgrid,
9926 priorRowInfo->mIsMasonry);
9927 prevInFlow->SetProperty(GridRowTrackInfo(), revisedPriorRowInfo);
9928 }
9929
9930 // Generate the line info properties. We need to provide the number of
9931 // repeat tracks produced in the reflow. Only explicit names are assigned
9932 // to lines here; the mozilla::dom::GridLines class will later extract
9933 // implicit names from grid areas and assign them to the appropriate lines.
9934
9935 auto& colFunctions = gridRI.mColFunctions;
9936
9937 // Generate column lines first.
9938 uint32_t capacity = gridRI.mCols.mSizes.Length();
9939 nsTArray<nsTArray<RefPtr<nsAtom>>> columnLineNames(capacity);
9940 for (col = 0; col <= gridRI.mCols.mSizes.Length(); col++) {
9941 // Offset col by the explicit grid offset, to get the original names.
9942 nsTArray<RefPtr<nsAtom>> explicitNames =
9943 colLineNameMap.GetExplicitLineNamesAtIndex(
9944 col - colFunctions.mExplicitGridOffset);
9945
9946 columnLineNames.EmplaceBack(std::move(explicitNames));
9947 }
9948 // Get the explicit names that follow a repeat auto declaration.
9949 nsTArray<RefPtr<nsAtom>> colNamesFollowingRepeat;
9950 nsTArray<RefPtr<nsAtom>> colBeforeRepeatAuto;
9951 nsTArray<RefPtr<nsAtom>> colAfterRepeatAuto;
9952 // Note: the following is only used for a non-subgridded axis.
9953 if (colLineNameMap.HasRepeatAuto()) {
9954 MOZ_ASSERT(!colFunctions.mTemplate.IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!colFunctions.mTemplate.IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!colFunctions.mTemplate.IsSubgrid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!colFunctions.mTemplate.IsSubgrid()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!colFunctions.mTemplate.IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9954); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9955 // The line name list after the repeatAutoIndex holds the line names
9956 // for the first explicit line after the repeat auto declaration.
9957 uint32_t repeatAutoEnd = colLineNameMap.RepeatAutoStart() + 1;
9958 for (auto* list : colLineNameMap.ExpandedLineNames()[repeatAutoEnd]) {
9959 for (auto& name : list->AsSpan()) {
9960 colNamesFollowingRepeat.AppendElement(name.AsAtom());
9961 }
9962 }
9963 auto names = colLineNameMap.TrackAutoRepeatLineNames();
9964 for (auto& name : names[0].AsSpan()) {
9965 colBeforeRepeatAuto.AppendElement(name.AsAtom());
9966 }
9967 for (auto& name : names[1].AsSpan()) {
9968 colAfterRepeatAuto.AppendElement(name.AsAtom());
9969 }
9970 }
9971
9972 ComputedGridLineInfo* columnLineInfo = new ComputedGridLineInfo{
9973 std::move(columnLineNames), std::move(colBeforeRepeatAuto),
9974 std::move(colAfterRepeatAuto), std::move(colNamesFollowingRepeat)};
9975 SetProperty(GridColumnLineInfo(), columnLineInfo);
9976
9977 // Generate row lines next.
9978 auto& rowFunctions = gridRI.mRowFunctions;
9979 capacity = gridRI.mRows.mSizes.Length();
9980 nsTArray<nsTArray<RefPtr<nsAtom>>> rowLineNames(capacity);
9981 for (row = 0; row <= gridRI.mRows.mSizes.Length(); row++) {
9982 // Offset row by the explicit grid offset, to get the original names.
9983 nsTArray<RefPtr<nsAtom>> explicitNames =
9984 rowLineNameMap.GetExplicitLineNamesAtIndex(
9985 row - rowFunctions.mExplicitGridOffset);
9986 rowLineNames.EmplaceBack(std::move(explicitNames));
9987 }
9988 // Get the explicit names that follow a repeat auto declaration.
9989 nsTArray<RefPtr<nsAtom>> rowNamesFollowingRepeat;
9990 nsTArray<RefPtr<nsAtom>> rowBeforeRepeatAuto;
9991 nsTArray<RefPtr<nsAtom>> rowAfterRepeatAuto;
9992 // Note: the following is only used for a non-subgridded axis.
9993 if (rowLineNameMap.HasRepeatAuto()) {
9994 MOZ_ASSERT(!rowFunctions.mTemplate.IsSubgrid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!rowFunctions.mTemplate.IsSubgrid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!rowFunctions.mTemplate.IsSubgrid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!rowFunctions.mTemplate.IsSubgrid()", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 9994); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rowFunctions.mTemplate.IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9994); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9995 // The line name list after the repeatAutoIndex holds the line names
9996 // for the first explicit line after the repeat auto declaration.
9997 uint32_t repeatAutoEnd = rowLineNameMap.RepeatAutoStart() + 1;
9998 for (auto* list : rowLineNameMap.ExpandedLineNames()[repeatAutoEnd]) {
9999 for (auto& name : list->AsSpan()) {
10000 rowNamesFollowingRepeat.AppendElement(name.AsAtom());
10001 }
10002 }
10003 auto names = rowLineNameMap.TrackAutoRepeatLineNames();
10004 for (auto& name : names[0].AsSpan()) {
10005 rowBeforeRepeatAuto.AppendElement(name.AsAtom());
10006 }
10007 for (auto& name : names[1].AsSpan()) {
10008 rowAfterRepeatAuto.AppendElement(name.AsAtom());
10009 }
10010 }
10011
10012 ComputedGridLineInfo* rowLineInfo = new ComputedGridLineInfo{
10013 std::move(rowLineNames), std::move(rowBeforeRepeatAuto),
10014 std::move(rowAfterRepeatAuto), std::move(rowNamesFollowingRepeat)};
10015 SetProperty(GridRowLineInfo(), rowLineInfo);
10016
10017 // Generate area info for explicit areas. Implicit areas are handled
10018 // elsewhere.
10019 if (!gridRI.mGridStyle->mGridTemplateAreas.IsNone()) {
10020 auto* areas = new StyleOwnedSlice<NamedArea>(
10021 gridRI.mGridStyle->mGridTemplateAreas.AsAreas()->areas);
10022 SetProperty(ExplicitNamedAreasProperty(), areas);
10023 } else {
10024 RemoveProperty(ExplicitNamedAreasProperty());
10025 }
10026 }
10027
10028 if (!prevInFlow) {
10029 if (!aStatus.IsFullyComplete()) {
10030 SharedGridData* sharedGridData =
10031 GetOrCreateDeletableProperty(SharedGridData::Prop());
10032 sharedGridData->mCols.mSizes = std::move(gridRI.mCols.mSizes);
10033 sharedGridData->mCols.mContentBoxSize = gridRI.mCols.mContentBoxSize;
10034 sharedGridData->mCols.mBaselineSubtreeAlign =
10035 gridRI.mCols.mBaselineSubtreeAlign;
10036 sharedGridData->mCols.mIsMasonry = gridRI.mCols.mIsMasonry;
10037 sharedGridData->mRows.mSizes = std::move(gridRI.mRows.mSizes);
10038 // Save the original row grid sizes and gaps so we can restore them later
10039 // in GridReflowInput::Initialize for the continuations.
10040 auto& origRowData = sharedGridData->mOriginalRowData;
10041 origRowData.ClearAndRetainStorage();
10042 origRowData.SetCapacity(sharedGridData->mRows.mSizes.Length());
10043 nscoord prevTrackEnd = 0;
10044 for (auto& sz : sharedGridData->mRows.mSizes) {
10045 SharedGridData::RowData data = {sz.mBase, sz.mPosition - prevTrackEnd};
10046 origRowData.AppendElement(data);
10047 prevTrackEnd = sz.mPosition + sz.mBase;
10048 }
10049 sharedGridData->mRows.mContentBoxSize = gridRI.mRows.mContentBoxSize;
10050 sharedGridData->mRows.mBaselineSubtreeAlign =
10051 gridRI.mRows.mBaselineSubtreeAlign;
10052 sharedGridData->mRows.mIsMasonry = gridRI.mRows.mIsMasonry;
10053 sharedGridData->mGridItems = std::move(gridRI.mGridItems);
10054 sharedGridData->mAbsPosItems = std::move(gridRI.mAbsPosItems);
10055
10056 sharedGridData->mGenerateComputedGridInfo =
10057 HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO);
10058 } else if (!GetNextInFlow()) {
10059 RemoveProperty(SharedGridData::Prop());
10060 }
10061 }
10062
10063 FinishAndStoreOverflow(&aDesiredSize);
10064}
10065
10066void nsGridContainerFrame::UpdateSubgridFrameState() {
10067 nsFrameState oldBits = GetStateBits() & kIsSubgridBits;
10068 nsFrameState newBits = ComputeSelfSubgridMasonryBits() & kIsSubgridBits;
10069 if (newBits != oldBits) {
10070 RemoveStateBits(kIsSubgridBits);
10071 if (!newBits) {
10072 RemoveProperty(Subgrid::Prop());
10073 } else {
10074 AddStateBits(newBits);
10075 }
10076 }
10077}
10078
10079nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
10080 nsFrameState bits = NS_FRAME_STATE_NONE;
10081 const auto* pos = StylePosition();
10082
10083 if (StyleDisplay()->DisplayInside() == StyleDisplayInside::GridLanes) {
10084 // If rows are defined and columns are none → row tracks (with inline axis
10085 // being the stacking axis, i.e. there are no columns)
10086 //
10087 // Otherwise (columns defined, both defined, or neither defined) → column
10088 // tracks (with block axis being the stacking axis, i.e. there are no rows)
10089 if (!pos->mGridTemplateRows.IsNone() &&
10090 pos->mGridTemplateColumns.IsNone()) {
10091 bits |= NS_STATE_GRID_IS_COL_MASONRY;
10092 } else {
10093 bits |= NS_STATE_GRID_IS_ROW_MASONRY;
10094 }
10095 }
10096
10097 // NOTE: The rest of this function is only relevant if we're a subgrid;
10098 // hence, we return early as soon as we rule out that possibility.
10099
10100 // 'contain:layout/paint' makes us an "independent formatting context",
10101 // which prevents us from being a subgrid in this case (but not always).
10102 // We will also need to check our containing scroll frame for this property.
10103 // https://drafts.csswg.org/css-display-3/#establish-an-independent-formatting-context
10104 if (ShouldInhibitSubgridDueToIFC(this)) {
10105 return bits;
10106 }
10107
10108 // Skip over our scroll frame and such if we have it, to find our "parent
10109 // grid", if we have one.
10110
10111 // After this loop, 'parent' will represent the parent of the outermost frame
10112 // that shares our content node. (Normally this is just our parent frame, but
10113 // if we're e.g. a scrolled frame, then this will be the parent of our
10114 // wrapper-scrollable-frame.) If 'parent' turns out to be a grid container,
10115 // then it's our "parent grid", and we could potentially be a subgrid of it.
10116 auto* parent = GetParent();
10117 while (parent && parent->GetContent() == GetContent()) {
10118 // If we find our containing frame (e.g. our scroll frame) can't be a
10119 // subgrid, then we can't be a subgrid, for the same reasons as above. This
10120 // can happen when this frame is itself a grid item with "overflow:scroll"
10121 // or similar.
10122 if (ShouldInhibitSubgridDueToIFC(parent)) {
10123 return bits;
10124 }
10125 parent = parent->GetParent();
10126 }
10127 const nsGridContainerFrame* parentGrid = do_QueryFrame(parent);
10128 if (parentGrid) {
10129 bool isOrthogonal =
10130 GetWritingMode().IsOrthogonalTo(parent->GetWritingMode());
10131 bool isColSubgrid = pos->mGridTemplateColumns.IsSubgrid();
10132 // Subgridding a parent masonry axis makes us use masonry layout too,
10133 // unless our other axis is a masonry axis.
10134 if (isColSubgrid &&
10135 parent->HasAnyStateBits(isOrthogonal ? NS_STATE_GRID_IS_ROW_MASONRY
10136 : NS_STATE_GRID_IS_COL_MASONRY)) {
10137 isColSubgrid = false;
10138 if (!HasAnyStateBits(NS_STATE_GRID_IS_ROW_MASONRY)) {
10139 bits |= NS_STATE_GRID_IS_COL_MASONRY;
10140 }
10141 }
10142 if (isColSubgrid) {
10143 bits |= NS_STATE_GRID_IS_COL_SUBGRID;
10144 }
10145
10146 bool isRowSubgrid = pos->mGridTemplateRows.IsSubgrid();
10147 if (isRowSubgrid &&
10148 parent->HasAnyStateBits(isOrthogonal ? NS_STATE_GRID_IS_COL_MASONRY
10149 : NS_STATE_GRID_IS_ROW_MASONRY)) {
10150 isRowSubgrid = false;
10151 if (!HasAnyStateBits(NS_STATE_GRID_IS_COL_MASONRY)) {
10152 bits |= NS_STATE_GRID_IS_ROW_MASONRY;
10153 }
10154 }
10155 if (isRowSubgrid) {
10156 bits |= NS_STATE_GRID_IS_ROW_SUBGRID;
10157 }
10158 }
10159 return bits;
10160}
10161
10162void nsGridContainerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
10163 nsIFrame* aPrevInFlow) {
10164 nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
10165
10166 if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)) {
10167 AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
10168 }
10169
10170 nsFrameState bits = NS_FRAME_STATE_NONE;
10171 if (MOZ_LIKELY(!aPrevInFlow)(__builtin_expect(!!(!aPrevInFlow), 1))) {
10172 bits = ComputeSelfSubgridMasonryBits();
10173 } else {
10174 bits = aPrevInFlow->GetStateBits() &
10175 (NS_STATE_GRID_IS_ROW_MASONRY | NS_STATE_GRID_IS_COL_MASONRY |
10176 kIsSubgridBits | NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
10177 NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
10178 }
10179 AddStateBits(bits);
10180}
10181
10182void nsGridContainerFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
10183 nsContainerFrame::DidSetComputedStyle(aOldStyle);
10184
10185 if (!aOldStyle) {
10186 return; // Init() already initialized the bits.
10187 }
10188 UpdateSubgridFrameState();
10189}
10190
10191nscoord nsGridContainerFrame::ComputeIntrinsicISize(
10192 const IntrinsicSizeInput& aInput, IntrinsicISizeType aType) {
10193 GRID_LOG("Compute %s isize for grid container frame %p",do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Compute %s isize for grid container frame %p"
, aType == IntrinsicISizeType::MinISize ? "min" : "pref", this
); } } while (0);
10194 aType == IntrinsicISizeType::MinISize ? "min" : "pref", this)do { const ::mozilla::LogModule* moz_real_module = gGridContainerLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Compute %s isize for grid container frame %p"
, aType == IntrinsicISizeType::MinISize ? "min" : "pref", this
); } } while (0);
;
10195
10196 if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
10197 return *containISize;
10198 }
10199
10200 // Calculate the sum of column sizes under intrinsic sizing.
10201 // https://drafts.csswg.org/css-grid-2/#intrinsic-sizes
10202 NormalizeChildLists();
10203 GridReflowInput gridRI(this, *aInput.mContext);
10204 // Ensure we do not measure flex tracks against unconstrained bounds.
10205 gridRI.mIsGridIntrinsicSizing = true;
10206 InitImplicitNamedAreas(gridRI.mGridStyle); // XXX optimize
10207
10208 // The min/sz/max sizes are the input to the "repeat-to-fill" algorithm:
10209 // https://drafts.csswg.org/css-grid-2/#auto-repeat
10210 // They're only used for auto-repeat so we skip computing them otherwise.
10211 RepeatTrackSizingInput repeatSizing(gridRI.mWM);
10212 if (!IsColSubgrid() && gridRI.mColFunctions.mHasRepeatAuto) {
10213 repeatSizing.InitFromStyle(
10214 LogicalAxis::Inline, gridRI.mWM, gridRI.mFrame, gridRI.mFrame->Style(),
10215 gridRI.mFrame->GetAspectRatio(), aInput.mContainingBlockSize);
10216 }
10217 if ((!IsRowSubgrid() && gridRI.mRowFunctions.mHasRepeatAuto &&
10218 !(gridRI.mGridStyle->mGridAutoFlow & StyleGridAutoFlow::ROW)) ||
10219 IsColMasonry()) {
10220 // Only 'grid-auto-flow:column' can create new implicit columns, so that's
10221 // the only case where our block-size can affect the number of columns.
10222 // Masonry layout always depends on how many rows we have though.
10223 repeatSizing.InitFromStyle(
10224 LogicalAxis::Block, gridRI.mWM, gridRI.mFrame, gridRI.mFrame->Style(),
10225 gridRI.mFrame->GetAspectRatio(), aInput.mContainingBlockSize);
10226 }
10227
10228 Grid grid;
10229 if (MOZ_LIKELY(!IsSubgrid())(__builtin_expect(!!(!IsSubgrid()), 1))) {
10230 grid.PlaceGridItems(gridRI, repeatSizing); // XXX optimize
10231 } else {
10232 auto* subgrid = GetProperty(Subgrid::Prop());
10233 gridRI.mGridItems = subgrid->mGridItems.Clone();
10234 gridRI.mAbsPosItems = subgrid->mAbsPosItems.Clone();
10235 grid.mGridColEnd = subgrid->mGridColEnd;
10236 grid.mGridRowEnd = subgrid->mGridRowEnd;
10237 }
10238
10239 auto constraint = aType == IntrinsicISizeType::MinISize
10240 ? SizingConstraint::MinContent
10241 : SizingConstraint::MaxContent;
10242 if (IsColMasonry()) {
10243 ReflowOutput desiredSize(gridRI.mWM);
10244 nsSize containerSize;
10245 LogicalRect contentArea(gridRI.mWM);
10246 nsReflowStatus status;
10247 gridRI.mRows.mSizes.SetLength(grid.mGridRowEnd);
10248 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10249 NS_UNCONSTRAINEDSIZE, constraint);
10250 return MasonryLayout(gridRI, contentArea, constraint, desiredSize, status,
10251 nullptr, containerSize);
10252 }
10253
10254 if (grid.mGridColEnd == 0) {
10255 return nscoord(0);
10256 }
10257
10258 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10259 NS_UNCONSTRAINEDSIZE, constraint);
10260
10261 const nscoord contentBoxBSize =
10262 aInput.mPercentageBasisForChildren
10263 ? aInput.mPercentageBasisForChildren->BSize(gridRI.mWM)
10264 : NS_UNCONSTRAINEDSIZE;
10265
10266 if (IsRowSubgrid() && contentBoxBSize == NS_UNCONSTRAINEDSIZE) {
10267 // Our rows are the parent grid's rows, and IntrinsicISize() gave us their
10268 // size as our percentage basis. If it's indefinite, the parent hasn't
10269 // resolved them yet: we're being measured as part of its column sizing,
10270 // and resolving the rows here would recurse back into it.
10271 return gridRI.mCols.TotalTrackSizeWithoutAlignment(this);
10272 }
10273
10274 // Resolve row sizes so that when we re-resolve the column sizes, grid items
10275 // with percent-valued block-sizes (and aspect ratios) have definite row
10276 // sizes as the percentage basis. Their resolved block-size can then
10277 // transfer to the inline-axis, contributing correctly to the grid
10278 // container's intrinsic inline-size.
10279 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid, contentBoxBSize,
10280 SizingConstraint::NoConstraint);
10281
10282 // Invalidate the column sizes before re-resolving them.
10283 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Inline);
10284
10285 // Re-resolve the column sizes, using the resolved row sizes established
10286 // above. See 12.1.3 of the Grid Sizing Algorithm for more scenarios where
10287 // re-resolving the column sizes is necessary:
10288 // https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
10289 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10290 NS_UNCONSTRAINEDSIZE, constraint);
10291
10292 return gridRI.mCols.TotalTrackSizeWithoutAlignment(this);
10293}
10294
10295nscoord nsGridContainerFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
10296 IntrinsicISizeType aType) {
10297 auto* firstCont = static_cast<nsGridContainerFrame*>(FirstContinuation());
10298 if (firstCont != this) {
10299 return firstCont->IntrinsicISize(aInput, aType);
10300 }
10301 return mCachedIntrinsicSizes.GetOrSet(*this, aType, aInput, [&] {
10302 return ComputeIntrinsicISize(aInput, aType);
10303 });
10304}
10305
10306void nsGridContainerFrame::MarkIntrinsicISizesDirty() {
10307 mCachedIntrinsicSizes.Clear();
10308 for (auto& perAxisBaseline : mBaseline) {
10309 for (auto& baseline : perAxisBaseline) {
10310 baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
10311 }
10312 }
10313 nsContainerFrame::MarkIntrinsicISizesDirty();
10314}
10315
10316void nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
10317 const nsDisplayListSet& aLists) {
10318 DisplayBorderBackgroundOutline(aBuilder, aLists);
10319 if (HidesContent()) {
10320 return;
10321 }
10322
10323 if (GetPrevInFlow()) {
10324 DisplayOverflowContainers(aBuilder, aLists);
10325 }
10326
10327 // Our children are all grid-level boxes, which behave the same as
10328 // inline-blocks in painting, so their borders/backgrounds all go on
10329 // the BlockBorderBackgrounds list.
10330 typedef CSSOrderAwareFrameIterator::OrderState OrderState;
10331 OrderState order =
10332 HasAnyStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
10333 ? OrderState::Ordered
10334 : OrderState::Unordered;
10335 CSSOrderAwareFrameIterator iter(
10336 this, FrameChildListID::Principal,
10337 CSSOrderAwareFrameIterator::ChildFilter::IncludeAll, order);
10338 const auto flags = DisplayFlagsForFlexOrGridItem();
10339 for (; !iter.AtEnd(); iter.Next()) {
10340 nsIFrame* child = *iter;
10341 BuildDisplayListForChild(aBuilder, child, aLists, flags);
10342 }
10343
10344 if (GetPrevInFlow() || GetNextInFlow()) {
10345 DisplayAbsoluteFramesNotBuiltByPlaceholder(aBuilder, aLists);
10346 }
10347}
10348
10349bool nsGridContainerFrame::DrainSelfOverflowList() {
10350 return DrainAndMergeSelfOverflowList();
10351}
10352
10353void nsGridContainerFrame::AppendFrames(ChildListID aListID,
10354 nsFrameList&& aFrameList) {
10355 NoteNewChildren(aListID, aFrameList);
10356 nsContainerFrame::AppendFrames(aListID, std::move(aFrameList));
10357}
10358
10359void nsGridContainerFrame::InsertFrames(
10360 ChildListID aListID, nsIFrame* aPrevFrame,
10361 const nsLineList::iterator* aPrevFrameLine, nsFrameList&& aFrameList) {
10362 NoteNewChildren(aListID, aFrameList);
10363 nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
10364 std::move(aFrameList));
10365}
10366
10367void nsGridContainerFrame::RemoveFrame(DestroyContext& aContext,
10368 ChildListID aListID,
10369 nsIFrame* aOldFrame) {
10370 MOZ_ASSERT(aListID == FrameChildListID::Principal, "unexpected child list")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aListID == FrameChildListID::Principal)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aListID == FrameChildListID::Principal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aListID == FrameChildListID::Principal"
" (" "unexpected child list" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10370); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aListID == FrameChildListID::Principal"
") (" "unexpected child list" ")"); do { MOZ_CrashSequence(__null
, 10370); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10371
10372#ifdef DEBUG1
10373 SetDidPushItemsBitIfNeeded(aListID, aOldFrame);
10374#endif
10375
10376 nsContainerFrame::RemoveFrame(aContext, aListID, aOldFrame);
10377}
10378
10379nscoord nsGridContainerFrame::SynthesizeBaseline(
10380 const FindItemInGridOrderResult& aGridOrderItem, LogicalAxis aAxis,
10381 BaselineSharingGroup aGroup, const nsSize& aCBPhysicalSize, nscoord aCBSize,
10382 WritingMode aCBWM) {
10383 if (MOZ_UNLIKELY(!aGridOrderItem.mItem)(__builtin_expect(!!(!aGridOrderItem.mItem), 0))) {
10384 // No item in this fragment - synthesize a baseline from our border-box.
10385 return ::SynthesizeBaselineFromBorderBox(aGroup, aCBWM, aAxis, aCBSize);
10386 }
10387
10388 nsIFrame* child = aGridOrderItem.mItem->mFrame;
10389 nsGridContainerFrame* grid = do_QueryFrame(child);
10390 auto childWM = child->GetWritingMode();
10391 bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
10392 const LogicalAxis childAxis = aCBWM.ConvertAxisTo(aAxis, childWM);
10393 nscoord baseline;
10394 nscoord start;
10395 nscoord size;
10396
10397 if (aAxis == LogicalAxis::Block) {
10398 start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).B(aCBWM);
10399 size = child->BSize(aCBWM);
10400 if (grid && aGridOrderItem.mIsInEdgeTrack) {
10401 baseline = isOrthogonal ? grid->GetIBaseline(aGroup)
10402 : grid->GetBBaseline(aGroup);
10403 } else if (!isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
10404 // This assertion is mostly for documentation purposes; it must hold,
10405 // given the checks in our 'if' statements. (We know aAxis is
10406 // LogicalAxis::Block, and isOrthogonal is false, which means childAxis
10407 // must be LogicalAxis::Block). If instead we got here with a childAxis of
10408 // LogicalAxis::Inline, then our call to
10409 // Baseline::SynthesizeBaselineFromBorderBox might incorrectly think
10410 // it makes sense to use a central baseline, in an axis where that
10411 // doesn't make sense.
10412 MOZ_ASSERT(childAxis == LogicalAxis::Block, "unexpected childAxis")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(childAxis == LogicalAxis::Block)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(childAxis == LogicalAxis::Block
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"childAxis == LogicalAxis::Block" " (" "unexpected childAxis"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10412
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childAxis == LogicalAxis::Block"
") (" "unexpected childAxis" ")"); do { MOZ_CrashSequence(__null
, 10412); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10413 baseline = child
10414 ->GetNaturalBaselineBOffset(childWM, aGroup,
10415 BaselineExportContext::Other)
10416 .valueOrFrom([aGroup, child, childWM]() {
10417 return Baseline::SynthesizeBOffsetFromBorderBox(
10418 child, childWM, aGroup);
10419 });
10420 } else {
10421 baseline =
10422 ::SynthesizeBaselineFromBorderBox(aGroup, childWM, childAxis, size);
10423 }
10424 } else {
10425 start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).I(aCBWM);
10426 size = child->ISize(aCBWM);
10427 if (grid && aGridOrderItem.mIsInEdgeTrack) {
10428 baseline = isOrthogonal ? grid->GetBBaseline(aGroup)
10429 : grid->GetIBaseline(aGroup);
10430 } else if (isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
10431 baseline = child
10432 ->GetNaturalBaselineBOffset(childWM, aGroup,
10433 BaselineExportContext::Other)
10434 .valueOrFrom([aGroup, childWM, childAxis, size]() {
10435 return ::SynthesizeBaselineFromBorderBox(
10436 aGroup, childWM, childAxis, size);
10437 });
10438 } else {
10439 baseline =
10440 ::SynthesizeBaselineFromBorderBox(aGroup, childWM, childAxis, size);
10441 }
10442 }
10443 return aGroup == BaselineSharingGroup::First
10444 ? start + baseline
10445 : aCBSize - start - size + baseline;
10446}
10447
10448void nsGridContainerFrame::CalculateBaselines(
10449 BaselineSet aBaselineSet, CSSOrderAwareFrameIterator* aIter,
10450 const nsTArray<GridItemInfo>* aGridItems, const Tracks& aTracks,
10451 uint32_t aFragmentStartTrack, uint32_t aFirstExcludedTrack, WritingMode aWM,
10452 const nsSize& aCBPhysicalSize, nscoord aCBBorderPaddingStart,
10453 nscoord aCBBorderPaddingEnd, nscoord aCBSize) {
10454 const auto axis = aTracks.mAxis;
10455
10456 auto firstBaseline = aTracks.GetBaseline(0, BaselineSharingGroup::First);
10457 if (!(aBaselineSet & BaselineSet::eFirst)) {
10458 mBaseline[axis][BaselineSharingGroup::First] =
10459 ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::First, aWM,
10460 axis, aCBSize);
10461 } else if (firstBaseline.isNothing()) {
10462 FindItemInGridOrderResult gridOrderFirstItem = FindFirstItemInGridOrder(
10463 *aIter, *aGridItems,
10464 axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
10465 axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
10466 aFragmentStartTrack);
10467 mBaseline[axis][BaselineSharingGroup::First] = SynthesizeBaseline(
10468 gridOrderFirstItem, axis, BaselineSharingGroup::First, aCBPhysicalSize,
10469 aCBSize, aWM);
10470 } else {
10471 // We have a 'first baseline' group in the start track in this fragment.
10472 // Convert it from track to grid container border-box coordinates.
10473 MOZ_ASSERT(!aGridItems->IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aGridItems->IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aGridItems->IsEmpty())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aGridItems->IsEmpty()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10473
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aGridItems->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 10473); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10474 nscoord gapBeforeStartTrack =
10475 aFragmentStartTrack == 0
10476 ? aTracks.GridLineEdge(aFragmentStartTrack,
10477 GridLineSide::AfterGridGap)
10478 : nscoord(0); // no content gap at start of fragment
10479 mBaseline[axis][BaselineSharingGroup::First] =
10480 aCBBorderPaddingStart + gapBeforeStartTrack + *firstBaseline;
10481 }
10482
10483 auto lastBaseline = aTracks.GetBaseline(aTracks.mBaselines.Length() - 1,
10484 BaselineSharingGroup::Last);
10485 if (!(aBaselineSet & BaselineSet::eLast)) {
10486 mBaseline[axis][BaselineSharingGroup::Last] =
10487 ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::Last, aWM, axis,
10488 aCBSize);
10489 } else if (lastBaseline.isNothing()) {
10490 // For finding items for the 'last baseline' we need to create a reverse
10491 // iterator ('aIter' is the forward iterator from the GridReflowInput).
10492 using Iter = ReverseCSSOrderAwareFrameIterator;
10493 auto orderState = aIter->ItemsAreAlreadyInOrder()
10494 ? Iter::OrderState::Ordered
10495 : Iter::OrderState::Unordered;
10496 Iter iter(this, FrameChildListID::Principal,
10497 Iter::ChildFilter::SkipPlaceholders, orderState);
10498 iter.SetItemCount(aGridItems->Length());
10499 FindItemInGridOrderResult gridOrderLastItem = FindLastItemInGridOrder(
10500 iter, *aGridItems,
10501 axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
10502 axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
10503 aFragmentStartTrack, aFirstExcludedTrack);
10504 mBaseline[axis][BaselineSharingGroup::Last] =
10505 SynthesizeBaseline(gridOrderLastItem, axis, BaselineSharingGroup::Last,
10506 aCBPhysicalSize, aCBSize, aWM);
10507 } else {
10508 // We have a 'last baseline' group in the end track in this fragment.
10509 // Convert it from track to grid container border-box coordinates.
10510 MOZ_ASSERT(!aGridItems->IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aGridItems->IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aGridItems->IsEmpty())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aGridItems->IsEmpty()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10510
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aGridItems->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 10510); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10511 auto borderBoxStartToEndOfEndTrack =
10512 aCBBorderPaddingStart +
10513 aTracks.GridLineEdge(aFirstExcludedTrack, GridLineSide::BeforeGridGap) -
10514 aTracks.GridLineEdge(aFragmentStartTrack, GridLineSide::BeforeGridGap);
10515 mBaseline[axis][BaselineSharingGroup::Last] =
10516 (aCBSize - borderBoxStartToEndOfEndTrack) + *lastBaseline;
10517 }
10518}
10519
10520#ifdef DEBUG_FRAME_DUMP1
10521nsresult nsGridContainerFrame::GetFrameName(nsAString& aResult) const {
10522 return MakeFrameName(u"GridContainer"_ns, aResult);
10523}
10524
10525void nsGridContainerFrame::ExtraContainerFrameInfo(
10526 nsACString& aTo, bool aListOnlyDeterministic) const {
10527 if (const void* const subgrid = GetProperty(Subgrid::Prop())) {
10528 aTo += "[subgrid";
10529 ListPtr(aTo, aListOnlyDeterministic, subgrid);
10530 aTo += "]";
10531 }
10532}
10533
10534#endif
10535
10536/* static */ nsGridContainerFrame::FindItemInGridOrderResult
10537nsGridContainerFrame::FindFirstItemInGridOrder(
10538 CSSOrderAwareFrameIterator& aIter, const nsTArray<GridItemInfo>& aGridItems,
10539 LineRange GridArea::* aMajor, LineRange GridArea::* aMinor,
10540 uint32_t aFragmentStartTrack) {
10541 FindItemInGridOrderResult result = {nullptr, false};
10542 uint32_t minMajor = kTranslatedMaxLine + 1;
10543 uint32_t minMinor = kTranslatedMaxLine + 1;
10544 aIter.Reset();
10545 for (; !aIter.AtEnd(); aIter.Next()) {
10546 const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
10547 if ((item.mArea.*aMajor).mEnd <= aFragmentStartTrack) {
10548 continue; // item doesn't span any track in this fragment
10549 }
10550 uint32_t major = (item.mArea.*aMajor).mStart;
10551 uint32_t minor = (item.mArea.*aMinor).mStart;
10552 if (major < minMajor || (major == minMajor && minor < minMinor)) {
10553 minMajor = major;
10554 minMinor = minor;
10555 result.mItem = &item;
10556 result.mIsInEdgeTrack = major == 0U;
10557 }
10558 }
10559 return result;
10560}
10561
10562/* static */ nsGridContainerFrame::FindItemInGridOrderResult
10563nsGridContainerFrame::FindLastItemInGridOrder(
10564 ReverseCSSOrderAwareFrameIterator& aIter,
10565 const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::* aMajor,
10566 LineRange GridArea::* aMinor, uint32_t aFragmentStartTrack,
10567 uint32_t aFirstExcludedTrack) {
10568 FindItemInGridOrderResult result = {nullptr, false};
10569 int32_t maxMajor = -1;
10570 int32_t maxMinor = -1;
10571 aIter.Reset();
10572 int32_t lastMajorTrack = int32_t(aFirstExcludedTrack) - 1;
10573 for (; !aIter.AtEnd(); aIter.Next()) {
10574 const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
10575 // Subtract 1 from the end line to get the item's last track index.
10576 int32_t major = (item.mArea.*aMajor).mEnd - 1;
10577 // Currently, this method is only called with aFirstExcludedTrack ==
10578 // the first track in the next fragment, so we take the opportunity
10579 // to assert this item really belongs to this fragment.
10580 MOZ_ASSERT((item.mArea.*aMajor).mStart < aFirstExcludedTrack,do { static_assert( mozilla::detail::AssertionConditionType<
decltype((item.mArea.*aMajor).mStart < aFirstExcludedTrack
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((item.mArea.*aMajor).mStart < aFirstExcludedTrack
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"(item.mArea.*aMajor).mStart < aFirstExcludedTrack" " (" "found an item that belongs to some later fragment"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10581
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item.mArea.*aMajor).mStart < aFirstExcludedTrack"
") (" "found an item that belongs to some later fragment" ")"
); do { MOZ_CrashSequence(__null, 10581); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10581 "found an item that belongs to some later fragment")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((item.mArea.*aMajor).mStart < aFirstExcludedTrack
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((item.mArea.*aMajor).mStart < aFirstExcludedTrack
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"(item.mArea.*aMajor).mStart < aFirstExcludedTrack" " (" "found an item that belongs to some later fragment"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10581
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item.mArea.*aMajor).mStart < aFirstExcludedTrack"
") (" "found an item that belongs to some later fragment" ")"
); do { MOZ_CrashSequence(__null, 10581); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10582 if (major < int32_t(aFragmentStartTrack)) {
10583 continue; // item doesn't span any track in this fragment
10584 }
10585 int32_t minor = (item.mArea.*aMinor).mEnd - 1;
10586 MOZ_ASSERT(minor >= 0 && major >= 0, "grid item must have span >= 1")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(minor >= 0 && major >= 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(minor >= 0 && major >= 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("minor >= 0 && major >= 0"
" (" "grid item must have span >= 1" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10586); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minor >= 0 && major >= 0"
") (" "grid item must have span >= 1" ")"); do { MOZ_CrashSequence
(__null, 10586); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10587 if (major > maxMajor || (major == maxMajor && minor > maxMinor)) {
10588 maxMajor = major;
10589 maxMinor = minor;
10590 result.mItem = &item;
10591 result.mIsInEdgeTrack = major == lastMajorTrack;
10592 }
10593 }
10594 return result;
10595}
10596
10597nsGridContainerFrame::UsedTrackSizes* nsGridContainerFrame::GetUsedTrackSizes()
10598 const {
10599 return GetProperty(UsedTrackSizes::Prop());
10600}
10601
10602void nsGridContainerFrame::StoreUsedTrackSizes(LogicalAxis aAxis,
10603 const TrackPlan& aSizes) {
10604 auto* uts = GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
10605 uts->mTrackPlans[aAxis].Assign(aSizes);
10606 uts->mCanResolveLineRangeSize[aAxis] = true;
10607 // XXX is resetting these bits necessary?
10608 for (auto& sz : uts->mTrackPlans[aAxis]) {
10609 sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited |
10610 TrackSize::eInfinitelyGrowable);
10611 }
10612}
10613
10614#ifdef DEBUG1
10615void nsGridContainerFrame::SetInitialChildList(ChildListID aListID,
10616 nsFrameList&& aChildList) {
10617 ChildListIDs supportedLists = {FrameChildListID::Principal};
10618 MOZ_ASSERT(supportedLists.contains(aListID), "unexpected child list")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(supportedLists.contains(aListID))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(supportedLists.contains(aListID
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("supportedLists.contains(aListID)" " (" "unexpected child list"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10618
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "supportedLists.contains(aListID)"
") (" "unexpected child list" ")"); do { MOZ_CrashSequence(__null
, 10618); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10619 return nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
10620}
10621
10622void nsGridContainerFrame::TrackSize::DumpStateBits(StateBits aState) {
10623 printf("min:");
10624 if (aState & eAutoMinSizing) {
10625 printf("auto ");
10626 } else if (aState & eMinContentMinSizing) {
10627 printf("min-content ");
10628 } else if (aState & eMaxContentMinSizing) {
10629 printf("max-content ");
10630 }
10631 printf(" max:");
10632 if (aState & eAutoMaxSizing) {
10633 printf("auto ");
10634 } else if (aState & eMinContentMaxSizing) {
10635 printf("min-content ");
10636 } else if (aState & eMaxContentMaxSizing) {
10637 printf("max-content ");
10638 } else if (aState & eFlexMaxSizing) {
10639 printf("flex ");
10640 }
10641 if (aState & eFrozen) {
10642 printf("frozen ");
10643 }
10644 if (aState & eModified) {
10645 printf("modified ");
10646 }
10647 if (aState & eBreakBefore) {
10648 printf("break-before ");
10649 }
10650}
10651
10652void nsGridContainerFrame::TrackSize::Dump() const {
10653 printf("mPosition=%d mBase=%d mLimit=%d ", mPosition, mBase, mLimit);
10654 DumpStateBits(mState);
10655}
10656
10657#endif // DEBUG
10658
10659bool nsGridContainerFrame::IsMasonry(LogicalAxis aAxis) const {
10660 return HasAnyStateBits(aAxis == mozilla::LogicalAxis::Block
10661 ? NS_STATE_GRID_IS_ROW_MASONRY
10662 : NS_STATE_GRID_IS_COL_MASONRY);
10663}
10664
10665bool nsGridContainerFrame::GridItemShouldStretch(const nsIFrame* aChild,
10666 LogicalAxis aAxis) const {
10667 MOZ_ASSERT(aChild->IsGridItem())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->IsGridItem())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChild->IsGridItem()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->IsGridItem()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10667
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsGridItem()"
")"); do { MOZ_CrashSequence(__null, 10667); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10668
10669 if (aChild->IsGridContainerFrame()) {
10670 // The subgrid is always stretched in its subgridded dimensions.
10671 // https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment
10672 const auto* gridContainer =
10673 static_cast<const nsGridContainerFrame*>(aChild);
10674 if (gridContainer->IsSubgrid(aAxis)) {
10675 return true;
10676 }
10677 }
10678
10679 const auto wm = aChild->GetWritingMode();
10680 if (aChild->StyleMargin()->HasAuto(aAxis, wm,
10681 AnchorPosResolutionParams::From(aChild))) {
10682 // Per https://drafts.csswg.org/css-grid-2/#auto-margins, any 'auto' margin
10683 // in an axis disables the alignment property in that axis.
10684 return false;
10685 }
10686
10687 const auto cbwm = GetWritingMode();
10688 if (IsMasonry(wm, aAxis)) {
10689 // The child is in the container's masonry-axis.
10690 // AlignJustifyTracksInMasonryAxis will stretch it, so we don't report that
10691 // here.
10692 return false;
10693 }
10694
10695 const auto alignment =
10696 aChild->StylePosition()->UsedSelfAlignment(wm, aAxis, cbwm, Style());
10697 // An item with 'normal' alignment that is a replaced frame should use its
10698 // natural size, and not fill the grid area.
10699 // https://drafts.csswg.org/css-grid-2/#grid-item-sizing
10700 if (MOZ_LIKELY(alignment == StyleAlignFlags::NORMAL)(__builtin_expect(!!(alignment == StyleAlignFlags::NORMAL), 1
))
) {
10701 return !aChild->HasReplacedSizing();
10702 }
10703 return alignment == StyleAlignFlags::STRETCH;
10704}
10705
10706bool nsGridContainerFrame::ShouldInhibitSubgridDueToIFC(
10707 const nsIFrame* aFrame) {
10708 // Just checking for things that make us establish an independent formatting
10709 // context (IFC) and hence prevent us from being a subgrid:
10710 // * Out-of-flow (e.g. abspos) frames also establish an IFC. Note, our
10711 // NS_FRAME_OUT_OF_FLOW bit potentially isn't set yet, so we check our style.
10712 // * contain:layout and contain:paint each make us establish an IFC.
10713 const auto* display = aFrame->StyleDisplay();
10714 return display->IsContainLayout() || display->IsContainPaint() ||
10715 display->mContainerType &
10716 (StyleContainerType::SIZE | StyleContainerType::INLINE_SIZE) ||
10717 display->IsAbsolutelyPositionedStyle();
10718}
10719
10720nsGridContainerFrame* nsGridContainerFrame::GetGridContainerFrame(
10721 nsIFrame* aFrame) {
10722 nsGridContainerFrame* gridFrame = nullptr;
10723
10724 if (aFrame) {
10725 nsIFrame* inner = aFrame;
10726 if (MOZ_UNLIKELY(aFrame->IsFieldSetFrame())(__builtin_expect(!!(aFrame->IsFieldSetFrame()), 0))) {
10727 inner = static_cast<nsFieldSetFrame*>(aFrame)->GetInner();
10728 }
10729 // Since "Get" methods like GetInner and GetContentInsertionFrame can
10730 // return null, we check the return values before dereferencing. Our
10731 // calling pattern makes this unlikely, but we're being careful.
10732 nsIFrame* insertionFrame =
10733 inner ? inner->GetContentInsertionFrame() : nullptr;
10734 nsIFrame* possibleGridFrame = insertionFrame ? insertionFrame : aFrame;
10735 gridFrame = possibleGridFrame->IsGridContainerFrame()
10736 ? static_cast<nsGridContainerFrame*>(possibleGridFrame)
10737 : nullptr;
10738 }
10739 return gridFrame;
10740}
10741
10742nsGridContainerFrame* nsGridContainerFrame::GetGridFrameWithComputedInfo(
10743 nsIFrame* aFrame) {
10744 nsGridContainerFrame* gridFrame = GetGridContainerFrame(aFrame);
10745 if (!gridFrame) {
10746 return nullptr;
10747 }
10748
10749 auto HasComputedInfo = [](const nsGridContainerFrame& aFrame) -> bool {
10750 return aFrame.HasProperty(GridColTrackInfo()) &&
10751 aFrame.HasProperty(GridRowTrackInfo()) &&
10752 aFrame.HasProperty(GridColumnLineInfo()) &&
10753 aFrame.HasProperty(GridRowLineInfo());
10754 };
10755
10756 if (HasComputedInfo(*gridFrame)) {
10757 return gridFrame;
10758 }
10759
10760 // Trigger a reflow that generates additional grid property data.
10761 // Hold onto aFrame while we do this, in case reflow destroys it.
10762 AutoWeakFrame weakFrameRef(gridFrame);
10763
10764 RefPtr<mozilla::PresShell> presShell = gridFrame->PresShell();
10765 gridFrame->AddStateBits(NS_STATE_GRID_COMPUTED_INFO);
10766 presShell->FrameNeedsReflow(gridFrame, IntrinsicDirty::None,
10767 NS_FRAME_IS_DIRTY);
10768 presShell->FlushPendingNotifications(FlushType::Layout);
10769
10770 // If the weakFrameRef is no longer valid, then we must bail out.
10771 if (!weakFrameRef.IsAlive()) {
10772 return nullptr;
10773 }
10774
10775 // This can happen if for some reason we ended up not reflowing, like in print
10776 // preview under some circumstances.
10777 if (MOZ_UNLIKELY(!HasComputedInfo(*gridFrame))(__builtin_expect(!!(!HasComputedInfo(*gridFrame)), 0))) {
10778 return nullptr;
10779 }
10780
10781 return gridFrame;
10782}
10783
10784void nsGridContainerFrame::MarkCachedGridMeasurementsDirty(
10785 nsIFrame* aItemFrame) {
10786 MOZ_ASSERT(aItemFrame->IsGridItem())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aItemFrame->IsGridItem())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aItemFrame->IsGridItem())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aItemFrame->IsGridItem()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10786
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItemFrame->IsGridItem()"
")"); do { MOZ_CrashSequence(__null, 10786); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10787 aItemFrame->RemoveProperty(CachedBAxisMeasurement::Prop());
10788}
10789
10790// TODO: This is a rather dumb implementation of nsILineIterator, but it's
10791// better than our pre-existing behavior. Ideally, we should probably use the
10792// grid information to return a meaningful number of lines etc.
10793bool nsGridContainerFrame::IsLineIteratorFlowRTL() { return false; }
10794
10795int32_t nsGridContainerFrame::GetNumLines() const {
10796 return mFrames.GetLength();
10797}
10798
10799Result<nsILineIterator::LineInfo, nsresult> nsGridContainerFrame::GetLine(
10800 int32_t aLineNumber) {
10801 if (aLineNumber < 0 || aLineNumber >= GetNumLines()) {
10802 return Err(NS_ERROR_FAILURE);
10803 }
10804 LineInfo rv;
10805 nsIFrame* f = mFrames.FrameAt(aLineNumber);
10806 rv.mLineBounds = f->GetRect();
10807 rv.mFirstFrameOnLine = f;
10808 rv.mNumFramesOnLine = 1;
10809 return rv;
10810}
10811
10812int32_t nsGridContainerFrame::FindLineContaining(const nsIFrame* aFrame,
10813 int32_t aStartLine) {
10814 const int32_t index = mFrames.IndexOf(aFrame);
10815 if (index < 0) {
10816 return -1;
10817 }
10818 if (index < aStartLine) {
10819 return -1;
10820 }
10821 return index;
10822}
10823
10824NS_IMETHODIMPnsresult
10825nsGridContainerFrame::CheckLineOrder(int32_t aLine, bool* aIsReordered,
10826 nsIFrame** aFirstVisual,
10827 nsIFrame** aLastVisual) {
10828 *aIsReordered = false;
10829 *aFirstVisual = nullptr;
10830 *aLastVisual = nullptr;
10831 return NS_OK;
10832}
10833
10834NS_IMETHODIMPnsresult
10835nsGridContainerFrame::FindFrameAt(int32_t aLineNumber, nsPoint aPos,
10836 nsIFrame** aFrameFound,
10837 bool* aPosIsBeforeFirstFrame,
10838 bool* aPosIsAfterLastFrame) {
10839 const auto wm = GetWritingMode();
10840 const LogicalPoint pos(wm, aPos, GetSize());
10841
10842 *aFrameFound = nullptr;
10843 *aPosIsBeforeFirstFrame = true;
10844 *aPosIsAfterLastFrame = false;
10845
10846 nsIFrame* f = mFrames.FrameAt(aLineNumber);
10847 if (!f) {
10848 return NS_OK;
10849 }
10850
10851 auto rect = f->GetLogicalRect(wm, GetSize());
10852 *aFrameFound = f;
10853 *aPosIsBeforeFirstFrame = pos.I(wm) < rect.IStart(wm);
10854 *aPosIsAfterLastFrame = pos.I(wm) > rect.IEnd(wm);
10855 return NS_OK;
10856}
10857
10858void nsGridContainerFrame::TrackPlan::Initialize(TrackSizingPhase aPhase,
10859 const Tracks& aTracks) {
10860 MOZ_ASSERT(mTrackSizes.Length() == aTracks.mSizes.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTrackSizes.Length() == aTracks.mSizes.Length())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTrackSizes.Length() == aTracks.mSizes.Length()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mTrackSizes.Length() == aTracks.mSizes.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10860
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTrackSizes.Length() == aTracks.mSizes.Length()"
")"); do { MOZ_CrashSequence(__null, 10860); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10861 auto plan = mTrackSizes.begin();
10862 auto sz = aTracks.mSizes.begin();
10863 for (; plan != mTrackSizes.end() && sz != aTracks.mSizes.end();
10864 plan++, sz++) {
10865 plan->mBase = Tracks::StartSizeInDistribution(aPhase, *sz);
10866 MOZ_ASSERT(aPhase == TrackSizingPhase::MaxContentMaximums ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPhase == TrackSizingPhase::MaxContentMaximums || !(
sz->mState & TrackSize::eInfinitelyGrowable))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->
mState & TrackSize::eInfinitelyGrowable)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
" (" "forgot to reset the eInfinitelyGrowable bit?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10868); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
10867 !(sz->mState & TrackSize::eInfinitelyGrowable),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPhase == TrackSizingPhase::MaxContentMaximums || !(
sz->mState & TrackSize::eInfinitelyGrowable))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->
mState & TrackSize::eInfinitelyGrowable)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
" (" "forgot to reset the eInfinitelyGrowable bit?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10868); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
10868 "forgot to reset the eInfinitelyGrowable bit?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPhase == TrackSizingPhase::MaxContentMaximums || !(
sz->mState & TrackSize::eInfinitelyGrowable))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->
mState & TrackSize::eInfinitelyGrowable)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
" (" "forgot to reset the eInfinitelyGrowable bit?" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10868); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
;
10869 plan->mState = sz->mState;
10870 }
10871}
10872
10873// Distribute space to all flex tracks this item spans.
10874// https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
10875nscoord nsGridContainerFrame::TrackPlan::DistributeToFlexTrackSizes(
10876 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
10877 const TrackSizingFunctions& aFunctions,
10878 const nsGridContainerFrame::Tracks& aTracks) {
10879 nscoord space = aAvailableSpace;
10880 // Measure used fraction.
10881 double totalFr = 0.0;
10882 // TODO alaskanemily: we should be subtracting definite-sized tracks from
10883 // the available space below.
10884 for (uint32_t track : aGrowableTracks) {
10885 MOZ_ASSERT(aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
" (" "Only flex-sized tracks should be growable during step 4"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10886
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
") (" "Only flex-sized tracks should be growable during step 4"
")"); do { MOZ_CrashSequence(__null, 10886); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10886 "Only flex-sized tracks should be growable during step 4")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
" (" "Only flex-sized tracks should be growable during step 4"
")", "./../../../layout/generic/nsGridContainerFrame.cpp", 10886
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
") (" "Only flex-sized tracks should be growable during step 4"
")"); do { MOZ_CrashSequence(__null, 10886); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10887 totalFr += aFunctions.MaxSizingFor(track).AsFlex()._0;
10888 }
10889 MOZ_ASSERT(totalFr >= 0.0, "flex fractions must be non-negative.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(totalFr >= 0.0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(totalFr >= 0.0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("totalFr >= 0.0"
" (" "flex fractions must be non-negative." ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10889); AnnotateMozCrashReason("MOZ_ASSERT" "(" "totalFr >= 0.0"
") (" "flex fractions must be non-negative." ")"); do { MOZ_CrashSequence
(__null, 10889); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10890
10891 double frSize = aAvailableSpace;
10892 if (totalFr > 1.0) {
10893 frSize /= totalFr;
10894 }
10895 // Distribute the space to the tracks proportionally to the fractional
10896 // sizes.
10897 for (uint32_t track : aGrowableTracks) {
10898 TrackSize& sz = mTrackSizes[track];
10899 if (sz.IsFrozen()) {
10900 continue;
10901 }
10902 const double trackFr = aFunctions.MaxSizingFor(track).AsFlex()._0;
10903 nscoord size = NSToCoordRoundWithClamp(frSize * trackFr);
10904 // This shouldn't happen in theory, but it could happen due to a
10905 // combination of floating-point error during the multiplication above
10906 // and loss of precision in the cast.
10907 if (MOZ_UNLIKELY(size > space)(__builtin_expect(!!(size > space), 0))) {
10908 size = space;
10909 space = 0;
10910 } else {
10911 space -= size;
10912 }
10913 sz.mBase = std::max(sz.mBase, size);
10914 }
10915 return space;
10916}
10917
10918void nsGridContainerFrame::ItemPlan::Initialize(
10919 TrackSizingPhase aPhase, const nsTArray<uint32_t>& aGrowableTracks,
10920 const nsGridContainerFrame::Tracks& aTracks) {
10921 for (uint32_t track : aGrowableTracks) {
10922 auto& plan = mTrackSizes[track];
10923 const TrackSize& sz = aTracks.mSizes[track];
10924 plan.mBase = Tracks::StartSizeInDistribution(aPhase, sz);
10925 bool unlimited = sz.mState & TrackSize::eInfinitelyGrowable;
10926 plan.mLimit = unlimited ? NS_UNCONSTRAINEDSIZE : sz.mLimit;
10927 plan.mState = sz.mState;
10928 }
10929}
10930
10931nscoord nsGridContainerFrame::ItemPlan::GrowTracksToLimit(
10932 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
10933 const FitContentClamper& aFitContentClamper) {
10934 MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAvailableSpace > 0 && aGrowableTracks.Length
() > 0)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aAvailableSpace > 0 && aGrowableTracks
.Length() > 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAvailableSpace > 0 && aGrowableTracks.Length() > 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 10934
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0"
")"); do { MOZ_CrashSequence(__null, 10934); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10935 nscoord space = aAvailableSpace;
10936 uint32_t numGrowable = aGrowableTracks.Length();
10937 while (true) {
10938 nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
10939 for (uint32_t track : aGrowableTracks) {
10940 TrackSize& sz = mTrackSizes[track];
10941 if (sz.IsFrozen()) {
10942 continue;
10943 }
10944 nscoord newBase = sz.mBase + spacePerTrack;
10945 nscoord limit = sz.mLimit;
10946 if (MOZ_UNLIKELY((sz.mState & TrackSize::eApplyFitContentClamping) &&(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
10947 aFitContentClamper)(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
) {
10948 // Clamp the limit to the fit-content() size, for §12.5.2 step 5/6.
10949 aFitContentClamper(track, sz.mBase, &limit);
10950 }
10951 if (newBase > limit) {
10952 nscoord consumed = limit - sz.mBase;
10953 if (consumed > 0) {
10954 space -= consumed;
10955 sz.mBase = limit;
10956 }
10957 sz.mState |= TrackSize::eFrozen;
10958 if (--numGrowable == 0) {
10959 return space;
10960 }
10961 } else {
10962 sz.mBase = newBase;
10963 space -= spacePerTrack;
10964 }
10965 MOZ_ASSERT(space >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(space >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(space >= 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("space >= 0",
"./../../../layout/generic/nsGridContainerFrame.cpp", 10965)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "space >= 0" ")"
); do { MOZ_CrashSequence(__null, 10965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10966 if (space == 0) {
10967 return 0;
10968 }
10969 }
10970 }
10971 MOZ_ASSERT_UNREACHABLE("we don't exit the loop above except by return")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"we don't exit the loop above except by return" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 10971); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "we don't exit the loop above except by return"
")"); do { MOZ_CrashSequence(__null, 10971); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10972 return 0;
10973}
10974
10975uint32_t nsGridContainerFrame::ItemPlan::MarkExcludedTracks(
10976 TrackSizingPhase aPhase, const nsTArray<uint32_t>& aGrowableTracks,
10977 SizingConstraint aConstraint) {
10978 uint32_t numGrowable = aGrowableTracks.Length();
10979 if (aPhase == TrackSizingPhase::IntrinsicMaximums ||
10980 aPhase == TrackSizingPhase::MaxContentMaximums) {
10981 // "when handling any intrinsic growth limit: all affected tracks"
10982 return numGrowable;
10983 }
10984
10985 TrackSize::StateBits selector = Tracks::SelectorForPhase(aPhase, aConstraint);
10986 numGrowable = MarkExcludedTracks(
10987 numGrowable, aGrowableTracks, TrackSize::eMaxContentMinSizing,
10988 TrackSize::eMaxContentMaxSizing, TrackSize::eSkipGrowUnlimited1);
10989 // Note that eMaxContentMinSizing is always included. We do those first:
10990 if ((selector &= ~TrackSize::eMaxContentMinSizing)) {
10991 numGrowable = MarkExcludedTracks(numGrowable, aGrowableTracks, selector,
10992 TrackSize::eIntrinsicMaxSizing,
10993 TrackSize::eSkipGrowUnlimited2);
10994 }
10995 return numGrowable;
10996}
10997
10998uint32_t nsGridContainerFrame::ItemPlan::MarkExcludedTracks(
10999 uint32_t aNumGrowable, const nsTArray<uint32_t>& aGrowableTracks,
11000 TrackSize::StateBits aMinSizingSelector,
11001 TrackSize::StateBits aMaxSizingSelector, TrackSize::StateBits aSkipFlag) {
11002 bool foundOneSelected = false;
11003 bool foundOneGrowable = false;
11004 uint32_t numGrowable = aNumGrowable;
11005 for (uint32_t track : aGrowableTracks) {
11006 TrackSize& sz = mTrackSizes[track];
11007 const auto state = sz.mState;
11008 if (state & aMinSizingSelector) {
11009 foundOneSelected = true;
11010 if (state & aMaxSizingSelector) {
11011 foundOneGrowable = true;
11012 continue;
11013 }
11014 sz.mState |= aSkipFlag;
11015 MOZ_ASSERT(numGrowable != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numGrowable != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(numGrowable != 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("numGrowable != 0"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 11015
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numGrowable != 0"
")"); do { MOZ_CrashSequence(__null, 11015); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11016 --numGrowable;
11017 }
11018 }
11019 // 12.5 "if there are no such tracks, then all affected tracks"
11020 if (foundOneSelected && !foundOneGrowable) {
11021 for (uint32_t track : aGrowableTracks) {
11022 mTrackSizes[track].mState &= ~aSkipFlag;
11023 }
11024 numGrowable = aNumGrowable;
11025 }
11026 return numGrowable;
11027}
11028
11029void nsGridContainerFrame::ItemPlan::GrowSelectedTracksUnlimited(
11030 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
11031 uint32_t aNumGrowable, const FitContentClamper& aFitContentClamper) {
11032 MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0 &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAvailableSpace > 0 && aGrowableTracks.Length
() > 0 && aNumGrowable <= aGrowableTracks.Length
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aAvailableSpace > 0 && aGrowableTracks.Length
() > 0 && aNumGrowable <= aGrowableTracks.Length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 11033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 11033); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11033 aNumGrowable <= aGrowableTracks.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAvailableSpace > 0 && aGrowableTracks.Length
() > 0 && aNumGrowable <= aGrowableTracks.Length
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aAvailableSpace > 0 && aGrowableTracks.Length
() > 0 && aNumGrowable <= aGrowableTracks.Length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 11033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 11033); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11034 nscoord space = aAvailableSpace;
11035 DebugOnly<bool> didClamp = false;
11036 while (aNumGrowable) {
11037 nscoord spacePerTrack = std::max<nscoord>(space / aNumGrowable, 1);
11038 for (uint32_t track : aGrowableTracks) {
11039 TrackSize& sz = mTrackSizes[track];
11040 if (sz.mState & TrackSize::eSkipGrowUnlimited) {
11041 continue; // an excluded track
11042 }
11043 nscoord delta = spacePerTrack;
11044 nscoord newBase = sz.mBase + delta;
11045 if (MOZ_UNLIKELY((sz.mState & TrackSize::eApplyFitContentClamping) &&(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
11046 aFitContentClamper)(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
) {
11047 // Clamp newBase to the fit-content() size, for §12.5.2 step 5/6.
11048 if (aFitContentClamper(track, sz.mBase, &newBase)) {
11049 didClamp = true;
11050 delta = newBase - sz.mBase;
11051 MOZ_ASSERT(delta >= 0, "track size shouldn't shrink")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(delta >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(delta >= 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("delta >= 0" " ("
"track size shouldn't shrink" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 11051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "delta >= 0"
") (" "track size shouldn't shrink" ")"); do { MOZ_CrashSequence
(__null, 11051); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11052 sz.mState |= TrackSize::eSkipGrowUnlimited1;
11053 --aNumGrowable;
11054 }
11055 }
11056 sz.mBase = newBase;
11057 space -= delta;
11058 MOZ_ASSERT(space >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(space >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(space >= 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("space >= 0",
"./../../../layout/generic/nsGridContainerFrame.cpp", 11058)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "space >= 0" ")"
); do { MOZ_CrashSequence(__null, 11058); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11059 if (space == 0) {
11060 return;
11061 }
11062 }
11063 }
11064 MOZ_ASSERT(didClamp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(didClamp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(didClamp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("didClamp" " (" "we don't exit the loop above except by return, "
"unless we clamped some track's size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 11066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "didClamp" ") ("
"we don't exit the loop above except by return, " "unless we clamped some track's size"
")"); do { MOZ_CrashSequence(__null, 11066); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11065 "we don't exit the loop above except by return, "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(didClamp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(didClamp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("didClamp" " (" "we don't exit the loop above except by return, "
"unless we clamped some track's size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 11066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "didClamp" ") ("
"we don't exit the loop above except by return, " "unless we clamped some track's size"
")"); do { MOZ_CrashSequence(__null, 11066); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11066 "unless we clamped some track's size")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(didClamp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(didClamp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("didClamp" " (" "we don't exit the loop above except by return, "
"unless we clamped some track's size" ")", "./../../../layout/generic/nsGridContainerFrame.cpp"
, 11066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "didClamp" ") ("
"we don't exit the loop above except by return, " "unless we clamped some track's size"
")"); do { MOZ_CrashSequence(__null, 11066); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11067}