Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/generic/./../../../layout/generic/nsGridContainerFrame.cpp
Warning:line 6575, 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/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -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-09-01-224014-2642839-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(bool aIsSubgrid) const {
79 if (IsTrackList()) {
80 return AsTrackList()->line_names.AsSpan();
81 }
82 if (IsSubgrid() && aIsSubgrid) {
83 // For subgrid, we need to resolve <line-name-list> from each
84 // StyleGenericLineNameListValue, so return empty.
85 return {};
86 }
87 MOZ_ASSERT(IsNone() || IsMasonry() || (IsSubgrid() && !aIsSubgrid))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNone() || IsMasonry() || (IsSubgrid() && !
aIsSubgrid))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(IsNone() || IsMasonry() || (IsSubgrid
() && !aIsSubgrid)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsNone() || IsMasonry() || (IsSubgrid() && !aIsSubgrid)"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 87); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsNone() || IsMasonry() || (IsSubgrid() && !aIsSubgrid)"
")"); do { MOZ_CrashSequence(__null, 87); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
88 return {};
89}
90
91template <>
92inline const StyleTrackBreadth& StyleTrackSize::GetMax() const {
93 if (IsBreadth()) {
94 return AsBreadth();
95 }
96 if (IsMinmax()) {
97 return AsMinmax()._1;
98 }
99 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", 99); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFitContent()" ")"); do { MOZ_CrashSequence
(__null, 99); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
100 return AsFitContent();
101}
102
103template <>
104inline const StyleTrackBreadth& StyleTrackSize::GetMin() const {
105 static const StyleTrackBreadth kAuto = StyleTrackBreadth::Auto();
106 if (IsBreadth()) {
107 // <flex> behaves like minmax(auto, <flex>)
108 return AsBreadth().IsFlex() ? kAuto : AsBreadth();
109 }
110 if (IsMinmax()) {
111 return AsMinmax()._0;
112 }
113 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", 113);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFitContent()" ")"
); do { MOZ_CrashSequence(__null, 113); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
114 return kAuto;
115}
116
117} // namespace mozilla
118
119static nscoord ClampToCSSMaxBSize(nscoord aSize,
120 const ReflowInput* aReflowInput) {
121 auto maxSize = aReflowInput->ComputedMaxBSize();
122 if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)(__builtin_expect(!!(maxSize != NS_UNCONSTRAINEDSIZE), 0))) {
123 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", 123);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReflowInput->ComputedMinBSize() <= maxSize"
")"); do { MOZ_CrashSequence(__null, 123); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
124 aSize = std::min(aSize, maxSize);
125 }
126 return aSize;
127}
128
129// Same as above and set aStatus INCOMPLETE if aSize wasn't clamped.
130// (If we clamp aSize it means our size is less than the break point,
131// i.e. we're effectively breaking in our overflow, so we should leave
132// aStatus as is (it will likely be set to OVERFLOW_INCOMPLETE later)).
133static nscoord ClampToCSSMaxBSize(nscoord aSize,
134 const ReflowInput* aReflowInput,
135 nsReflowStatus* aStatus) {
136 auto maxSize = aReflowInput->ComputedMaxBSize();
137 if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)(__builtin_expect(!!(maxSize != NS_UNCONSTRAINEDSIZE), 0))) {
138 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", 138);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReflowInput->ComputedMinBSize() <= maxSize"
")"); do { MOZ_CrashSequence(__null, 138); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
139 if (aSize < maxSize) {
140 aStatus->SetIncomplete();
141 } else {
142 aSize = maxSize;
143 }
144 } else {
145 aStatus->SetIncomplete();
146 }
147 return aSize;
148}
149
150template <typename Size>
151static bool IsPercentOfIndefiniteSize(const Size& aCoord,
152 nscoord aPercentBasis) {
153 return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
154}
155
156static nscoord ResolveToDefiniteSize(const StyleTrackBreadth& aBreadth,
157 nscoord aPercentBasis) {
158 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", 158);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBreadth.IsBreadth()"
")"); do { MOZ_CrashSequence(__null, 158); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
159 if (::IsPercentOfIndefiniteSize(aBreadth.AsBreadth(), aPercentBasis)) {
160 return nscoord(0);
161 }
162 return std::max(nscoord(0), aBreadth.AsBreadth().Resolve(aPercentBasis));
163}
164
165// Synthesize a baseline from a border box. For an alphabetical baseline
166// this is the end edge of the border box. For a central baseline it's
167// the center of the border box.
168// https://drafts.csswg.org/css-align-3/#synthesize-baseline
169// For a 'first baseline' the measure is from the border-box start edge and
170// for a 'last baseline' the measure is from the border-box end edge.
171//
172// The 'LogicalAxis aAxis' represents the axis (in terms of aWM) that the
173// baseline corresponds to. (Typically, baselines are a measurement in the
174// block axis; e.g. for English horizontal-tb text, a traditional baseline
175// would be a y-axis measurement. But in some cases (e.g. orthogonal WMs), we
176// may need to synthesize a baseline in a child's inline axis, which is when
177// this function might receive an aAxis of LogicalAxis::Inline. In that case, we
178// assume that the writing mode's preference for central vs. alphabetic
179// baselines is irrelevant, since that's a choice about its block-axis
180// baselines, and we just unconditionally use the alphabetic baseline
181// (e.g. border-box bottom edge).
182static nscoord SynthesizeBaselineFromBorderBox(BaselineSharingGroup aGroup,
183 WritingMode aWM,
184 LogicalAxis aAxis,
185 nscoord aBorderBoxSize) {
186 const bool useAlphabeticBaseline =
187 (aAxis == LogicalAxis::Inline) ? true : aWM.IsAlphabeticalBaseline();
188
189 if (aGroup == BaselineSharingGroup::First) {
190 return useAlphabeticBaseline ? aBorderBoxSize : aBorderBoxSize / 2;
191 }
192 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"
, 192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGroup == BaselineSharingGroup::Last"
")"); do { MOZ_CrashSequence(__null, 192); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
193 // Round up for central baseline offset, to be consistent with eFirst.
194 return useAlphabeticBaseline ? 0
195 : (aBorderBoxSize / 2) + (aBorderBoxSize % 2);
196}
197
198// The helper struct to hold the box sizing adjustment.
199struct BoxSizingAdjustment {
200 BoxSizingAdjustment() = delete;
201 BoxSizingAdjustment(const WritingMode aWM, const ComputedStyle& aStyle)
202 : mWM(aWM), mStyle(aStyle) {}
203
204 const LogicalSize& EnsureAndGet() {
205 if (mValue) {
206 return mValue.ref();
207 }
208
209 if (mStyle.StylePosition()->mBoxSizing != StyleBoxSizing::BorderBox) {
210 // Use default, (0, 0).
211 mValue.emplace(mWM);
212 return mValue.ref();
213 }
214
215 const auto& padding = mStyle.StylePadding()->mPadding;
216 LogicalMargin border(mWM, mStyle.StyleBorder()->GetComputedBorder());
217 // We can use zero percentage basis since this is only called from
218 // intrinsic sizing code.
219 const nscoord percentageBasis = 0;
220 const nscoord iBP =
221 std::max(padding.GetIStart(mWM).Resolve(percentageBasis), 0) +
222 std::max(padding.GetIEnd(mWM).Resolve(percentageBasis), 0) +
223 border.IStartEnd(mWM);
224 const nscoord bBP =
225 std::max(padding.GetBStart(mWM).Resolve(percentageBasis), 0) +
226 std::max(padding.GetBEnd(mWM).Resolve(percentageBasis), 0) +
227 border.BStartEnd(mWM);
228 mValue.emplace(mWM, iBP, bBP);
229 return mValue.ref();
230 }
231
232 private:
233 const WritingMode mWM;
234 const ComputedStyle& mStyle;
235 // The wrapped value we would like to use for the box sizing adjustment.
236 Maybe<LogicalSize> mValue;
237};
238
239static Maybe<nscoord> GetPercentageBasisForAR(
240 const LogicalAxis aRatioDeterminingAxis, const WritingMode aWM,
241 const Maybe<LogicalSize>& aContainingBlockSize) {
242 if (!aContainingBlockSize) {
243 return Nothing();
244 }
245
246 const nscoord basis = aContainingBlockSize->Size(aRatioDeterminingAxis, aWM);
247 // If the basis is unconstrained (because we are still computing the
248 // containing block size), we should treat it as no basis.
249 return basis == NS_UNCONSTRAINEDSIZE ? Nothing() : Some(basis);
250}
251
252template <typename Type>
253static Maybe<nscoord> ComputeTransferredSize(
254 const Type& aRatioDeterminingSize, const LogicalAxis aAxis,
255 const WritingMode aWM, const AspectRatio& aAspectRatio,
256 BoxSizingAdjustment& aBoxSizingAdjustment,
257 const Maybe<LogicalSize>& aContainingBlockSize) {
258 // Use GetOrthogonalAxis() to get the ratio-determining axis.
259 const Maybe<nscoord> basis = GetPercentageBasisForAR(
260 GetOrthogonalAxis(aAxis), aWM, aContainingBlockSize);
261 nscoord rdSize = 0;
262 if (aRatioDeterminingSize->ConvertsToLength()) {
263 rdSize = aRatioDeterminingSize->ToLength();
264 } else if (aRatioDeterminingSize->HasPercent() && basis) {
265 rdSize = aRatioDeterminingSize->AsLengthPercentage().Resolve(*basis);
266 } else {
267 // Either we are not using LengthPercentage or there is no percentage basis.
268 return Nothing();
269 }
270 return Some(aAspectRatio.ComputeRatioDependentSize(
271 aAxis, aWM, rdSize, aBoxSizingAdjustment.EnsureAndGet()));
272}
273
274// A cached result for a grid item's block-axis measuring reflow. This
275// cache prevents us from doing exponential reflows in cases of deeply
276// nested grid frames.
277//
278// We store the cached value in the grid item's frame property table.
279//
280// We cache the following as a "key"
281// - The size of the grid area in the item's inline axis
282// - The item's block axis baseline padding
283// ...and we cache the following as the "value",
284// - The item's border-box BSize
285class nsGridContainerFrame::CachedBAxisMeasurement final {
286 public:
287 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, CachedBAxisMeasurement)static const mozilla::FramePropertyDescriptor<CachedBAxisMeasurement
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<CachedBAxisMeasurement>::NewWithDestructor<DeleteValue
>(); return &descriptor; }
288
289 CachedBAxisMeasurement(const nsIFrame* aFrame, const LogicalSize& aCBSize,
290 const nscoord aBSize)
291 : mKey(aFrame, aCBSize), mBSize(aBSize) {}
292
293 bool IsValidFor(const nsIFrame* aFrame, const LogicalSize& aCBSize) const {
294 if (aFrame->IsSubtreeDirty()) {
295 return false;
296 }
297 return mKey == Key(aFrame, aCBSize);
298 }
299
300 nscoord BSize() const { return mBSize; }
301
302 void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize,
303 const nscoord aBSize) {
304 mKey.Update(aFrame, aCBSize);
305 mBSize = aBSize;
306 }
307
308 private:
309 struct Key final {
310 nscoord mCBSizeInItemInlineAxis;
311 nscoord mBaselinePaddingInItemBlockAxis;
312
313 Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
314 Update(aFrame, aCBSize);
315 }
316
317 void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
318 mCBSizeInItemInlineAxis = aCBSize.ISize(aFrame->GetWritingMode());
319 mBaselinePaddingInItemBlockAxis =
320 aFrame->GetProperty(nsIFrame::BBaselinePadProperty());
321 }
322
323 bool operator==(const Key& aOther) const = default;
324 };
325
326 Key mKey;
327 nscoord mBSize;
328};
329
330// The input sizes for calculating the number of repeat(auto-fill/fit) tracks.
331// https://drafts.csswg.org/css-grid-2/#auto-repeat
332struct RepeatTrackSizingInput {
333 explicit RepeatTrackSizingInput(WritingMode aWM)
334 : mMin(aWM, 0, 0),
335 mSize(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
336 mMax(aWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) {}
337
338 RepeatTrackSizingInput(const LogicalSize& aMin, const LogicalSize& aSize,
339 const LogicalSize& aMax)
340 : mMin(aMin), mSize(aSize), mMax(aMax) {}
341
342 // This should be used in intrinsic sizing (i.e. when we can't initialize
343 // the sizes directly from ReflowInput values).
344 void InitFromStyle(LogicalAxis aAxis, WritingMode aWM, const nsIFrame* aFrame,
345 const ComputedStyle* aStyle,
346 const AspectRatio& aAspectRatio,
347 const Maybe<LogicalSize>& aContainingBlockSize) {
348 const auto& pos = aStyle->StylePosition();
349 const AnchorPosResolutionParams anchorResolutionParams{
350 aFrame, aStyle->StyleDisplay()->mPosition};
351 BoxSizingAdjustment boxSizingAdjustment(aWM, *aStyle);
352 const nscoord cbSizeInAxis = aContainingBlockSize
353 ? aContainingBlockSize->Size(aAxis, aWM)
354 : NS_UNCONSTRAINEDSIZE;
355
356 auto adjustForBoxSizing = [aWM, aAxis,
357 &boxSizingAdjustment](nscoord aSize) {
358 return std::max(
359 aSize - boxSizingAdjustment.EnsureAndGet().Size(aAxis, aWM), 0);
360 };
361
362 nscoord& min = mMin.Size(aAxis, aWM);
363 const auto styleMinSize = pos->MinSize(aAxis, aWM, anchorResolutionParams);
364 if (styleMinSize->ConvertsToLength()) {
365 min = adjustForBoxSizing(styleMinSize->ToLength());
366 } else if (styleMinSize->HasPercent() &&
367 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
368 min = adjustForBoxSizing(
369 styleMinSize->AsLengthPercentage().Resolve(cbSizeInAxis));
370 } else if (aAspectRatio && styleMinSize->BehavesLikeInitialValue(aAxis)) {
371 // Use GetOrthogonalAxis() to get the ratio-determining axis. Same for max
372 // and size below in this function.
373 const auto styleRDMinSize =
374 pos->MinSize(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
375 if (Maybe<nscoord> resolvedMinSize = ComputeTransferredSize(
376 styleRDMinSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
377 aContainingBlockSize)) {
378 min = *resolvedMinSize;
379 }
380 }
381
382 nscoord& max = mMax.Size(aAxis, aWM);
383 const auto styleMaxSize = pos->MaxSize(aAxis, aWM, anchorResolutionParams);
384 if (styleMaxSize->ConvertsToLength()) {
385 max = std::max(min, adjustForBoxSizing(styleMaxSize->ToLength()));
386 } else if (styleMaxSize->HasPercent() &&
387 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
388 max = std::max(
389 min, adjustForBoxSizing(
390 styleMaxSize->AsLengthPercentage().Resolve(cbSizeInAxis)));
391 } else if (aAspectRatio && styleMaxSize->BehavesLikeInitialValue(aAxis)) {
392 const auto styleRDMaxSize =
393 pos->MaxSize(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
394 if (Maybe<nscoord> resolvedMaxSize = ComputeTransferredSize(
395 styleRDMaxSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
396 aContainingBlockSize)) {
397 max = std::max(min, *resolvedMaxSize);
398 }
399 }
400
401 nscoord& size = mSize.Size(aAxis, aWM);
402 // When computing the intrinsic inline size, disregard the explicit
403 // inline-size property as it should not affect the final result.
404 const auto styleSize = aAxis == LogicalAxis::Inline
405 ? AnchorResolvedSizeHelper::Auto()
406 : pos->BSize(aWM, anchorResolutionParams);
407 if (styleSize->ConvertsToLength()) {
408 size = std::clamp(adjustForBoxSizing(styleSize->ToLength()), min, max);
409 } else if (styleSize->HasPercent() &&
410 cbSizeInAxis != NS_UNCONSTRAINEDSIZE) {
411 size =
412 std::clamp(adjustForBoxSizing(
413 styleSize->AsLengthPercentage().Resolve(cbSizeInAxis)),
414 min, max);
415 } else if (aAspectRatio && styleSize->BehavesLikeInitialValue(aAxis)) {
416 const auto styleRDSize =
417 pos->Size(GetOrthogonalAxis(aAxis), aWM, anchorResolutionParams);
418 if (Maybe<nscoord> resolvedSize = ComputeTransferredSize(
419 styleRDSize, aAxis, aWM, aAspectRatio, boxSizingAdjustment,
420 aContainingBlockSize)) {
421 size = std::clamp(*resolvedSize, min, max);
422 }
423 }
424 }
425
426 LogicalSize mMin;
427 LogicalSize mSize;
428 LogicalSize mMax;
429};
430
431enum class GridLineSide {
432 BeforeGridGap,
433 AfterGridGap,
434};
435
436struct nsGridContainerFrame::TrackSize {
437 enum StateBits : uint16_t {
438 eNone = 0,
439 eAutoMinSizing = 1 << 0,
440 eMinContentMinSizing = 1 << 1,
441 eMaxContentMinSizing = 1 << 2,
442 eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
443 eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
444 eModified = 1 << 3,
445 eAutoMaxSizing = 1 << 4,
446 eMinContentMaxSizing = 1 << 5,
447 eMaxContentMaxSizing = 1 << 6,
448 eAutoOrMaxContentMaxSizing = eAutoMaxSizing | eMaxContentMaxSizing,
449 eIntrinsicMaxSizing = eAutoOrMaxContentMaxSizing | eMinContentMaxSizing,
450 eFlexMaxSizing = 1 << 7,
451 eFrozen = 1 << 8,
452 eSkipGrowUnlimited1 = 1 << 9,
453 eSkipGrowUnlimited2 = 1 << 10,
454 eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
455 eBreakBefore = 1 << 11,
456 eApplyFitContentClamping = 1 << 12,
457 eInfinitelyGrowable = 1 << 13,
458
459 // These are only used in the masonry axis. They share the same value
460 // as *MinSizing above, but that's OK because we don't use those in
461 // the masonry axis.
462 //
463 // This track corresponds to an item margin-box size that is stretching.
464 eItemStretchSize = 1 << 0,
465 // This bit says that we should clamp that size to mLimit.
466 eClampToLimit = 1 << 1,
467 // This bit says that the corresponding item has `auto` margin(s).
468 eItemHasAutoMargin = 1 << 2,
469 };
470
471 StateBits Initialize(nscoord aPercentageBasis, const StyleTrackSize&);
472 bool IsFrozen() const { return mState & eFrozen; }
473#ifdef DEBUG1
474 static void DumpStateBits(StateBits aState);
475 void Dump() const;
476#endif
477
478 static bool IsDefiniteMaxSizing(StateBits aStateBits) {
479 return (aStateBits & (eIntrinsicMaxSizing | eFlexMaxSizing)) == 0;
480 }
481
482 // Base size of this track.
483 // https://drafts.csswg.org/css-grid-2/#base-size
484 nscoord mBase;
485
486 // Growth limit of this track.
487 // https://drafts.csswg.org/css-grid-2/#growth-limit
488 nscoord mLimit;
489
490 nscoord mPosition; // zero until we apply 'align/justify-content'
491 // mBaselineSubtreeSize is the size of a baseline-aligned subtree within
492 // this track. One subtree per baseline-sharing group (per track).
493 PerBaseline<nscoord> mBaselineSubtreeSize;
494 StateBits mState;
495};
496
497MOZ_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)))); }
498
499static_assert(std::is_trivially_copyable_v<nsGridContainerFrame::TrackSize>,
500 "Must be trivially copyable");
501static_assert(std::is_trivially_destructible_v<nsGridContainerFrame::TrackSize>,
502 "Must be trivially destructible");
503
504TrackSize::StateBits nsGridContainerFrame::TrackSize::Initialize(
505 nscoord aPercentageBasis, const StyleTrackSize& aSize) {
506 using Tag = StyleTrackBreadth::Tag;
507
508 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", 509); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBase == 0 && mLimit == 0 && mState == 0"
") (" "track size data is expected to be initialized to zero"
")"); do { MOZ_CrashSequence(__null, 509); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
509 "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", 509); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mBase == 0 && mLimit == 0 && mState == 0"
") (" "track size data is expected to be initialized to zero"
")"); do { MOZ_CrashSequence(__null, 509); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
510 mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0);
511 mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0);
512
513 auto& min = aSize.GetMin();
514 auto& max = aSize.GetMax();
515
516 Tag minSizeTag = min.tag;
517 Tag maxSizeTag = max.tag;
518 if (aSize.IsFitContent()) {
519 // In layout, fit-content(size) behaves as minmax(auto, max-content), with
520 // 'size' as an additional upper-bound.
521 if (!::IsPercentOfIndefiniteSize(aSize.AsFitContent(), aPercentageBasis)) {
522 mState = eApplyFitContentClamping;
523 }
524 minSizeTag = Tag::Auto;
525 maxSizeTag = Tag::MaxContent;
526 }
527 if (::IsPercentOfIndefiniteSize(min, aPercentageBasis)) {
528 // https://drafts.csswg.org/css-grid-2/#valdef-grid-template-columns-length-percentage-0
529 // "If the inline or block size of the grid container is indefinite,
530 // <percentage> values relative to that size are treated as 'auto'."
531 minSizeTag = Tag::Auto;
532 }
533 if (::IsPercentOfIndefiniteSize(max, aPercentageBasis)) {
534 maxSizeTag = Tag::Auto;
535 }
536
537 // https://drafts.csswg.org/css-grid-2/#algo-init
538 switch (minSizeTag) {
539 case Tag::Auto:
540 mState |= eAutoMinSizing;
541 break;
542 case Tag::MinContent:
543 mState |= eMinContentMinSizing;
544 break;
545 case Tag::MaxContent:
546 mState |= eMaxContentMinSizing;
547 break;
548 default:
549 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"
, 549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!min.IsFlex()"
") (" "<flex> min-sizing is invalid as a track size" ")"
); do { MOZ_CrashSequence(__null, 549); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
550 mBase = ::ResolveToDefiniteSize(min, aPercentageBasis);
551 }
552 switch (maxSizeTag) {
553 case Tag::Auto:
554 mState |= eAutoMaxSizing;
555 mLimit = NS_UNCONSTRAINEDSIZE;
556 break;
557 case Tag::MinContent:
558 case Tag::MaxContent:
559 mState |= maxSizeTag == Tag::MinContent ? eMinContentMaxSizing
560 : eMaxContentMaxSizing;
561 mLimit = NS_UNCONSTRAINEDSIZE;
562 break;
563 case Tag::Flex:
564 mState |= eFlexMaxSizing;
565 mLimit = NS_UNCONSTRAINEDSIZE;
566 break;
567 default:
568 mLimit = ::ResolveToDefiniteSize(max, aPercentageBasis);
569 if (mLimit < mBase) {
570 mLimit = mBase;
571 }
572 }
573 return mState;
574}
575
576// Indicates if we are in intrinsic sizing step 3 (spanning items not
577// spanning any flex tracks) or step 4 (spanning items that span one or more
578// flex tracks).
579// https://drafts.csswg.org/css-grid-2/#algo-content
580enum class TrackSizingStep {
581 NotFlex, // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
582 Flex, // https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
583};
584
585// Sizing phases, used in intrinsic sizing steps 3 and 4.
586// https://drafts.csswg.org/css-grid-2/#algo-spanning-items
587enum class TrackSizingPhase {
588 IntrinsicMinimums,
589 ContentBasedMinimums,
590 MaxContentMinimums,
591 IntrinsicMaximums,
592 MaxContentMaximums,
593};
594
595// Used for grid items intrinsic size types.
596// See CachedIntrinsicSizes which uses this for content contributions.
597enum class GridIntrinsicSizeType {
598 // MinContribution is the "minimum contribution", defined at
599 // https://drafts.csswg.org/css-grid-2/#min-size-contribution
600 MinContribution,
601 MinContentContribution,
602 MaxContentContribution
603};
604
605static constexpr GridIntrinsicSizeType kAllGridIntrinsicSizeTypes[] = {
606 GridIntrinsicSizeType::MinContribution,
607 GridIntrinsicSizeType::MinContentContribution,
608 GridIntrinsicSizeType::MaxContentContribution};
609
610// Glue to make mozilla::EnumeratedArray work with GridIntrinsicSizeType.
611namespace mozilla {
612template <>
613struct MaxContiguousEnumValue<GridIntrinsicSizeType> {
614 static constexpr GridIntrinsicSizeType value =
615 GridIntrinsicSizeType::MaxContentContribution;
616};
617} // namespace mozilla
618
619// Convert a track sizing phase into which GridIntrinsicSizeType is applicable.
620static GridIntrinsicSizeType SizeTypeForPhase(TrackSizingPhase aPhase) {
621 switch (aPhase) {
622 case TrackSizingPhase::IntrinsicMinimums:
623 return GridIntrinsicSizeType::MinContribution;
624 case TrackSizingPhase::ContentBasedMinimums:
625 case TrackSizingPhase::IntrinsicMaximums:
626 return GridIntrinsicSizeType::MinContentContribution;
627 case TrackSizingPhase::MaxContentMinimums:
628 case TrackSizingPhase::MaxContentMaximums:
629 return GridIntrinsicSizeType::MaxContentContribution;
630 }
631 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"
, 631); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 631); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); __builtin_unreachable(); } while (false
)
;
632}
633
634class nsGridContainerFrame::TrackPlan {
635 public:
636 TrackPlan() = default;
637
638 explicit TrackPlan(size_t aCapacity) : mTrackSizes(aCapacity) {}
639
640 TrackPlan(const TrackPlan& aOther) = default;
641
642 TrackPlan(TrackPlan&& aOther) : mTrackSizes(std::move(aOther.mTrackSizes)) {}
643
644 ~TrackPlan() = default;
645
646 TrackPlan& operator=(const TrackPlan& aOther) {
647 mTrackSizes.Assign(aOther.mTrackSizes);
648 return *this;
649 }
650 TrackPlan& operator=(TrackPlan&& aOther) {
651 mTrackSizes.Assign(std::move(aOther.mTrackSizes));
652 return *this;
653 }
654
655 size_t Length() const { return mTrackSizes.Length(); }
656
657 void SetLength(size_t aSize) { mTrackSizes.SetLength(aSize); }
658
659 bool IsEmpty() const { return mTrackSizes.IsEmpty(); }
660
661 void Assign(const TrackPlan& aRHS) { mTrackSizes.Assign(aRHS.mTrackSizes); }
662
663 nsGridContainerFrame::TrackSize* AppendElement(
664 nsGridContainerFrame::TrackSize aElement) {
665 return mTrackSizes.AppendElement(aElement);
666 }
667
668 nsGridContainerFrame::TrackSize& LastElement() {
669 return mTrackSizes.LastElement();
670 }
671
672 nsGridContainerFrame::TrackSize& operator[](size_t aIndex) {
673 return mTrackSizes[aIndex];
674 }
675
676 const nsGridContainerFrame::TrackSize& operator[](size_t aIndex) const {
677 return mTrackSizes[aIndex];
678 }
679
680 void ClearAndRetainStorage() { mTrackSizes.ClearAndRetainStorage(); }
681
682 void ZeroInitialize() {
683 PodZero(mTrackSizes.Elements(), mTrackSizes.Length());
684 }
685
686 using iterator = nsTArray<nsGridContainerFrame::TrackSize>::iterator;
687 iterator begin() { return mTrackSizes.begin(); }
688 iterator end() { return mTrackSizes.end(); }
689
690 using const_iterator =
691 nsTArray<nsGridContainerFrame::TrackSize>::const_iterator;
692 const_iterator begin() const { return mTrackSizes.begin(); }
693 const_iterator end() const { return mTrackSizes.end(); }
694
695 void Initialize(TrackSizingPhase aPhase, const Tracks& aTracks);
696
697 // Distribute space to all flex tracks this item spans.
698 // https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
699 nscoord DistributeToFlexTrackSizes(
700 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
701 const TrackSizingFunctions& aFunctions,
702 const nsGridContainerFrame::Tracks& aTracks);
703
704 private:
705 CopyableTArray<nsGridContainerFrame::TrackSize> mTrackSizes;
706};
707
708using TrackPlan = nsGridContainerFrame::TrackPlan;
709
710class nsGridContainerFrame::ItemPlan {
711 public:
712 ItemPlan() = default;
713
714 explicit ItemPlan(size_t aCapacity) : mTrackSizes(aCapacity) {}
715
716 ~ItemPlan() = default;
717
718 void SetLength(size_t aSize) { mTrackSizes.SetLength(aSize); }
719
720 nsGridContainerFrame::TrackSize& operator[](size_t aIndex) {
721 return mTrackSizes[aIndex];
722 }
723
724 void Initialize(TrackSizingPhase aPhase,
725 const nsTArray<uint32_t>& aGrowableTracks,
726 const nsGridContainerFrame::Tracks& aTracks);
727
728 using FitContentClamper =
729 std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
730
731 /**
732 * Grow the planned size for tracks in aGrowableTracks up to their limit
733 * and then freeze them (all aGrowableTracks must be unfrozen on entry).
734 * Subtract the space added from aAvailableSpace and return that.
735 */
736 nscoord GrowTracksToLimit(nscoord aAvailableSpace,
737 const nsTArray<uint32_t>& aGrowableTracks,
738 const FitContentClamper& aFitContentClamper);
739
740 /**
741 * Helper for GrowSelectedTracksUnlimited. For the set of tracks (S) that
742 * match aMinSizingSelector: if a track in S doesn't match aMaxSizingSelector
743 * then mark it with aSkipFlag. If all tracks in S were marked then unmark
744 * them. Return aNumGrowable minus the number of tracks marked. It is
745 * assumed that this plan has no aSkipFlag set for tracks in aGrowableTracks
746 * on entry to this method.
747 */
748 uint32_t MarkExcludedTracks(uint32_t aNumGrowable,
749 const nsTArray<uint32_t>& aGrowableTracks,
750 TrackSize::StateBits aMinSizingSelector,
751 TrackSize::StateBits aMaxSizingSelector,
752 TrackSize::StateBits aSkipFlag);
753
754 /**
755 * Mark all tracks in aGrowableTracks with an eSkipGrowUnlimited bit if
756 * they *shouldn't* grow unlimited in §12.5.1.2.4 "Distribute space beyond
757 * growth limits" https://drafts.csswg.org/css-grid-2/#extra-space
758 * Return the number of tracks that are still growable.
759 */
760 uint32_t MarkExcludedTracks(TrackSizingPhase aPhase,
761 const nsTArray<uint32_t>& aGrowableTracks,
762 SizingConstraint aConstraint);
763
764 /**
765 * Increase the planned size for tracks in aGrowableTracks that aren't
766 * marked with a eSkipGrowUnlimited flag beyond their limit.
767 * This implements the "Distribute space beyond growth limits" step in
768 * https://drafts.csswg.org/css-grid-2/#distribute-extra-space
769 */
770 void GrowSelectedTracksUnlimited(nscoord aAvailableSpace,
771 const nsTArray<uint32_t>& aGrowableTracks,
772 uint32_t aNumGrowable,
773 const FitContentClamper& aFitContentClamper);
774
775 private:
776 nsTArray<nsGridContainerFrame::TrackSize> mTrackSizes;
777};
778
779using ItemPlan = nsGridContainerFrame::ItemPlan;
780
781/**
782 * A LineRange can be definite or auto - when it's definite it represents
783 * a consecutive set of tracks between a starting line and an ending line.
784 * Before it's definite it can also represent an auto position with a span,
785 * where mStart == kAutoLine and mEnd is the (non-zero positive) span.
786 * For normal-flow items, the invariant mStart < mEnd holds when both
787 * lines are definite.
788 *
789 * For abs.pos. grid items, mStart and mEnd may both be kAutoLine, meaning
790 * "attach this side to the grid container containing block edge".
791 * Additionally, mStart <= mEnd holds when both are definite (non-kAutoLine),
792 * i.e. the invariant is slightly relaxed compared to normal flow items.
793 */
794struct nsGridContainerFrame::LineRange {
795 LineRange(int32_t aStart, int32_t aEnd)
796 : mUntranslatedStart(aStart), mUntranslatedEnd(aEnd) {
797#ifdef DEBUG1
798 if (!IsAutoAuto()) {
799 if (IsAuto()) {
800 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"
, 800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd >= kMinLine && aEnd <= kMaxLine"
") (" "invalid span" ")"); do { MOZ_CrashSequence(__null, 800
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
801 } else {
802 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"
, 803); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart >= kMinLine && aStart <= kMaxLine"
") (" "invalid start line" ")"); do { MOZ_CrashSequence(__null
, 803); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
803 "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"
, 803); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart >= kMinLine && aStart <= kMaxLine"
") (" "invalid start line" ")"); do { MOZ_CrashSequence(__null
, 803); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
804 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"
, 806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 806); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
805 (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"
, 806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 806); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
806 "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"
, 806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEnd == int32_t(kAutoLine) || (aEnd >= kMinLine && aEnd <= kMaxLine)"
") (" "invalid end line" ")"); do { MOZ_CrashSequence(__null
, 806); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
807 }
808 }
809#endif
810 }
811 bool IsAutoAuto() const { return mStart == kAutoLine && mEnd == kAutoLine; }
812 bool IsAuto() const { return mStart == kAutoLine; }
813 bool IsDefinite() const { return mStart != kAutoLine; }
814 uint32_t Extent() const {
815 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"
, 815); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd != kAutoLine"
") (" "Extent is undefined for abs.pos. 'auto'" ")"); do { MOZ_CrashSequence
(__null, 815); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
816 if (IsAuto()) {
817 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", 817
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd >= 1 && mEnd < uint32_t(kMaxLine)"
") (" "invalid span" ")"); do { MOZ_CrashSequence(__null, 817
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
818 return mEnd;
819 }
820 return mEnd - mStart;
821 }
822
823 /**
824 * Return an object suitable for iterating this range.
825 */
826 auto Range() const { return IntegerRange<uint32_t>(mStart, mEnd); }
827
828 /**
829 * Resolve this auto range to start at aStart, making it definite.
830 * @param aClampMaxLine the maximum allowed line number (zero-based)
831 * Precondition: this range IsAuto()
832 */
833 void ResolveAutoPosition(uint32_t aStart, uint32_t aClampMaxLine) {
834 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", 834
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsAuto()" ") (" "Why call me?"
")"); do { MOZ_CrashSequence(__null, 834); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
835 mStart = aStart;
836 mEnd += aStart;
837 // Clamp to aClampMaxLine, which is where kMaxLine is in the explicit
838 // grid in a non-subgrid axis; this implements clamping per
839 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
840 // In a subgrid axis it's the end of the grid in that axis.
841 if (MOZ_UNLIKELY(mStart >= aClampMaxLine)(__builtin_expect(!!(mStart >= aClampMaxLine), 0))) {
842 mEnd = aClampMaxLine;
843 mStart = mEnd - 1;
844 } else if (MOZ_UNLIKELY(mEnd > aClampMaxLine)(__builtin_expect(!!(mEnd > aClampMaxLine), 0))) {
845 mEnd = aClampMaxLine;
846 }
847 }
848 /**
849 * Translate the lines to account for (empty) removed tracks. This method
850 * is only for grid items and should only be called after placement.
851 * aNumRemovedTracks contains a count for each line in the grid how many
852 * tracks were removed between the start of the grid and that line.
853 */
854 void AdjustForRemovedTracks(const nsTArray<uint32_t>& aNumRemovedTracks) {
855 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"
, 855); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine"
") (" "invalid resolved line for a grid item" ")"); do { MOZ_CrashSequence
(__null, 855); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
856 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"
, 856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnd != kAutoLine"
") (" "invalid resolved line for a grid item" ")"); do { MOZ_CrashSequence
(__null, 856); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
857 uint32_t numRemovedTracks = aNumRemovedTracks[mStart];
858 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"
, 859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numRemovedTracks == aNumRemovedTracks[mEnd]"
") (" "tracks that a grid item spans can't be removed" ")");
do { MOZ_CrashSequence(__null, 859); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
859 "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"
, 859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numRemovedTracks == aNumRemovedTracks[mEnd]"
") (" "tracks that a grid item spans can't be removed" ")");
do { MOZ_CrashSequence(__null, 859); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
860 mStart -= numRemovedTracks;
861 mEnd -= numRemovedTracks;
862 }
863 /**
864 * Translate the lines to account for (empty) removed tracks. This method
865 * is only for abs.pos. children and should only be called after placement.
866 * Same as for in-flow items, but we don't touch 'auto' lines here and we
867 * also need to adjust areas that span into the removed tracks.
868 */
869 void AdjustAbsPosForRemovedTracks(
870 const nsTArray<uint32_t>& aNumRemovedTracks) {
871 if (mStart != kAutoLine) {
872 mStart -= aNumRemovedTracks[mStart];
873 }
874 if (mEnd != kAutoLine) {
875 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"
, 875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart == kAutoLine || mEnd > mStart"
") (" "invalid line range" ")"); do { MOZ_CrashSequence(__null
, 875); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
876 mEnd -= aNumRemovedTracks[mEnd];
877 }
878 }
879
880 /**
881 * Return the contribution of this line range for step 2 in
882 * https://drafts.csswg.org/css-grid-2/#auto-placement-algo
883 */
884 uint32_t HypotheticalEnd() const { return mEnd; }
885
886 /**
887 * Given an array of track sizes, return the starting position and length
888 * of the tracks in this line range.
889 */
890 void ToPositionAndLength(const TrackPlan& aTrackPlan, nscoord* aPos,
891 nscoord* aLength) const;
892
893 /**
894 * Given an array of track sizes, return the length of the tracks in this
895 * line range.
896 */
897 nscoord ToLength(const TrackPlan& aTrackPlan) const;
898
899 /**
900 * Given an array of track sizes and a grid origin coordinate, adjust the
901 * abs.pos. containing block along an axis given by aPos and aLength.
902 * aPos and aLength should already be initialized to the grid container
903 * containing block for this axis before calling this method.
904 */
905 void ToPositionAndLengthForAbsPos(const Tracks& aTracks, nscoord aGridOrigin,
906 nscoord* aPos, nscoord* aLength) const;
907
908 void Translate(int32_t aOffset) {
909 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"
, 909); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 909); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
910 mStart += aOffset;
911 mEnd += aOffset;
912 }
913
914 /** Swap the start/end sides of this range. */
915 void ReverseDirection(uint32_t aGridEnd) {
916 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"
, 916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 916); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
917 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", 917);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridEnd >= mEnd"
")"); do { MOZ_CrashSequence(__null, 917); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
918 uint32_t newStart = aGridEnd - mEnd;
919 mEnd = aGridEnd - mStart;
920 mStart = newStart;
921 }
922
923 /**
924 * @note We'll use the signed member while resolving definite positions
925 * to line numbers (1-based), which may become negative for implicit lines
926 * to the top/left of the explicit grid. PlaceGridItems() then translates
927 * the whole grid to a 0,0 origin and we'll use the unsigned member from
928 * there on.
929 */
930 union {
931 uint32_t mStart;
932 int32_t mUntranslatedStart;
933 };
934 union {
935 uint32_t mEnd;
936 int32_t mUntranslatedEnd;
937 };
938
939 protected:
940 LineRange() : mStart(0), mEnd(0) {}
941};
942
943/**
944 * Helper class to construct a LineRange from translated lines.
945 * The ctor only accepts translated definite line numbers.
946 */
947struct nsGridContainerFrame::TranslatedLineRange : public LineRange {
948 TranslatedLineRange(uint32_t aStart, uint32_t aEnd) {
949 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"
, 949); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStart < aEnd && aEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 949); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
950 mStart = aStart;
951 mEnd = aEnd;
952 }
953};
954
955/**
956 * A GridArea is the area in the grid for a grid item.
957 * The area is represented by two LineRanges, both of which can be auto
958 * (@see LineRange) in intermediate steps while the item is being placed.
959 * @see PlaceGridItems
960 */
961struct nsGridContainerFrame::GridArea {
962 GridArea(const LineRange& aCols, const LineRange& aRows)
963 : mCols(aCols), mRows(aRows) {}
964 bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
965 LineRange& LineRangeForAxis(LogicalAxis aAxis) {
966 return aAxis == LogicalAxis::Inline ? mCols : mRows;
967 }
968 const LineRange& LineRangeForAxis(LogicalAxis aAxis) const {
969 return aAxis == LogicalAxis::Inline ? mCols : mRows;
970 }
971 LineRange mCols;
972 LineRange mRows;
973};
974
975struct nsGridContainerFrame::GridItemInfo {
976 /**
977 * Item state per axis.
978 */
979 enum StateBits : uint16_t {
980 // Does the item span a flex track?
981 eIsFlexing = 0x1,
982
983 // First or last baseline alignment preference. They are mutually exclusive.
984 // This does *NOT* represent the baseline alignment group. See the member
985 // variable for that.
986 // <https://drafts.csswg.org/css-align-3/#baseline-alignment-preference>
987 eFirstBaseline = 0x2,
988 eLastBaseline = 0x4,
989 eIsBaselineAligned = eFirstBaseline | eLastBaseline,
990
991 // One of e[Self|Content]Baseline is set when eIsBaselineAligned is true
992 eSelfBaseline = 0x8, // is it *-self:[last ]baseline alignment?
993 // Ditto *-content:[last ]baseline. Mutually exclusive w. eSelfBaseline.
994 eContentBaseline = 0x10,
995
996 // The baseline affects the margin or padding on the item's end side when
997 // this bit is set. In a grid-axis it's always set for eLastBaseline and
998 // always unset for eFirstBaseline. In a masonry-axis, it's set for
999 // baseline groups in the EndStretch set and unset for the StartStretch set.
1000 eEndSideBaseline = 0x20,
1001
1002 // Set when the grid item is in the last baseline sharing group, otherwise
1003 // assume the first baseline sharing group. The baseline sharing group might
1004 // differ from the specified baseline alignment due to baseline alignment
1005 // rules.
1006 eLastBaselineSharingGroup = 0x40,
1007
1008 eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline |
1009 eEndSideBaseline | eLastBaselineSharingGroup,
1010
1011 // Automatic Minimum Size is content based. If not set, automatic minimum
1012 // size is zero.
1013 // https://drafts.csswg.org/css-grid-2/#min-size-auto
1014 // https://drafts.csswg.org/css-grid-2/#content-based-minimum-size
1015 eContentBasedAutoMinSize = 0x80,
1016 // Clamp per https://drafts.csswg.org/css-grid-2/#min-size-auto
1017 eClampMarginBoxMinSize = 0x100,
1018 eIsSubgrid = 0x200,
1019 // set on subgrids and items in subgrids if they are adjacent to the grid
1020 // start/end edge (excluding grid-aligned abs.pos. frames)
1021 eStartEdge = 0x400,
1022 eEndEdge = 0x800,
1023 eEdgeBits = eStartEdge | eEndEdge,
1024 // Set if this item was auto-placed in this axis.
1025 eAutoPlacement = 0x1000,
1026 // Set if this item is the last item in its track (masonry layout only)
1027 eIsLastItemInMasonryTrack = 0x2000,
1028
1029 // Bits set during the track sizing step.
1030 eTrackSizingBits =
1031 eIsFlexing | eContentBasedAutoMinSize | eClampMarginBoxMinSize,
1032 };
1033
1034 GridItemInfo(nsIFrame* aFrame, const GridArea& aArea);
1035
1036 GridItemInfo(const GridItemInfo& aOther)
1037 : mFrame(aOther.mFrame), mArea(aOther.mArea) {
1038 mBaselineOffset = aOther.mBaselineOffset;
1039 mState = aOther.mState;
1040 }
1041
1042 GridItemInfo& operator=(const GridItemInfo&) = delete;
1043
1044 static bool BaselineAlignmentAffectsEndSide(StateBits state) {
1045 return state & StateBits::eEndSideBaseline;
1046 }
1047
1048 /**
1049 * Inhibit subgrid layout unless the item is placed in the first "track" in
1050 * a parent masonry-axis, or has definite placement or spans all tracks in
1051 * the parent grid-axis.
1052 * TODO: this is stricter than what the Masonry proposal currently states
1053 * (bug 1627581)
1054 */
1055 void MaybeInhibitSubgridInMasonry(nsGridContainerFrame* aParent,
1056 uint32_t aGridAxisTrackCount);
1057
1058 /**
1059 * Inhibit subgridding in aAxis for this item.
1060 */
1061 void InhibitSubgrid(nsGridContainerFrame* aParent, LogicalAxis aAxis);
1062
1063 /**
1064 * Return a copy of this item with its row/column data swapped.
1065 */
1066 GridItemInfo Transpose() const {
1067 GridItemInfo info(mFrame, GridArea(mArea.mRows, mArea.mCols));
1068 info.mState[LogicalAxis::Block] = mState[LogicalAxis::Inline];
1069 info.mState[LogicalAxis::Inline] = mState[LogicalAxis::Block];
1070 info.mBaselineOffset[LogicalAxis::Block] =
1071 mBaselineOffset[LogicalAxis::Inline];
1072 info.mBaselineOffset[LogicalAxis::Inline] =
1073 mBaselineOffset[LogicalAxis::Block];
1074 return info;
1075 }
1076
1077 // Reset bits in mState in aAxis that were set during the track sizing step.
1078 void ResetTrackSizingBits(LogicalAxis aAxis);
1079
1080 /** Swap the start/end sides in aAxis. */
1081 inline void ReverseDirection(LogicalAxis aAxis, uint32_t aGridEnd);
1082
1083 // Is this item a subgrid in the given container axis?
1084 bool IsSubgrid(LogicalAxis aAxis) const {
1085 return mState[aAxis] & StateBits::eIsSubgrid;
1086 }
1087
1088 // Is this item a subgrid in either axis?
1089 bool IsSubgrid() const {
1090 return IsSubgrid(LogicalAxis::Inline) || IsSubgrid(LogicalAxis::Block);
1091 }
1092
1093 // Return the (inner) grid container frame associated with this subgrid item.
1094 nsGridContainerFrame* SubgridFrame() const {
1095 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"
, 1095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 1095); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1096 nsGridContainerFrame* gridFrame = GetGridContainerFrame(mFrame);
1097 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", 1097)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridFrame && gridFrame->IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 1097); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1098 return gridFrame;
1099 }
1100
1101 /**
1102 * Adjust our grid areas to account for removed auto-fit tracks in aAxis.
1103 */
1104 void AdjustForRemovedTracks(LogicalAxis aAxis,
1105 const nsTArray<uint32_t>& aNumRemovedTracks);
1106
1107 /**
1108 * If the item is [align|justify]-self:[last ]baseline aligned in the given
1109 * axis then set aBaselineOffset to the baseline offset and return aAlign.
1110 * Otherwise, return a fallback alignment.
1111 */
1112 StyleAlignFlags GetSelfBaseline(StyleAlignFlags aAlign, LogicalAxis aAxis,
1113 nscoord* aBaselineOffset) const {
1114 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", 1115)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
")"); do { MOZ_CrashSequence(__null, 1115); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1115 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", 1115)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlign == StyleAlignFlags::BASELINE || aAlign == StyleAlignFlags::LAST_BASELINE"
")"); do { MOZ_CrashSequence(__null, 1115); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1116 if (!(mState[aAxis] & eSelfBaseline)) {
1117 return aAlign == StyleAlignFlags::BASELINE ? StyleAlignFlags::SELF_START
1118 : StyleAlignFlags::SELF_END;
1119 }
1120 *aBaselineOffset = mBaselineOffset[aAxis];
1121 return aAlign;
1122 }
1123
1124 // Return true if we should use MinContribution on items that do not span
1125 // any flex tracks to determine the minimum contribution, and if we should
1126 // set the eContentBasedAutoMinSize flag on grid items.
1127 //
1128 // In part this is determined by whether or not the minimum contribution
1129 // of the item is content-based.
1130 // https://drafts.csswg.org/css-grid-2/#min-size-auto
1131 //
1132 // @note the caller should also check that the item has a span length of 1,
1133 // and that the item's track has a min track sizing function that is 'auto'.
1134 bool MinContributionDependsOnAutoMinSize(WritingMode aContainerWM,
1135 LogicalAxis aContainerAxis) const {
1136 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", 1138
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1138); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1137 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", 1138
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1138); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1138 "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", 1138
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mArea.LineRangeForAxis(aContainerAxis).Extent() == 1"
") (" "Should not be called with grid items that span multiple tracks."
")"); do { MOZ_CrashSequence(__null, 1138); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1139 const LogicalAxis itemAxis =
1140 aContainerWM.ConvertAxisTo(aContainerAxis, mFrame->GetWritingMode());
1141 const auto* styleFrame = mFrame->IsTableWrapperFrame()
1142 ? mFrame->PrincipalChildList().FirstChild()
1143 : mFrame;
1144 const auto* pos = styleFrame->StylePosition();
1145 const auto anchorResolutionParams =
1146 AnchorPosResolutionParams::From(styleFrame);
1147 const auto size =
1148 pos->Size(aContainerAxis, aContainerWM, anchorResolutionParams);
1149 // max-content and min-content should behave as initial value in block axis.
1150 // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
1151 // for block size dimension on sizing properties (e.g. height), so we
1152 // treat it as `auto`.
1153 bool isAuto = size->BehavesLikeInitialValue(itemAxis);
1154 // This check for HasPercent is intended to correspond to whether or not
1155 // the item's preferred size depends on the size of its containing block.
1156 //
1157 // TODO alaskanemily: This probably shouldn't be a special case here.
1158 // This is part of how EnsureContributions with the MinSize flag is
1159 // implemented, where this forces ResolveIntrinsicSizeForNonSpanningItems
1160 // to use MinSize instead of Min/MaxContentContribution, which
1161 // EnsureContributions will then translate to/from MinContentContribution
1162 //
1163 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
1164 // Section "For auto minimums"
1165 if (!isAuto && !size->HasPercent()) {
1166 return false;
1167 }
1168 const auto minSize =
1169 pos->MinSize(aContainerAxis, aContainerWM, anchorResolutionParams);
1170 // max-content and min-content should behave as initial value in block axis.
1171 // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
1172 // for block size dimension on sizing properties (e.g. height), so we
1173 // treat it as `auto`.
1174 isAuto = minSize->BehavesLikeInitialValue(itemAxis);
1175 return isAuto && !mFrame->StyleDisplay()->IsScrollableOverflow();
1176 }
1177
1178#ifdef DEBUG1
1179 void Dump() const;
1180#endif
1181
1182 static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b) {
1183 return a->mArea.mRows.mStart < b->mArea.mRows.mStart;
1184 }
1185
1186 // Sorting functions for 'masonry-auto-flow:next'. We sort the items that
1187 // were placed into the first track by the Grid placement algorithm first
1188 // (to honor that placement). All other items will be placed by the Masonry
1189 // layout algorithm (their Grid placement in the masonry axis is irrelevant).
1190 static bool RowMasonryOrdered(const GridItemInfo* a, const GridItemInfo* b) {
1191 return a->mArea.mRows.mStart == 0 && b->mArea.mRows.mStart != 0 &&
1192 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1193 }
1194 static bool ColMasonryOrdered(const GridItemInfo* a, const GridItemInfo* b) {
1195 return a->mArea.mCols.mStart == 0 && b->mArea.mCols.mStart != 0 &&
1196 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1197 }
1198
1199 // Sorting functions for 'masonry-auto-flow:definite-first'. Similar to
1200 // the above, but here we also sort items with a definite item placement in
1201 // the grid axis in track order before 'auto'-placed items. We also sort all
1202 // continuations first since they use the same placement as their
1203 // first-in-flow (we treat them as "definite" regardless of eAutoPlacement).
1204 static bool RowMasonryDefiniteFirst(const GridItemInfo* a,
1205 const GridItemInfo* b) {
1206 bool isContinuationA = a->mFrame->GetPrevInFlow();
1207 bool isContinuationB = b->mFrame->GetPrevInFlow();
1208 if (isContinuationA != isContinuationB) {
1209 return isContinuationA;
1210 }
1211 auto masonryA = a->mArea.mRows.mStart;
1212 auto gridA = a->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
1213 auto masonryB = b->mArea.mRows.mStart;
1214 auto gridB = b->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
1215 return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
1216 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1217 }
1218 static bool ColMasonryDefiniteFirst(const GridItemInfo* a,
1219 const GridItemInfo* b) {
1220 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"
, 1221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
") (" "fragmentation not supported in inline axis" ")"); do {
MOZ_CrashSequence(__null, 1221); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1221 "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"
, 1221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow()"
") (" "fragmentation not supported in inline axis" ")"); do {
MOZ_CrashSequence(__null, 1221); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1222 auto masonryA = a->mArea.mCols.mStart;
1223 auto gridA = a->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
1224 auto masonryB = b->mArea.mCols.mStart;
1225 auto gridB = b->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
1226 return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
1227 !a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1228 }
1229
1230 // Return true if this items block size is dependent on the size of the
1231 // container it is in.
1232 bool IsBSizeDependentOnContainerSize(WritingMode aContainerWM) const {
1233 const auto IsDependentOnContainerSize = [](const auto& size) -> bool {
1234 // XXXdholbert The BehavesLikeStretchOnInlineAxis usage seems like
1235 // maybe it should be considering block-axis instead?
1236 return size.HasPercent() || size.BehavesLikeStretchOnInlineAxis();
1237 };
1238
1239 const nsStylePosition* stylePos = mFrame->StylePosition();
1240 const auto anchorResolutionParams = AnchorPosResolutionParams::From(mFrame);
1241 bool isItemAutoSize = IsDependentOnContainerSize(*stylePos->BSize(
1242 aContainerWM, anchorResolutionParams)) ||
1243 IsDependentOnContainerSize(*stylePos->MinBSize(
1244 aContainerWM, anchorResolutionParams)) ||
1245 IsDependentOnContainerSize(*stylePos->MaxBSize(
1246 aContainerWM, anchorResolutionParams));
1247
1248 return isItemAutoSize;
1249 }
1250
1251 nsIFrame* const mFrame;
1252 GridArea mArea;
1253
1254 // Offset from the margin edge to the baseline (LogicalAxis index). It's from
1255 // the start edge for first baseline sharing group, otherwise from the end
1256 // edge.
1257 // It's mutable since we update the value fairly late (just before reflowing
1258 // the item).
1259 mutable PerLogicalAxis<nscoord> mBaselineOffset;
1260
1261 // State bits per axis.
1262 mutable PerLogicalAxis<StateBits> mState;
1263};
1264
1265using GridItemInfo = nsGridContainerFrame::GridItemInfo;
1266using ItemState = GridItemInfo::StateBits;
1267MOZ_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))));
}
1268
1269GridItemInfo::GridItemInfo(nsIFrame* aFrame, const GridArea& aArea)
1270 : mFrame(aFrame), mArea(aArea), mBaselineOffset{0, 0} {
1271 mState[LogicalAxis::Block] =
1272 StateBits(mArea.mRows.mStart == kAutoLine ? eAutoPlacement : 0);
1273 mState[LogicalAxis::Inline] =
1274 StateBits(mArea.mCols.mStart == kAutoLine ? eAutoPlacement : 0);
1275
1276 if (auto* gridFrame = GetGridContainerFrame(mFrame)) {
1277 auto parentWM = aFrame->GetParent()->GetWritingMode();
1278 bool isOrthogonal = parentWM.IsOrthogonalTo(gridFrame->GetWritingMode());
1279 if (gridFrame->IsColSubgrid()) {
1280 mState[isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline] |=
1281 StateBits::eIsSubgrid;
1282 }
1283 if (gridFrame->IsRowSubgrid()) {
1284 mState[isOrthogonal ? LogicalAxis::Inline : LogicalAxis::Block] |=
1285 StateBits::eIsSubgrid;
1286 }
1287 }
1288}
1289
1290void GridItemInfo::ResetTrackSizingBits(LogicalAxis aAxis) {
1291 mState[aAxis] &= ~StateBits::eTrackSizingBits;
1292}
1293
1294void GridItemInfo::ReverseDirection(LogicalAxis aAxis, uint32_t aGridEnd) {
1295 mArea.LineRangeForAxis(aAxis).ReverseDirection(aGridEnd);
1296 ItemState& state = mState[aAxis];
1297 ItemState newState = state & ~ItemState::eEdgeBits;
1298 if (state & ItemState::eStartEdge) {
1299 newState |= ItemState::eEndEdge;
1300 }
1301 if (state & ItemState::eEndEdge) {
1302 newState |= ItemState::eStartEdge;
1303 }
1304 state = newState;
1305}
1306
1307void GridItemInfo::InhibitSubgrid(nsGridContainerFrame* aParent,
1308 LogicalAxis aAxis) {
1309 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", 1309)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid(aAxis)" ")"
); do { MOZ_CrashSequence(__null, 1309); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1310 auto bit = NS_STATE_GRID_IS_COL_SUBGRID;
1311 if (aParent->GetWritingMode().IsOrthogonalTo(mFrame->GetWritingMode()) !=
1312 (aAxis == LogicalAxis::Block)) {
1313 bit = NS_STATE_GRID_IS_ROW_SUBGRID;
1314 }
1315 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", 1315)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "SubgridFrame()->HasAnyStateBits(bit)"
")"); do { MOZ_CrashSequence(__null, 1315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1316 SubgridFrame()->RemoveStateBits(bit);
1317 mState[aAxis] &= StateBits(~StateBits::eIsSubgrid);
1318}
1319
1320void GridItemInfo::MaybeInhibitSubgridInMasonry(nsGridContainerFrame* aParent,
1321 uint32_t aGridAxisTrackCount) {
1322 if (IsSubgrid(LogicalAxis::Inline) && aParent->IsRowMasonry() &&
1323 mArea.mRows.mStart != 0 && mArea.mCols.Extent() != aGridAxisTrackCount &&
1324 (mState[LogicalAxis::Inline] & eAutoPlacement)) {
1325 InhibitSubgrid(aParent, LogicalAxis::Inline);
1326 return;
1327 }
1328 if (IsSubgrid(LogicalAxis::Block) && aParent->IsColMasonry() &&
1329 mArea.mCols.mStart != 0 && mArea.mRows.Extent() != aGridAxisTrackCount &&
1330 (mState[LogicalAxis::Block] & eAutoPlacement)) {
1331 InhibitSubgrid(aParent, LogicalAxis::Block);
1332 }
1333}
1334
1335// Each subgrid stores this data about its items etc on a frame property.
1336struct nsGridContainerFrame::Subgrid {
1337 Subgrid(const GridArea& aArea, bool aIsOrthogonal, WritingMode aCBWM)
1338 : mArea(aArea),
1339 mGridColEnd(0),
1340 mGridRowEnd(0),
1341 mMarginBorderPadding(aCBWM),
1342 mIsOrthogonal(aIsOrthogonal) {}
1343
1344 // Return the relevant line range for the subgrid column axis.
1345 const LineRange& SubgridCols() const {
1346 return mIsOrthogonal ? mArea.mRows : mArea.mCols;
1347 }
1348 // Return the relevant line range for the subgrid row axis.
1349 const LineRange& SubgridRows() const {
1350 return mIsOrthogonal ? mArea.mCols : mArea.mRows;
1351 }
1352
1353 // The subgrid's items.
1354 nsTArray<GridItemInfo> mGridItems;
1355 // The subgrid's abs.pos. items.
1356 nsTArray<GridItemInfo> mAbsPosItems;
1357 // The subgrid's area as a grid item, i.e. in its parent's grid space.
1358 GridArea mArea;
1359 // The (inner) grid size for the subgrid, zero-based.
1360 uint32_t mGridColEnd;
1361 uint32_t mGridRowEnd;
1362 // The margin+border+padding for the subgrid box in its parent grid's WM.
1363 // (This also includes the size of any scrollbars.)
1364 LogicalMargin mMarginBorderPadding;
1365 // Does the subgrid frame have orthogonal writing-mode to its parent grid
1366 // container?
1367 bool mIsOrthogonal;
1368
1369 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, Subgrid)static const mozilla::FramePropertyDescriptor<Subgrid>*
Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<Subgrid>::NewWithDestructor<DeleteValue>(); return
&descriptor; }
1370};
1371using Subgrid = nsGridContainerFrame::Subgrid;
1372
1373void GridItemInfo::AdjustForRemovedTracks(
1374 LogicalAxis aAxis, const nsTArray<uint32_t>& aNumRemovedTracks) {
1375 const bool abspos = mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
1376 auto& lines = mArea.LineRangeForAxis(aAxis);
1377 if (abspos) {
1378 lines.AdjustAbsPosForRemovedTracks(aNumRemovedTracks);
1379 } else {
1380 lines.AdjustForRemovedTracks(aNumRemovedTracks);
1381 }
1382 if (IsSubgrid()) {
1383 auto* subgrid = SubgridFrame()->GetProperty(Subgrid::Prop());
1384 if (subgrid) {
1385 auto& lines = subgrid->mArea.LineRangeForAxis(aAxis);
1386 if (abspos) {
1387 lines.AdjustAbsPosForRemovedTracks(aNumRemovedTracks);
1388 } else {
1389 lines.AdjustForRemovedTracks(aNumRemovedTracks);
1390 }
1391 }
1392 }
1393}
1394
1395/**
1396 * Track size data for use by subgrids (which don't do sizing of their own
1397 * in a subgridded axis). A non-subgrid container stores its resolved sizes,
1398 * but only if it has any subgrid children. A subgrid always stores one.
1399 * In a subgridded axis, we copy the parent's sizes (see CopyUsedTrackSizes).
1400 *
1401 * This struct us stored on a frame property, which may be null before the track
1402 * sizing step for the given container. A null property is semantically
1403 * equivalent to mCanResolveLineRangeSize being false in both axes.
1404 * @note the axis used to access this data is in the grid container's own
1405 * writing-mode, same as in other track-sizing functions.
1406 */
1407struct nsGridContainerFrame::UsedTrackSizes {
1408 UsedTrackSizes() = default;
1409
1410 /**
1411 * Setup mTrackPlans by copying track sizes from aFrame's grid container
1412 * parent when aAxis is subgridded (and recurse if the parent is a subgrid
1413 * that doesn't have sizes yet), or by running the Track Sizing Algo when
1414 * the axis is not subgridded (for a subgrid).
1415 * Set mCanResolveLineRangeSize[aAxis] to true once we have obtained
1416 * sizes for an axis (if it's already true then this method is a NOP).
1417 */
1418 void ResolveTrackSizesForAxis(nsGridContainerFrame* aFrame, LogicalAxis aAxis,
1419 gfxContext& aRC);
1420
1421 /** Helper function for the above method */
1422 void ResolveSubgridTrackSizesForAxis(nsGridContainerFrame* aFrame,
1423 LogicalAxis aAxis, Subgrid* aSubgrid,
1424 gfxContext& aRC,
1425 nscoord aContentBoxSize);
1426
1427 // This only has valid sizes when mCanResolveLineRangeSize is true in
1428 // the same axis. It may have zero tracks (a grid with only abs.pos.
1429 // subgrids/items may have zero tracks).
1430 PerLogicalAxis<TrackPlan> mTrackPlans;
1431 // True if mTrackPlans can be used to resolve line range sizes in an axis.
1432 PerLogicalAxis<bool> mCanResolveLineRangeSize{false, false};
1433
1434 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, UsedTrackSizes)static const mozilla::FramePropertyDescriptor<UsedTrackSizes
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<UsedTrackSizes>::NewWithDestructor<DeleteValue>(
); return &descriptor; }
1435};
1436using UsedTrackSizes = nsGridContainerFrame::UsedTrackSizes;
1437
1438#ifdef DEBUG1
1439void nsGridContainerFrame::GridItemInfo::Dump() const {
1440 auto Dump1 = [this](const char* aMsg, LogicalAxis aAxis) {
1441 auto state = mState[aAxis];
1442 if (!state) {
1443 return;
1444 }
1445 printf("%s", aMsg);
1446 if (state & ItemState::eEdgeBits) {
1447 printf("subgrid-adjacent-edges(");
1448 if (state & ItemState::eStartEdge) {
1449 printf("start ");
1450 }
1451 if (state & ItemState::eEndEdge) {
1452 printf("end");
1453 }
1454 printf(") ");
1455 }
1456 if (state & ItemState::eAutoPlacement) {
1457 printf("masonry-auto ");
1458 }
1459 if (state & ItemState::eIsSubgrid) {
1460 printf("subgrid ");
1461 }
1462 if (state & ItemState::eIsFlexing) {
1463 printf("flexing ");
1464 }
1465 if (state & ItemState::eContentBasedAutoMinSize) {
1466 printf("auto-min-size ");
1467 }
1468 if (state & ItemState::eClampMarginBoxMinSize) {
1469 printf("clamp ");
1470 }
1471 if (state & ItemState::eIsLastItemInMasonryTrack) {
1472 printf("last-in-track ");
1473 }
1474 if (state & ItemState::eFirstBaseline) {
1475 printf("first baseline %s-alignment ",
1476 (state & ItemState::eSelfBaseline) ? "self" : "content");
1477 }
1478 if (state & ItemState::eLastBaseline) {
1479 printf("last baseline %s-alignment ",
1480 (state & ItemState::eSelfBaseline) ? "self" : "content");
1481 }
1482 if (state & ItemState::eIsBaselineAligned) {
1483 printf("%.2fpx", NSAppUnitsToFloatPixels(mBaselineOffset[aAxis],
1484 AppUnitsPerCSSPixel()));
1485 }
1486 printf("\n");
1487 };
1488 printf("grid-row: %d %d\n", mArea.mRows.mStart, mArea.mRows.mEnd);
1489 Dump1(" grid block-axis: ", LogicalAxis::Block);
1490 printf("grid-column: %d %d\n", mArea.mCols.mStart, mArea.mCols.mEnd);
1491 Dump1(" grid inline-axis: ", LogicalAxis::Inline);
1492}
1493#endif
1494
1495/**
1496 * Encapsulates CSS track-sizing functions.
1497 */
1498struct nsGridContainerFrame::TrackSizingFunctions {
1499 private:
1500 TrackSizingFunctions(const GridTemplate& aTemplate,
1501 const StyleImplicitGridTracks& aAutoSizing,
1502 const Maybe<size_t>& aRepeatAutoIndex, bool aIsSubgrid)
1503 : mTemplate(aTemplate),
1504 mTrackListValues(aTemplate.TrackListValues()),
1505 mAutoSizing(aAutoSizing),
1506 mExplicitGridOffset(0),
1507 mRepeatAutoStart(aRepeatAutoIndex.valueOr(0)),
1508 mRepeatAutoEnd(mRepeatAutoStart),
1509 mHasRepeatAuto(aRepeatAutoIndex.isSome()) {
1510 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", 1511
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || !aIsSubgrid"
") (" "a track-list for a subgrid can't have an <auto-repeat> track"
")"); do { MOZ_CrashSequence(__null, 1511); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1511 "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", 1511
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || !aIsSubgrid"
") (" "a track-list for a subgrid can't have an <auto-repeat> track"
")"); do { MOZ_CrashSequence(__null, 1511); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1512 if (!aIsSubgrid) {
1513 ExpandNonRepeatAutoTracks();
1514 }
1515 if (mHasRepeatAuto) {
1516 if (NumRepeatTracks() == 0) [[unlikely]] {
1517 // We ran out of room before expanding the `repeat(auto-fill/fit)`
1518 // track, so it's outside the clamped grid.
1519 mHasRepeatAuto = false;
1520 } else {
1521 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", 1521)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRepeatAutoStart < mExpandedTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 1521); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1522 }
1523 }
1524 }
1525
1526 public:
1527 TrackSizingFunctions(const GridTemplate& aGridTemplate,
1528 const StyleImplicitGridTracks& aAutoSizing,
1529 bool aIsSubgrid)
1530 : TrackSizingFunctions(aGridTemplate, aAutoSizing,
1531 aGridTemplate.RepeatAutoIndex(), aIsSubgrid) {}
1532
1533 private:
1534 enum { ForSubgridFallbackTag };
1535 TrackSizingFunctions(const GridTemplate& aGridTemplate,
1536 const StyleImplicitGridTracks& aAutoSizing,
1537 decltype(ForSubgridFallbackTag))
1538 : TrackSizingFunctions(aGridTemplate, aAutoSizing, Nothing(),
1539 /* aIsSubgrid */ true) {}
1540
1541 public:
1542 /**
1543 * This is used in a subgridded axis to resolve sizes before its parent's
1544 * sizes are known for intrinsic sizing purposes. It copies the slice of
1545 * the nearest non-subgridded axis' track sizing functions spanned by
1546 * the subgrid.
1547 *
1548 * FIXME: this was written before there was a spec... the spec now says:
1549 * "If calculating the layout of a grid item in this step depends on
1550 * the available space in the block axis, assume the available space
1551 * that it would have if any row with a definite max track sizing
1552 * function had that size and all other rows were infinite."
1553 * https://drafts.csswg.org/css-grid-2/#subgrid-sizing
1554 */
1555 static TrackSizingFunctions ForSubgridFallback(
1556 nsGridContainerFrame* aSubgridFrame, const Subgrid* aSubgrid,
1557 nsGridContainerFrame* aParentGridContainer, LogicalAxis aParentAxis) {
1558 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"
, 1558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgrid" ")"
); do { MOZ_CrashSequence(__null, 1558); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1559 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", 1561)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1560 ? 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", 1561)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1561 : 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", 1561)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->IsSubgrid(aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aParentAxis) : aParentAxis)"
")"); do { MOZ_CrashSequence(__null, 1561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1562 nsGridContainerFrame* parent = aParentGridContainer;
1563 auto parentAxis = aParentAxis;
1564 LineRange range = aSubgrid->mArea.LineRangeForAxis(parentAxis);
1565 // Find our nearest non-subgridded axis and use its track sizing functions.
1566 while (parent->IsSubgrid(parentAxis)) {
1567 const auto* parentSubgrid = parent->GetProperty(Subgrid::Prop());
1568 auto* grandParent = parent->ParentGridContainerForSubgrid();
1569 auto grandParentWM = grandParent->GetWritingMode();
1570 bool isSameDirInAxis =
1571 parent->GetWritingMode().ParallelAxisStartsOnSameSide(parentAxis,
1572 grandParentWM);
1573 if (MOZ_UNLIKELY(!isSameDirInAxis)(__builtin_expect(!!(!isSameDirInAxis), 0))) {
1574 auto end = parentAxis == LogicalAxis::Block
1575 ? parentSubgrid->mGridRowEnd
1576 : parentSubgrid->mGridColEnd;
1577 range.ReverseDirection(end);
1578 // range is now in the same direction as the grand-parent's axis
1579 }
1580 auto grandParentAxis = parentSubgrid->mIsOrthogonal
1581 ? GetOrthogonalAxis(parentAxis)
1582 : parentAxis;
1583 const auto& parentRange =
1584 parentSubgrid->mArea.LineRangeForAxis(grandParentAxis);
1585 range.Translate(parentRange.mStart);
1586 // range is now in the grand-parent's coordinates
1587 parentAxis = grandParentAxis;
1588 parent = grandParent;
1589 }
1590 const auto* pos = parent->StylePosition();
1591 const auto isInlineAxis = parentAxis == LogicalAxis::Inline;
1592 const auto& szf =
1593 isInlineAxis ? pos->mGridTemplateRows : pos->mGridTemplateColumns;
1594 const auto& autoSizing =
1595 isInlineAxis ? pos->mGridAutoColumns : pos->mGridAutoRows;
1596 return TrackSizingFunctions(szf, autoSizing, ForSubgridFallbackTag);
1597 }
1598
1599 /**
1600 * Initialize the number of auto-fill/fit tracks to use.
1601 * This can be zero if no auto-fill/fit track was specified, or if the repeat
1602 * begins after the maximum allowed track.
1603 */
1604 void InitRepeatTracks(const NonNegativeLengthPercentageOrNormal& aGridGap,
1605 nscoord aMinSize, nscoord aSize, nscoord aMaxSize) {
1606 // Check for a repeat after the maximum allowed track.
1607 if (MOZ_UNLIKELY(mRepeatAutoStart >= kMaxTrack)(__builtin_expect(!!(mRepeatAutoStart >= kMaxTrack), 0))) {
1608 mHasRepeatAuto = false;
1609 mRepeatAutoStart = 0;
1610 mRepeatAutoEnd = 0;
1611 return;
1612 }
1613 uint32_t repeatTracks =
1614 CalculateRepeatFillCount(aGridGap, aMinSize, aSize, aMaxSize) *
1615 NumRepeatTracks();
1616 // Clamp the number of repeat tracks to the maximum possible track.
1617 repeatTracks = std::min(repeatTracks, kMaxTrack - mRepeatAutoStart);
1618 SetNumRepeatTracks(repeatTracks);
1619 // Blank out the removed flags for each of these tracks.
1620 mRemovedRepeatTracks.SetLength(repeatTracks);
1621 for (auto& track : mRemovedRepeatTracks) {
1622 track = false;
1623 }
1624 }
1625
1626 uint32_t CalculateRepeatFillCount(
1627 const NonNegativeLengthPercentageOrNormal& aGridGap, nscoord aMinSize,
1628 nscoord aSize, nscoord aMaxSize) const {
1629 if (!mHasRepeatAuto) {
1630 return 0;
1631 }
1632 // At this point no tracks will have been collapsed, so the RepeatEndDelta
1633 // should not be negative.
1634 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", 1634)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "RepeatEndDelta() >= 0"
")"); do { MOZ_CrashSequence(__null, 1634); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1635 // Note that this uses NumRepeatTracks and mRepeatAutoStart/End, although
1636 // the result of this method is used to change those values to a fully
1637 // expanded value. Spec quotes are from
1638 // https://drafts.csswg.org/css-grid-2/#repeat-notation
1639 const uint32_t numTracks = mExpandedTracks.Length() + RepeatEndDelta();
1640 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"
, 1640); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numTracks >= 1"
") (" "expected at least the repeat() track" ")"); do { MOZ_CrashSequence
(__null, 1640); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1641 if (MOZ_UNLIKELY(numTracks >= kMaxLine)(__builtin_expect(!!(numTracks >= kMaxLine), 0))) {
1642 // The fixed tracks plus an entire repetition is either larger or as
1643 // large as the maximum track, so we do not need to measure how many
1644 // repetitions will fit. This also avoids needing to check for if
1645 // kMaxLine - numTracks would underflow at the end where we clamp the
1646 // result.
1647 return 1;
1648 }
1649 nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize;
1650 if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) {
1651 // "Otherwise, the specified track list repeats only once."
1652 return 1;
1653 }
1654 nscoord repeatTrackSum = 0;
1655 // Note that one repeat() track size is included in |sum| in this loop.
1656 nscoord sum = 0;
1657 const nscoord percentBasis = aSize;
1658 for (uint32_t i = 0; i < numTracks; ++i) {
1659 // "treating each track as its max track sizing function if that is
1660 // definite or as its minimum track sizing function otherwise"
1661 // https://drafts.csswg.org/css-grid-2/#valdef-repeat-auto-fill
1662 nscoord trackSize;
1663 {
1664 const auto& sizingFunction = SizingFor(i);
1665 const auto& maxCoord = sizingFunction.GetMax();
1666 const auto& minCoord = sizingFunction.GetMin();
1667 if (maxCoord.IsBreadth() && minCoord.IsBreadth()) {
1668 // If the max is less than the min, then the max will be floored by
1669 // the min (essentially yielding minmax(min, min))
1670 // https://drafts.csswg.org/css-grid-2/#funcdef-grid-template-columns-minmax
1671 const nscoord minSize =
1672 ::ResolveToDefiniteSize(minCoord, percentBasis);
1673 const nscoord maxSize =
1674 ::ResolveToDefiniteSize(maxCoord, percentBasis);
1675 trackSize = std::max(maxSize, minSize);
1676 } else {
1677 const auto* coord = &maxCoord;
1678 if (!coord->IsBreadth()) {
1679 coord = &minCoord;
1680 if (!coord->IsBreadth()) {
1681 return 1;
1682 }
1683 }
1684 trackSize = ::ResolveToDefiniteSize(*coord, percentBasis);
1685 }
1686 }
1687
1688 if (i >= mRepeatAutoStart && i < mRepeatAutoEnd) {
1689 // Use a minimum 1px for the repeat() track-size.
1690 if (trackSize < AppUnitsPerCSSPixel()) {
1691 trackSize = AppUnitsPerCSSPixel();
1692 }
1693 repeatTrackSum += trackSize;
1694 }
1695 sum += trackSize;
1696 }
1697 nscoord gridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aSize);
1698 if (numTracks > 1) {
1699 // Add grid-gaps for all the tracks including the repeat() track.
1700 sum += gridGap * (numTracks - 1);
1701 }
1702 // Calculate the max number of tracks that fits without overflow.
1703 nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize;
1704 nscoord spaceToFill = available - sum;
1705 if (spaceToFill <= 0) {
1706 // "if any number of repetitions would overflow, then 1 repetition"
1707 return 1;
1708 }
1709 // Calculate the max number of tracks that fits without overflow.
1710 // Since we already have one repetition in sum, we can simply add one grid
1711 // gap for each element in the repeat.
1712 div_t q = div(spaceToFill, repeatTrackSum + gridGap * NumRepeatTracks());
1713 // The +1 here is for the one repeat track we already accounted for above.
1714 uint32_t numRepeatTracks = q.quot + 1;
1715 if (q.rem != 0 && maxFill == NS_UNCONSTRAINEDSIZE) {
1716 // "Otherwise, if the grid container has a definite min size in
1717 // the relevant axis, the number of repetitions is the largest possible
1718 // positive integer that fulfills that minimum requirement."
1719 ++numRepeatTracks; // one more to ensure the grid is at least min-size
1720 }
1721 // Clamp the number of repeat tracks so that the last line <= kMaxLine.
1722 // (note that |numTracks| already includes one repeat() track)
1723 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"
, 1723); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numTracks >= NumRepeatTracks()"
")"); do { MOZ_CrashSequence(__null, 1723); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1724 const uint32_t maxRepeatTrackCount = kMaxLine - numTracks;
1725 const uint32_t maxRepetitions = maxRepeatTrackCount / NumRepeatTracks();
1726 return std::min(numRepeatTracks, maxRepetitions);
1727 }
1728
1729 /**
1730 * Compute the explicit grid end line number (in a zero-based grid).
1731 * @param aGridTemplateAreasEnd 'grid-template-areas' end line in this axis
1732 */
1733 uint32_t ComputeExplicitGridEnd(uint32_t aGridTemplateAreasEnd) {
1734 uint32_t end = NumExplicitTracks() + 1;
1735 end = std::max(end, aGridTemplateAreasEnd);
1736 end = std::min(end, uint32_t(kMaxLine));
1737 return end;
1738 }
1739 const StyleTrackSize& SizingFor(uint32_t aTrackIndex) const {
1740 static const StyleTrackSize kAutoTrackSize =
1741 StyleTrackSize::Breadth(StyleTrackBreadth::Auto());
1742 // |aIndex| is the relative index to mAutoSizing. A negative value means it
1743 // is the last Nth element.
1744 auto getImplicitSize = [this](int32_t aIndex) -> const StyleTrackSize& {
1745 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1746 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1747 "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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1748 "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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1749
1750 if (mAutoSizing.IsEmpty()) {
1751 return kAutoTrackSize;
1752 }
1753
1754 // If multiple track sizes are given, the pattern is repeated as necessary
1755 // to find the size of the implicit tracks.
1756 int32_t i = aIndex % int32_t(mAutoSizing.Length());
1757 if (i < 0) {
1758 i += mAutoSizing.Length();
1759 }
1760 return mAutoSizing.AsSpan()[i];
1761 };
1762
1763 if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)(__builtin_expect(!!(aTrackIndex < mExplicitGridOffset), 0
))
) {
1764 // The last implicit grid track before the explicit grid receives the
1765 // last specified size, and so on backwards. Therefore we pass the
1766 // negative relative index to imply that we should get the implicit size
1767 // from the last Nth specified grid auto size.
1768 return getImplicitSize(int32_t(aTrackIndex) -
1769 int32_t(mExplicitGridOffset));
1770 }
1771 uint32_t index = aTrackIndex - mExplicitGridOffset;
1772 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", 1772)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRepeatAutoStart <= mRepeatAutoEnd"
")"); do { MOZ_CrashSequence(__null, 1772); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1773
1774 if (index >= mRepeatAutoStart) {
1775 if (index < mRepeatAutoEnd) {
1776 // Expand the repeat tracks.
1777 const auto& indices = mExpandedTracks[mRepeatAutoStart];
1778 const TrackListValue& value = mTrackListValues[indices.first];
1779
1780 // We expect the default to be used for all track repeats.
1781 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", 1781)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "indices.second == 0"
")"); do { MOZ_CrashSequence(__null, 1781); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1782
1783 const auto& repeatTracks = value.AsTrackRepeat().track_sizes.AsSpan();
1784
1785 // Find the repeat track to use, skipping over any collapsed tracks.
1786 const uint32_t finalRepeatIndex = (index - mRepeatAutoStart);
1787 uint32_t repeatWithCollapsed = 0;
1788 // NOTE: We need SizingFor before the final collapsed tracks are known.
1789 // We know that it's invalid to have empty mRemovedRepeatTracks when
1790 // there are any repeat tracks, so we can detect that situation here.
1791 if (mRemovedRepeatTracks.IsEmpty()) {
1792 repeatWithCollapsed = finalRepeatIndex;
1793 } else {
1794 // Count up through the repeat tracks, until we have seen
1795 // finalRepeatIndex number of non-collapsed tracks.
1796 for (uint32_t repeatNoCollapsed = 0;
1797 repeatNoCollapsed < finalRepeatIndex; repeatWithCollapsed++) {
1798 if (!mRemovedRepeatTracks[repeatWithCollapsed]) {
1799 repeatNoCollapsed++;
1800 }
1801 }
1802 // If we stopped iterating on a collapsed track, continue to the next
1803 // non-collapsed track.
1804 while (mRemovedRepeatTracks[repeatWithCollapsed]) {
1805 repeatWithCollapsed++;
1806 }
1807 }
1808 return repeatTracks[repeatWithCollapsed % repeatTracks.Length()];
1809 } else {
1810 // The index is after the repeat auto range, adjust it to skip over the
1811 // repeat value. This will have no effect if there is no auto repeat,
1812 // since then RepeatEndDelta will return zero.
1813 index -= RepeatEndDelta();
1814 }
1815 }
1816 if (index >= mExpandedTracks.Length()) {
1817 return getImplicitSize(index - mExpandedTracks.Length());
1818 }
1819 auto& indices = mExpandedTracks[index];
1820 const TrackListValue& value = mTrackListValues[indices.first];
1821 if (value.IsTrackSize()) {
1822 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", 1822)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "indices.second == 0"
")"); do { MOZ_CrashSequence(__null, 1822); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1823 return value.AsTrackSize();
1824 }
1825 return value.AsTrackRepeat().track_sizes.AsSpan()[indices.second];
1826 }
1827 const StyleTrackBreadth& MaxSizingFor(uint32_t aTrackIndex) const {
1828 return SizingFor(aTrackIndex).GetMax();
1829 }
1830 const StyleTrackBreadth& MinSizingFor(uint32_t aTrackIndex) const {
1831 return SizingFor(aTrackIndex).GetMin();
1832 }
1833 uint32_t NumExplicitTracks() const {
1834 return mExpandedTracks.Length() + RepeatEndDelta();
1835 }
1836 uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; }
1837 // The difference between mExplicitGridEnd and mSizingFunctions.Length().
1838 int32_t RepeatEndDelta() const {
1839 return mHasRepeatAuto ? int32_t(NumRepeatTracks()) - 1 : 0;
1840 }
1841 void SetNumRepeatTracks(uint32_t aNumRepeatTracks) {
1842 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", 1842)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mHasRepeatAuto || aNumRepeatTracks == 0"
")"); do { MOZ_CrashSequence(__null, 1842); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1843 mRepeatAutoEnd = mRepeatAutoStart + aNumRepeatTracks;
1844 }
1845
1846 [[nodiscard]] bool EmplaceExpandedTrack(size_t aTrackListValueIndex,
1847 size_t aRepeatIndex) {
1848 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", 1848)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mExpandedTracks.Length() < kMaxLine"
")"); do { MOZ_CrashSequence(__null, 1848); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1849 if (mExpandedTracks.Length() == kMaxTrack) {
1850 return false;
1851 }
1852 return mExpandedTracks.EmplaceBack(fallible, aTrackListValueIndex,
1853 aRepeatIndex);
1854 }
1855
1856 // Store mTrackListValues into mExpandedTracks with `repeat(INTEGER, ...)`
1857 // tracks expanded.
1858 void ExpandNonRepeatAutoTracks() {
1859 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", 1859)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mExpandedTracks.Length() <= kMaxTrack"
")"); do { MOZ_CrashSequence(__null, 1859); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1860 for (size_t i = 0; i < mTrackListValues.Length(); ++i) {
1861 auto& value = mTrackListValues[i];
1862 if (value.IsTrackSize()) {
1863 if (!EmplaceExpandedTrack(i, 0)) {
1864 return;
1865 }
1866 continue;
1867 }
1868 auto& repeat = value.AsTrackRepeat();
1869 if (!repeat.count.IsNumber()) {
1870 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", 1870)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "i == mRepeatAutoStart"
")"); do { MOZ_CrashSequence(__null, 1870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1871 const auto repeatAutoStart = mExpandedTracks.Length();
1872 if (!EmplaceExpandedTrack(i, 0)) {
1873 return;
1874 }
1875 mRepeatAutoStart = repeatAutoStart;
1876 mRepeatAutoEnd = repeatAutoStart + repeat.track_sizes.Length();
1877 continue;
1878 }
1879 for (auto j : IntegerRange(repeat.count.AsNumber())) {
1880 (void)j;
1881 size_t trackSizesCount = repeat.track_sizes.Length();
1882 for (auto k : IntegerRange(trackSizesCount)) {
1883 if (!EmplaceExpandedTrack(i, k)) {
1884 return;
1885 }
1886 }
1887 }
1888 }
1889 }
1890
1891 // Some style data references, for easy access.
1892 const GridTemplate& mTemplate;
1893 const Span<const TrackListValue> mTrackListValues;
1894 const StyleImplicitGridTracks& mAutoSizing;
1895 // An array from expanded track sizes (without expanding auto-repeat, which is
1896 // included just once at `mRepeatAutoStart`).
1897 //
1898 // Each entry contains two indices, the first into mTrackListValues, and a
1899 // second one inside mTrackListValues' repeat value, if any, or zero
1900 // otherwise.
1901 nsTArray<std::pair<size_t, size_t>> mExpandedTracks;
1902 // Offset from the start of the implicit grid to the first explicit track.
1903 uint32_t mExplicitGridOffset;
1904 // The index of the repeat(auto-fill/fit) track, or zero if there is none.
1905 // Relative to mExplicitGridOffset (repeat tracks are explicit by definition).
1906 uint32_t mRepeatAutoStart;
1907 // The (hypothetical) index of the last such repeat() track.
1908 uint32_t mRepeatAutoEnd;
1909 // True if there is a specified repeat(auto-fill/fit) track.
1910 bool mHasRepeatAuto;
1911 // True if this track (relative to mRepeatAutoStart) is a removed auto-fit.
1912 // Indexed relative to mExplicitGridOffset + mRepeatAutoStart.
1913 nsTArray<bool> mRemovedRepeatTracks;
1914};
1915
1916/**
1917 * Utility class to find line names. It provides an interface to lookup line
1918 * names with a dynamic number of repeat(auto-fill/fit) tracks taken into
1919 * account.
1920 */
1921class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap {
1922 public:
1923 /**
1924 * Create a LineNameMap.
1925 * @param aStylePosition the style for the grid container
1926 * @param aImplicitNamedAreas the implicit areas for the grid container
1927 * @param aGridTemplate is the grid-template-rows/columns data for this axis
1928 * @param aParentLineNameMap the parent grid's map parallel to this map, or
1929 * null if this map isn't for a subgrid
1930 * @param aRange the subgrid's range in the parent grid, or null
1931 * @param aIsSameDirection true if our axis progresses in the same direction
1932 * in the subgrid and parent
1933 * @param aIsOrthogonal true if the subgrid and parent have orthongonal
1934 * writing modes
1935 */
1936 LineNameMap(const nsStylePosition* aStylePosition,
1937 const ImplicitNamedAreas* aImplicitNamedAreas,
1938 const TrackSizingFunctions& aTracks,
1939 const LineNameMap* aParentLineNameMap, const LineRange* aRange,
1940 bool aIsSameDirection = true, bool aIsOrthogonal = false)
1941 : mStylePosition(aStylePosition),
1942 mAreas(aImplicitNamedAreas),
1943 mRepeatAutoStart(aTracks.mRepeatAutoStart),
1944 mRepeatAutoEnd(aTracks.mRepeatAutoEnd),
1945 mRepeatEndDelta(aTracks.RepeatEndDelta()),
1946 mParentLineNameMap(aParentLineNameMap),
1947 mRange(aRange),
1948 mIsSameDirection(aIsSameDirection),
1949 mIsOrthogonal(aIsOrthogonal),
1950 mHasRepeatAuto(aTracks.mHasRepeatAuto) {
1951 if (MOZ_UNLIKELY(aRange)(__builtin_expect(!!(aRange), 0))) { // subgrid case
1952 mClampMinLine = 1;
1953 mClampMaxLine = 1 + aRange->Extent();
1954 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", 1954
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mTemplate.IsSubgrid()"
") (" "Should be subgrid type" ")"); do { MOZ_CrashSequence(
__null, 1954); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
1955 ExpandRepeatLineNamesForSubgrid(*aTracks.mTemplate.AsSubgrid());
1956 // we've expanded all subgrid auto-fill lines in
1957 // ExpandRepeatLineNamesForSubgrid()
1958 mRepeatAutoStart = 0;
1959 mRepeatAutoEnd = mRepeatAutoStart;
1960 mHasRepeatAuto = false;
1961 } else {
1962 mClampMinLine = kMinLine;
1963 mClampMaxLine = kMaxLine;
1964 if (mHasRepeatAuto) {
1965 mTrackAutoRepeatLineNames =
1966 aTracks.mTemplate.GetRepeatAutoValue()->line_names.AsSpan();
1967 }
1968 ExpandRepeatLineNames(aTracks);
1969 }
1970 if (mHasRepeatAuto) {
1971 // We need mTemplateLinesEnd to be after all line names.
1972 // mExpandedLineNames has one repetition of the repeat(auto-fit/fill)
1973 // track name lists already, so we must subtract the number of repeat
1974 // track name lists to get to the number of non-repeat tracks, minus 2
1975 // because the first and last line name lists are shared with the
1976 // preceding and following non-repeat line name lists. We then add
1977 // mRepeatEndDelta to include the interior line name lists from repeat
1978 // tracks.
1979 mTemplateLinesEnd = mExpandedLineNames.Length() -
1980 (mTrackAutoRepeatLineNames.Length() - 2) +
1981 mRepeatEndDelta;
1982 } else {
1983 mTemplateLinesEnd = mExpandedLineNames.Length();
1984 }
1985 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", 1985)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mHasRepeatAuto || mRepeatEndDelta <= 0"
")"); do { MOZ_CrashSequence(__null, 1985); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1986 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", 1988)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1988); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1987 (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", 1988)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1988); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1988 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", 1988)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || aRange || (mExpandedLineNames.Length() >= 2 && mRepeatAutoStart <= mExpandedLineNames.Length())"
")"); do { MOZ_CrashSequence(__null, 1988); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1989 }
1990
1991 // Store line names into mExpandedLineNames with `repeat(INTEGER, ...)`
1992 // expanded for non-subgrid.
1993 void ExpandRepeatLineNames(const TrackSizingFunctions& aTracks) {
1994 auto lineNameLists = aTracks.mTemplate.LineNameLists(false);
1995
1996 const auto& trackListValues = aTracks.mTrackListValues;
1997 const NameList* nameListToMerge = nullptr;
1998 // NOTE(emilio): We rely on std::move clearing out the array.
1999 SmallPointerArray<const NameList> names;
2000 const uint32_t end =
2001 std::min<uint32_t>(lineNameLists.Length(), mClampMaxLine + 1);
2002 auto AppendExpandedNames = [&]() -> bool {
2003 if (mExpandedLineNames.Length() == size_t(mClampMaxLine)) {
2004 return false;
2005 }
2006 return mExpandedLineNames.AppendElement(std::move(names), fallible);
2007 };
2008 for (uint32_t i = 0; i < end; ++i) {
2009 if (nameListToMerge) {
2010 names.AppendElement(nameListToMerge);
2011 nameListToMerge = nullptr;
2012 }
2013 names.AppendElement(&lineNameLists[i]);
2014 if (i >= trackListValues.Length()) {
2015 if (!AppendExpandedNames()) {
2016 return;
2017 }
2018 continue;
2019 }
2020 const auto& value = trackListValues[i];
2021 if (value.IsTrackSize()) {
2022 if (!AppendExpandedNames()) {
2023 return;
2024 }
2025 continue;
2026 }
2027 const auto& repeat = value.AsTrackRepeat();
2028 if (!repeat.count.IsNumber()) {
2029 const auto repeatNames = repeat.line_names.AsSpan();
2030 // If the repeat was truncated due to more than kMaxLine tracks, then
2031 // the repeat will no longer be set on mRepeatAutoStart).
2032 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", 2033)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
")"); do { MOZ_CrashSequence(__null, 2033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2033 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", 2033)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHasRepeatAuto || mRepeatAutoStart == mExpandedLineNames.Length()"
")"); do { MOZ_CrashSequence(__null, 2033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2034 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"
, 2034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatNames.Length() >= 2"
")"); do { MOZ_CrashSequence(__null, 2034); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2035 for (const auto j : IntegerRange(repeatNames.Length() - 1)) {
2036 names.AppendElement(&repeatNames[j]);
2037 if (!AppendExpandedNames()) {
2038 return;
2039 }
2040 }
2041 nameListToMerge = &repeatNames[repeatNames.Length() - 1];
2042 continue;
2043 }
2044 for (auto j : IntegerRange(repeat.count.AsNumber())) {
2045 (void)j;
2046 if (nameListToMerge) {
2047 names.AppendElement(nameListToMerge);
2048 nameListToMerge = nullptr;
2049 }
2050 size_t trackSizesCount = repeat.track_sizes.Length();
2051 auto repeatLineNames = repeat.line_names.AsSpan();
2052 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", 2053)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
")"); do { MOZ_CrashSequence(__null, 2053); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2053 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", 2053)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatLineNames.Length() == trackSizesCount || repeatLineNames.Length() == trackSizesCount + 1"
")"); do { MOZ_CrashSequence(__null, 2053); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2054 for (auto k : IntegerRange(trackSizesCount)) {
2055 names.AppendElement(&repeatLineNames[k]);
2056 if (!AppendExpandedNames()) {
2057 return;
2058 }
2059 }
2060 if (repeatLineNames.Length() == trackSizesCount + 1) {
2061 nameListToMerge = &repeatLineNames[trackSizesCount];
2062 }
2063 }
2064 }
2065 }
2066
2067 // Store line names into mExpandedLineNames with `repeat(INTEGER, ...)`
2068 // expanded, and all `repeat(...)` expanded for subgrid.
2069 // https://drafts.csswg.org/css-grid-2/#resolved-track-list-subgrid
2070 void ExpandRepeatLineNamesForSubgrid(
2071 const StyleGenericLineNameList<StyleInteger>& aStyleLineNameList) {
2072 const auto& lineNameList = aStyleLineNameList.line_names.AsSpan();
2073 SmallPointerArray<const NameList> names;
2074 auto AppendExpandedNames = [&]() -> bool {
2075 if (mExpandedLineNames.Length() == size_t(mClampMaxLine)) {
2076 return false;
2077 }
2078 return mExpandedLineNames.AppendElement(std::move(names), fallible);
2079 };
2080 for (const auto& item : lineNameList) {
2081 if (item.IsLineNames()) {
2082 // <line-names> case. Just copy it.
2083 names.AppendElement(&item.AsLineNames());
2084 if (!AppendExpandedNames()) {
2085 return;
2086 }
2087 continue;
2088 }
2089
2090 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", 2090)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.IsRepeat()" ")"
); do { MOZ_CrashSequence(__null, 2090); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2091 const auto& repeat = item.AsRepeat();
2092 const auto repeatLineNames = repeat.line_names.AsSpan();
2093
2094 if (repeat.count.IsNumber()) {
2095 // Clone all <line-names>+ (repeated by N) into
2096 // |mExpandedLineNames|.
2097 for (uint32_t repeatCount = 0;
2098 repeatCount < (uint32_t)repeat.count.AsNumber(); ++repeatCount) {
2099 for (const NameList& lineNames : repeatLineNames) {
2100 names.AppendElement(&lineNames);
2101 if (!AppendExpandedNames()) {
2102 return;
2103 }
2104 }
2105 }
2106 continue;
2107 }
2108
2109 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"
, 2110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeat.count.IsAutoFill()"
") (" "RepeatCount of subgrid is number or auto-fill" ")"); do
{ MOZ_CrashSequence(__null, 2110); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2110 "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"
, 2110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeat.count.IsAutoFill()"
") (" "RepeatCount of subgrid is number or auto-fill" ")"); do
{ MOZ_CrashSequence(__null, 2110); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2111
2112 const size_t fillLen = repeatLineNames.Length();
2113 const int32_t extraAutoFillLineCount =
2114 mClampMaxLine -
2115 (int32_t)aStyleLineNameList.expanded_line_names_length;
2116 // Maximum possible number of repeat name lists.
2117 // Note: |expanded_line_names_length| doesn't include auto repeat.
2118 const uint32_t possibleRepeatLength =
2119 std::max<int32_t>(0, extraAutoFillLineCount);
2120 const uint32_t repeatRemainder = possibleRepeatLength % fillLen;
2121
2122 // Note: Expand 'auto-fill' names for subgrid for now since
2123 // HasNameAt() only deals with auto-repeat **tracks** currently.
2124 const size_t len = possibleRepeatLength - repeatRemainder;
2125 for (size_t j = 0; j < len; ++j) {
2126 names.AppendElement(&repeatLineNames[j % fillLen]);
2127 if (!AppendExpandedNames()) {
2128 return;
2129 }
2130 }
2131 }
2132 }
2133
2134 /**
2135 * Find the aNth occurrence of aName, searching forward if aNth is positive,
2136 * and in reverse if aNth is negative (aNth == 0 is invalid), starting from
2137 * aFromIndex (not inclusive), and return a 1-based line number.
2138 * Also take into account there is an unconditional match at the lines in
2139 * aImplicitLines.
2140 * Return zero if aNth occurrences can't be found. In that case, aNth has
2141 * been decremented with the number of occurrences that were found (if any).
2142 *
2143 * E.g. to search for "A 2" forward from the start of the grid: aName is "A"
2144 * aNth is 2 and aFromIndex is zero. To search for "A -2", aNth is -2 and
2145 * aFromIndex is ExplicitGridEnd + 1 (which is the line "before" the last
2146 * line when we're searching in reverse). For "span A 2", aNth is 2 when
2147 * used on a grid-[row|column]-end property and -2 for a *-start property,
2148 * and aFromIndex is the line (which we should skip) on the opposite property.
2149 */
2150 uint32_t FindNamedLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2151 const nsTArray<uint32_t>& aImplicitLines) const {
2152 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"
, 2152); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aName" ")")
; do { MOZ_CrashSequence(__null, 2152); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2153 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", 2153)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aName->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 2153); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2154 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", 2154)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth != 0"
")"); do { MOZ_CrashSequence(__null, 2154); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2155 if (*aNth > 0) {
2156 return FindLine(aName, aNth, aFromIndex, aImplicitLines);
2157 }
2158 int32_t nth = -*aNth;
2159 int32_t line = RFindLine(aName, &nth, aFromIndex, aImplicitLines);
2160 *aNth = -nth;
2161 return line;
2162 }
2163
2164 /**
2165 * Return a set of lines in aImplicitLines which matches the area name aName
2166 * on aSide. For example, for aName "a" and aSide being an end side, it
2167 * returns the line numbers which would match "a-end" in the relevant axis.
2168 * For subgrids it includes searching the relevant axis in all ancestor
2169 * grids too (within this subgrid's spanned area). If an ancestor has
2170 * opposite direction, we switch aSide to the opposite logical side so we
2171 * match on the same physical side as the original subgrid we're resolving
2172 * the name for.
2173 */
2174 void FindNamedAreas(nsAtom* aName, LogicalSide aSide,
2175 nsTArray<uint32_t>& aImplicitLines) const {
2176 // True if we're currently in a map that has the same direction as 'this'.
2177 bool sameDirectionAsThis = true;
2178 uint32_t min = !mParentLineNameMap ? 1 : mClampMinLine;
2179 uint32_t max = mClampMaxLine;
2180 for (auto* map = this; true;) {
2181 uint32_t line = map->FindNamedArea(aName, aSide, min, max);
2182 if (line > 0) {
2183 if (MOZ_LIKELY(sameDirectionAsThis)(__builtin_expect(!!(sameDirectionAsThis), 1))) {
2184 line -= min - 1;
2185 } else {
2186 line = max - line + 1;
2187 }
2188 aImplicitLines.AppendElement(line);
2189 }
2190 auto* parent = map->mParentLineNameMap;
2191 if (!parent) {
2192 if (MOZ_UNLIKELY(aImplicitLines.Length() > 1)(__builtin_expect(!!(aImplicitLines.Length() > 1), 0))) {
2193 // Remove duplicates and sort in ascending order.
2194 aImplicitLines.Sort();
2195 for (size_t i = 0; i < aImplicitLines.Length(); ++i) {
2196 uint32_t prev = aImplicitLines[i];
2197 auto j = i + 1;
2198 const auto start = j;
2199 while (j < aImplicitLines.Length() && aImplicitLines[j] == prev) {
2200 ++j;
2201 }
2202 if (j != start) {
2203 aImplicitLines.RemoveElementsAt(start, j - start);
2204 }
2205 }
2206 }
2207 return;
2208 }
2209 if (MOZ_UNLIKELY(!map->mIsSameDirection)(__builtin_expect(!!(!map->mIsSameDirection), 0))) {
2210 aSide = GetOppositeSide(aSide);
2211 sameDirectionAsThis = !sameDirectionAsThis;
2212 }
2213 if (MOZ_UNLIKELY(map->mIsOrthogonal)(__builtin_expect(!!(map->mIsOrthogonal), 0))) {
2214 aSide =
2215 MakeLogicalSide(GetOrthogonalAxis(GetAxis(aSide)), GetEdge(aSide));
2216 }
2217 min = map->TranslateToParentMap(min);
2218 max = map->TranslateToParentMap(max);
2219 if (min > max) {
2220 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", 2220)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!map->mIsSameDirection"
")"); do { MOZ_CrashSequence(__null, 2220); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2221 std::swap(min, max);
2222 }
2223 map = parent;
2224 }
2225 }
2226
2227 /**
2228 * Return true if any implicit named areas match aName, in this map or
2229 * in any of our ancestor maps.
2230 */
2231 bool HasImplicitNamedArea(nsAtom* aName) const {
2232 const auto* map = this;
2233 do {
2234 if (map->mAreas && map->mAreas->has(aName)) {
2235 return true;
2236 }
2237 map = map->mParentLineNameMap;
2238 } while (map);
2239 return false;
2240 }
2241
2242 // For generating line name data for devtools.
2243 nsTArray<nsTArray<StyleCustomIdent>>
2244 GetResolvedLineNamesForComputedGridTrackInfo() const {
2245 nsTArray<nsTArray<StyleCustomIdent>> result;
2246 for (auto& expandedLine : mExpandedLineNames) {
2247 nsTArray<StyleCustomIdent> line;
2248 for (auto* chunk : expandedLine) {
2249 for (auto& name : chunk->AsSpan()) {
2250 line.AppendElement(name);
2251 }
2252 }
2253 result.AppendElement(std::move(line));
2254 }
2255 return result;
2256 }
2257
2258 nsTArray<RefPtr<nsAtom>> GetExplicitLineNamesAtIndex(uint32_t aIndex) const {
2259 nsTArray<RefPtr<nsAtom>> lineNames;
2260 if (aIndex < mTemplateLinesEnd) {
2261 const auto nameLists = GetLineNamesAt(aIndex);
2262 for (const NameList* nameList : nameLists) {
2263 for (const auto& name : nameList->AsSpan()) {
2264 lineNames.AppendElement(name.AsAtom());
2265 }
2266 }
2267 }
2268 return lineNames;
2269 }
2270
2271 const nsTArray<SmallPointerArray<const NameList>>& ExpandedLineNames() const {
2272 return mExpandedLineNames;
2273 }
2274 const Span<const StyleOwnedSlice<StyleCustomIdent>>&
2275 TrackAutoRepeatLineNames() const {
2276 return mTrackAutoRepeatLineNames;
2277 }
2278 bool HasRepeatAuto() const { return mHasRepeatAuto; }
2279 uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; }
2280 uint32_t RepeatAutoStart() const { return mRepeatAutoStart; }
2281
2282 // The min/max line number (1-based) for clamping.
2283 int32_t mClampMinLine;
2284 int32_t mClampMaxLine;
2285
2286 private:
2287 // Return true if this map represents a subgridded axis.
2288 bool IsSubgridded() const { return mParentLineNameMap != nullptr; }
2289
2290 /**
2291 * @see FindNamedLine, this function searches forward.
2292 */
2293 uint32_t FindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2294 const nsTArray<uint32_t>& aImplicitLines) const {
2295 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"
, 2295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth > 0"
")"); do { MOZ_CrashSequence(__null, 2295); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2296 int32_t nth = *aNth;
2297 // For a subgrid we need to search to the end of the grid rather than
2298 // the end of the local name list, since ancestors might match.
2299 const uint32_t end = IsSubgridded() ? mClampMaxLine : mTemplateLinesEnd;
2300 uint32_t line;
2301 uint32_t i = aFromIndex;
2302 for (; i < end; i = line) {
2303 line = i + 1;
2304 if (Contains(i, aName) || aImplicitLines.Contains(line)) {
2305 if (--nth == 0) {
2306 return line;
2307 }
2308 }
2309 }
2310 for (auto implicitLine : aImplicitLines) {
2311 if (implicitLine > i) {
2312 // implicitLine is after the lines we searched above so it's last.
2313 // (grid-template-areas has more tracks than
2314 // grid-template-[rows|columns])
2315 if (--nth == 0) {
2316 return implicitLine;
2317 }
2318 }
2319 }
2320 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", 2320
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nth > 0" ") ("
"should have returned a valid line above already" ")"); do {
MOZ_CrashSequence(__null, 2320); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2321 *aNth = nth;
2322 return 0;
2323 }
2324
2325 /**
2326 * @see FindNamedLine, this function searches in reverse.
2327 */
2328 uint32_t RFindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
2329 const nsTArray<uint32_t>& aImplicitLines) const {
2330 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"
, 2330); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth && *aNth > 0"
")"); do { MOZ_CrashSequence(__null, 2330); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2331 if (MOZ_UNLIKELY(aFromIndex == 0)(__builtin_expect(!!(aFromIndex == 0), 0))) {
2332 return 0; // There are no named lines beyond the start of the explicit
2333 // grid.
2334 }
2335 --aFromIndex; // (shift aFromIndex so we can treat it as inclusive)
2336 int32_t nth = *aNth;
2337 // Implicit lines may be beyond the explicit grid so we match those
2338 // first if it's within the mTemplateLinesEnd..aFromIndex range.
2339 // aImplicitLines is presumed sorted.
2340 // For a subgrid we need to search to the end of the grid rather than
2341 // the end of the local name list, since ancestors might match.
2342 const uint32_t end = IsSubgridded() ? mClampMaxLine : mTemplateLinesEnd;
2343 for (auto implicitLine : Reversed(aImplicitLines)) {
2344 if (implicitLine <= end) {
2345 break;
2346 }
2347 if (implicitLine < aFromIndex) {
2348 if (--nth == 0) {
2349 return implicitLine;
2350 }
2351 }
2352 }
2353 for (uint32_t i = std::min(aFromIndex, end); i; --i) {
2354 if (Contains(i - 1, aName) || aImplicitLines.Contains(i)) {
2355 if (--nth == 0) {
2356 return i;
2357 }
2358 }
2359 }
2360 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", 2360
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nth > 0" ") ("
"should have returned a valid line above already" ")"); do {
MOZ_CrashSequence(__null, 2360); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2361 *aNth = nth;
2362 return 0;
2363 }
2364
2365 // Return true if aName exists at aIndex in this map or any parent map.
2366 bool Contains(uint32_t aIndex, nsAtom* aName) const {
2367 const auto* map = this;
2368 while (true) {
2369 if (aIndex < map->mTemplateLinesEnd && map->HasNameAt(aIndex, aName)) {
2370 return true;
2371 }
2372 auto* parent = map->mParentLineNameMap;
2373 if (!parent) {
2374 return false;
2375 }
2376 uint32_t line = map->TranslateToParentMap(aIndex + 1);
2377 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"
, 2377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "line >= 1"
") (" "expected a 1-based line number" ")"); do { MOZ_CrashSequence
(__null, 2377); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2378 aIndex = line - 1;
2379 map = parent;
2380 }
2381 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"
, 2381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "we always return from inside the loop above"
")"); do { MOZ_CrashSequence(__null, 2381); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2382 }
2383
2384 static bool Contains(Span<const StyleCustomIdent> aNames, nsAtom* aName) {
2385 for (auto& name : aNames) {
2386 if (name.AsAtom() == aName) {
2387 return true;
2388 }
2389 }
2390 return false;
2391 }
2392
2393 // Return true if aName exists at aIndex in this map.
2394 bool HasNameAt(const uint32_t aIndex, nsAtom* const aName) const {
2395 const auto nameLists = GetLineNamesAt(aIndex);
2396 for (const NameList* nameList : nameLists) {
2397 if (Contains(nameList->AsSpan(), aName)) {
2398 return true;
2399 }
2400 }
2401 return false;
2402 }
2403
2404 // Get the line names at an index.
2405 // This accounts for auto repeat. The results may be spread over multiple name
2406 // lists returned in the array, which is done to avoid unneccessarily copying
2407 // the arrays to concatenate them.
2408 SmallPointerArray<const NameList> GetLineNamesAt(
2409 const uint32_t aIndex) const {
2410 SmallPointerArray<const NameList> names;
2411 // The index into mExpandedLineNames to use, if aIndex doesn't point to a
2412 // name inside of a auto repeat.
2413 uint32_t repeatAdjustedIndex = aIndex;
2414 // Note: For subgrid, |mHasRepeatAuto| is always false because we have
2415 // expanded it in the constructor of LineNameMap.
2416 if (mHasRepeatAuto) {
2417 // If the index is inside of the auto repeat, use the repeat line
2418 // names. Otherwise, if the index is past the end of the repeat it must
2419 // be adjusted to acount for the repeat tracks.
2420 // mExpandedLineNames has the first and last line name lists from the
2421 // repeat in it already, so we can just ignore aIndex == mRepeatAutoStart
2422 // and treat when aIndex == mRepeatAutoEnd the same as any line after the
2423 // the repeat.
2424 const uint32_t maxRepeatLine = mTrackAutoRepeatLineNames.Length() - 1;
2425 if (aIndex > mRepeatAutoStart && aIndex < mRepeatAutoEnd) {
2426 // The index is inside the auto repeat. Calculate the lines to use,
2427 // including the previous repetitions final names when we roll over
2428 // from one repetition to the next.
2429 const uint32_t repeatIndex =
2430 (aIndex - mRepeatAutoStart) % maxRepeatLine;
2431 if (repeatIndex == 0) {
2432 // The index is at the start of a new repetition. The start of the
2433 // first repetition is intentionally ignored above, so this will
2434 // consider both the end of the previous repetition and the start
2435 // the one that contains aIndex.
2436 names.AppendElement(&mTrackAutoRepeatLineNames[maxRepeatLine]);
2437 }
2438 names.AppendElement(&mTrackAutoRepeatLineNames[repeatIndex]);
2439 return names;
2440 }
2441 if (aIndex != mRepeatAutoStart && aIndex >= mRepeatAutoEnd) {
2442 // Adjust the index to account for the line names of the repeat.
2443 repeatAdjustedIndex -= mRepeatEndDelta;
2444 repeatAdjustedIndex += mTrackAutoRepeatLineNames.Length() - 2;
2445 }
2446 }
2447 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", 2448
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatAdjustedIndex < mExpandedLineNames.Length()"
") (" "Incorrect repeatedAdjustedIndex" ")"); do { MOZ_CrashSequence
(__null, 2448); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2448 "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", 2448
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "repeatAdjustedIndex < mExpandedLineNames.Length()"
") (" "Incorrect repeatedAdjustedIndex" ")"); do { MOZ_CrashSequence
(__null, 2448); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2449 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", 2449)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "names.IsEmpty()" ")"
); do { MOZ_CrashSequence(__null, 2449); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2450 // The index is not inside the repeat tracks, or no repeat tracks exist.
2451 const auto& nameLists = mExpandedLineNames[repeatAdjustedIndex];
2452 for (const NameList* nameList : nameLists) {
2453 names.AppendElement(nameList);
2454 }
2455 return names;
2456 }
2457
2458 // Translate a subgrid line (1-based) to a parent line (1-based).
2459 uint32_t TranslateToParentMap(uint32_t aLine) const {
2460 if (MOZ_LIKELY(mIsSameDirection)(__builtin_expect(!!(mIsSameDirection), 1))) {
2461 return aLine + mRange->mStart;
2462 }
2463 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"
, 2463); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRange->mEnd + 1 >= aLine"
")"); do { MOZ_CrashSequence(__null, 2463); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2464 return mRange->mEnd - (aLine - 1) + 1;
2465 }
2466
2467 /**
2468 * Return the 1-based line that match aName in 'grid-template-areas'
2469 * on the side aSide. Clamp the result to aMin..aMax but require
2470 * that some part of the area is inside for it to match.
2471 * Return zero if there is no match.
2472 */
2473 uint32_t FindNamedArea(nsAtom* aName, LogicalSide aSide, int32_t aMin,
2474 int32_t aMax) const {
2475 if (const NamedArea* area = FindNamedArea(aName)) {
2476 int32_t start = IsBlock(aSide) ? area->rows.start : area->columns.start;
2477 int32_t end = IsBlock(aSide) ? area->rows.end : area->columns.end;
2478 if (IsStart(aSide)) {
2479 if (start >= aMin) {
2480 if (start <= aMax) {
2481 return start;
2482 }
2483 } else if (end >= aMin) {
2484 return aMin;
2485 }
2486 } else {
2487 if (end <= aMax) {
2488 if (end >= aMin) {
2489 return end;
2490 }
2491 } else if (start <= aMax) {
2492 return aMax;
2493 }
2494 }
2495 }
2496 return 0; // no match
2497 }
2498
2499 /**
2500 * A convenience method to lookup a name in 'grid-template-areas'.
2501 * @return null if not found
2502 */
2503 const NamedArea* FindNamedArea(nsAtom* aName) const {
2504 if (mStylePosition->mGridTemplateAreas.IsNone()) {
2505 return nullptr;
2506 }
2507 const auto areas = mStylePosition->mGridTemplateAreas.AsAreas();
2508 for (const NamedArea& area : areas->areas.AsSpan()) {
2509 if (area.name.AsAtom() == aName) {
2510 return &area;
2511 }
2512 }
2513 return nullptr;
2514 }
2515
2516 // Some style data references, for easy access.
2517 const nsStylePosition* mStylePosition;
2518 const ImplicitNamedAreas* mAreas;
2519 // The expanded list of line-names. Each entry is usually a single NameList,
2520 // but can be multiple in the case where repeat() expands to something that
2521 // has a line name list at the end.
2522 nsTArray<SmallPointerArray<const NameList>> mExpandedLineNames;
2523 // The repeat(auto-fill/fit) track value, if any. (always empty for subgrid)
2524 Span<const StyleOwnedSlice<StyleCustomIdent>> mTrackAutoRepeatLineNames;
2525 // The index of the repeat(auto-fill/fit) track, or zero if there is none.
2526 uint32_t mRepeatAutoStart;
2527 // The index one past the end of the repeat(auto-fill/fit) tracks. Equal to
2528 // mRepeatAutoStart if there are no repeat(auto-fill/fit) tracks.
2529 uint32_t mRepeatAutoEnd;
2530 // The total number of repeat tracks minus 1.
2531 int32_t mRepeatEndDelta;
2532 // The end of the line name lists with repeat(auto-fill/fit) tracks accounted
2533 // for.
2534 uint32_t mTemplateLinesEnd;
2535
2536 // The parent line map, or null if this map isn't for a subgrid.
2537 const LineNameMap* mParentLineNameMap;
2538 // The subgrid's range, or null if this map isn't for a subgrid.
2539 const LineRange* mRange;
2540 // True if the subgrid/parent axes progresses in the same direction.
2541 const bool mIsSameDirection;
2542 // True if the subgrid and parent have orthogonal writing modes.
2543 const bool mIsOrthogonal;
2544
2545 // True if there is a specified repeat(auto-fill/fit) track.
2546 bool mHasRepeatAuto;
2547};
2548
2549struct CachedIntrinsicSizes;
2550
2551/**
2552 * State for the tracks in one dimension.
2553 */
2554struct nsGridContainerFrame::Tracks {
2555 explicit Tracks(LogicalAxis aAxis)
2556 : mContentBoxSize(NS_UNCONSTRAINEDSIZE),
2557 mGridGap(NS_UNCONSTRAINEDSIZE),
2558 mStateUnion(TrackSize::StateBits::eNone),
2559 mAxis(aAxis),
2560 mCanResolveLineRangeSize(false),
2561 mIsMasonry(false) {
2562 mBaselineSubtreeAlign[BaselineSharingGroup::First] = StyleAlignFlags::AUTO;
2563 mBaselineSubtreeAlign[BaselineSharingGroup::Last] = StyleAlignFlags::AUTO;
2564 }
2565
2566 void Initialize(const TrackSizingFunctions& aFunctions,
2567 const NonNegativeLengthPercentageOrNormal& aGridGap,
2568 uint32_t aNumTracks, nscoord aContentBoxSize);
2569
2570 /**
2571 * Return the union of the state bits for the tracks in aRange.
2572 */
2573 TrackSize::StateBits StateBitsForRange(const LineRange& aRange) const;
2574
2575 // Some data we collect for aligning baseline-aligned items.
2576 struct ItemBaselineData {
2577 uint32_t mBaselineTrack;
2578 nscoord mBaseline;
2579 nscoord mSize;
2580 GridItemInfo* mGridItem;
2581 static bool IsBaselineTrackLessThan(const ItemBaselineData& a,
2582 const ItemBaselineData& b) {
2583 return a.mBaselineTrack < b.mBaselineTrack;
2584 }
2585 };
2586
2587 /**
2588 * Calculate baseline offsets for the given set of items.
2589 * Helper for InitialzeItemBaselines.
2590 */
2591 void CalculateItemBaselines(nsTArray<ItemBaselineData>& aBaselineItems,
2592 BaselineSharingGroup aBaselineGroup);
2593
2594 /**
2595 * Initialize grid item baseline state and offsets.
2596 */
2597 void InitializeItemBaselines(GridReflowInput& aGridRI,
2598 nsTArray<GridItemInfo>& aGridItems);
2599
2600 /**
2601 * A masonry axis has four baseline alignment sets and each set can have
2602 * a first- and last-baseline alignment group, for a total of eight possible
2603 * baseline alignment groups, as follows:
2604 * set 1: the first item in each `start` or `stretch` grid track
2605 * set 2: the last item in each `start` grid track
2606 * set 3: the last item in each `end` or `stretch` grid track
2607 * set 4: the first item in each `end` grid track
2608 * (`start`/`end`/`stretch` refers to the relevant `align/justify-tracks`
2609 * value of the (grid-axis) start track for the item) Baseline-alignment for
2610 * set 1 and 2 always adjusts the item's padding or margin on the start side,
2611 * and set 3 and 4 on the end side, for both first- and last-baseline groups
2612 * in the set. (This is similar to regular grid which always adjusts
2613 * first-baseline groups on the start side and last-baseline groups on the
2614 * end-side. The crux is that those groups are always aligned to the track's
2615 * start/end side respectively.)
2616 */
2617 struct BaselineAlignmentSet {
2618 bool MatchTrackAlignment(StyleAlignFlags aTrackAlignment) const {
2619 if (mTrackAlignmentSet == BaselineAlignmentSet::StartStretch) {
2620 return aTrackAlignment == StyleAlignFlags::START ||
2621 (aTrackAlignment == StyleAlignFlags::STRETCH &&
2622 mItemSet == BaselineAlignmentSet::FirstItems);
2623 }
2624 return aTrackAlignment == StyleAlignFlags::END ||
2625 (aTrackAlignment == StyleAlignFlags::STRETCH &&
2626 mItemSet == BaselineAlignmentSet::LastItems);
2627 }
2628
2629 enum ItemSet { FirstItems, LastItems };
2630 ItemSet mItemSet = FirstItems;
2631 enum TrackAlignmentSet { StartStretch, EndStretch };
2632 TrackAlignmentSet mTrackAlignmentSet = StartStretch;
2633 };
2634 void InitializeItemBaselinesInMasonryAxis(
2635 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
2636 BaselineAlignmentSet aSet, const nsSize& aContainerSize,
2637 nsTArray<nscoord>& aTrackSizes,
2638 nsTArray<ItemBaselineData>& aFirstBaselineItems,
2639 nsTArray<ItemBaselineData>& aLastBaselineItems);
2640
2641 /**
2642 * Apply the additional alignment needed to align the baseline-aligned subtree
2643 * the item belongs to within its baseline track.
2644 */
2645 void AlignBaselineSubtree(const GridItemInfo& aGridItem) const;
2646
2647 static TrackSize::StateBits SelectorForPhase(TrackSizingPhase aPhase,
2648 SizingConstraint aConstraint) {
2649 switch (aPhase) {
2650 case TrackSizingPhase::IntrinsicMinimums:
2651 return TrackSize::eIntrinsicMinSizing;
2652 case TrackSizingPhase::ContentBasedMinimums:
2653 return aConstraint == SizingConstraint::MinContent
2654 ? TrackSize::eIntrinsicMinSizing
2655 : TrackSize::eMinOrMaxContentMinSizing;
2656 case TrackSizingPhase::MaxContentMinimums:
2657 return aConstraint == SizingConstraint::MaxContent
2658 ? (TrackSize::eMaxContentMinSizing |
2659 TrackSize::eAutoMinSizing)
2660 : TrackSize::eMaxContentMinSizing;
2661 case TrackSizingPhase::IntrinsicMaximums:
2662 return TrackSize::eIntrinsicMaxSizing;
2663 case TrackSizingPhase::MaxContentMaximums:
2664 return TrackSize::eAutoOrMaxContentMaxSizing;
2665 }
2666 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"
, 2666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 2666); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); __builtin_unreachable(); } while (
false)
;
2667 }
2668
2669 // Some data we collect on each item that spans more than one track for step 3
2670 // and 4 of the Track Sizing Algorithm in ResolveIntrinsicSize below.
2671 // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
2672 struct SpanningItemData final {
2673 uint32_t mSpan;
2674 TrackSize::StateBits mState;
2675 LineRange mLineRange;
2676 EnumeratedArray<GridIntrinsicSizeType, nscoord> mSizes;
2677 nsIFrame* mFrame;
2678
2679 static bool IsSpanLessThan(const SpanningItemData& a,
2680 const SpanningItemData& b) {
2681 return a.mSpan < b.mSpan;
2682 }
2683
2684 nscoord SizeContributionForPhase(TrackSizingPhase aPhase) const {
2685 return mSizes[SizeTypeForPhase(aPhase)];
2686 }
2687
2688#ifdef DEBUG1
2689 void Dump() const {
2690 printf(
2691 "SpanningItemData { mSpan: %d, mState: %d, mLineRange: (%d, %d), "
2692 "mSizes: {MinContribution: %d, MinContentContribution: %d, "
2693 "MaxContentContribution: %d}, mFrame: %p\n",
2694 mSpan, mState, mLineRange.mStart, mLineRange.mEnd,
2695 mSizes[GridIntrinsicSizeType::MinContribution],
2696 mSizes[GridIntrinsicSizeType::MinContentContribution],
2697 mSizes[GridIntrinsicSizeType::MaxContentContribution], mFrame);
2698 }
2699#endif
2700 };
2701
2702 using FitContentClamper =
2703 std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
2704
2705 // Helper method for ResolveIntrinsicSize.
2706 bool GrowSizeForSpanningItems(
2707 TrackSizingStep aStep, TrackSizingPhase aPhase,
2708 nsTArray<SpanningItemData>::iterator aIter,
2709 nsTArray<SpanningItemData>::iterator aIterEnd,
2710 nsTArray<uint32_t>& aTracks, TrackPlan& aTrackPlan, ItemPlan& aItemPlan,
2711 SizingConstraint aConstraint, bool aIsGridIntrinsicSizing,
2712 const TrackSizingFunctions& aFunctions,
2713 const FitContentClamper& aFitContentClamper = nullptr,
2714 bool aNeedInfinitelyGrowableFlag = false);
2715
2716 // Helper method for calculating CachedIntrinsicSizes.mMinSizeClamp.
2717 //
2718 // The caller should set ItemState::eClampMarginBoxMinSize on the
2719 // corresponding grid item if this returns something.
2720 Maybe<nscoord> ComputeMinSizeClamp(const TrackSizingFunctions& aFunctions,
2721 nscoord aPercentageBasis,
2722 const LineRange& aLineRange) const {
2723 return ComputeMinSizeClamp(aFunctions, aPercentageBasis, aLineRange,
2724 StateBitsForRange(aLineRange));
2725 }
2726
2727 // More efficient version of ComputeMinSizeClamp if the caller has already
2728 // computed the state bits for this line range.
2729 Maybe<nscoord> ComputeMinSizeClamp(const TrackSizingFunctions& aFunctions,
2730 nscoord aPercentageBasis,
2731 const LineRange& aLineRange,
2732 const TrackSize::StateBits aState) const;
2733
2734 /**
2735 * Resolve Intrinsic Track Sizes.
2736 * https://drafts.csswg.org/css-grid-2/#algo-content
2737 */
2738 void ResolveIntrinsicSize(GridReflowInput& aGridRI,
2739 nsTArray<GridItemInfo>& aGridItems,
2740 const TrackSizingFunctions& aFunctions,
2741 LineRange GridArea::* aRange,
2742 nscoord aPercentageBasis,
2743 SizingConstraint aConstraint);
2744
2745 /**
2746 * Helper for ResolveIntrinsicSize. It implements "Resolve Intrinsic Track
2747 * Sizes" step 2: "Size tracks to fit non-spanning items" in the spec.
2748 * https://drafts.csswg.org/css-grid-2/#algo-single-span-items
2749 */
2750 void ResolveIntrinsicSizeForNonSpanningItems(
2751 GridReflowInput& aGridRI, const TrackSizingFunctions& aFunctions,
2752 nscoord aPercentageBasis, SizingConstraint aConstraint,
2753 const LineRange& aRange, const GridItemInfo& aGridItem);
2754
2755 // Helper method that returns the track size to use in §12.5.1.2
2756 // https://drafts.csswg.org/css-grid-2/#extra-space
2757 static nscoord StartSizeInDistribution(TrackSizingPhase aPhase,
2758 const TrackSize& aSize) {
2759 switch (aPhase) {
2760 case TrackSizingPhase::IntrinsicMinimums:
2761 case TrackSizingPhase::ContentBasedMinimums:
2762 case TrackSizingPhase::MaxContentMinimums:
2763 return aSize.mBase;
2764 case TrackSizingPhase::IntrinsicMaximums:
2765 case TrackSizingPhase::MaxContentMaximums:
2766 if (aSize.mLimit == NS_UNCONSTRAINEDSIZE) {
2767 return aSize.mBase;
2768 }
2769 return aSize.mLimit;
2770 }
2771 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"
, 2771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected phase" ")"); do { MOZ_CrashSequence
(__null, 2771); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false); __builtin_unreachable(); } while (
false)
;
2772 }
2773
2774 /**
2775 * Collect the tracks which are growable (matching the sizing step/phase
2776 * and sizing constraint) into aGrowableTracks, and return the amount of
2777 * space that can be used to grow those tracks. This method implements
2778 * CSS Grid 2 §12.5.1.2.
2779 * https://drafts.csswg.org/css-grid-2/#extra-space
2780 */
2781 nscoord CollectGrowable(TrackSizingStep aStep, TrackSizingPhase aPhase,
2782 nscoord aAvailableSpace, const LineRange& aRange,
2783 SizingConstraint aConstraint,
2784 nsTArray<uint32_t>& aGrowableTracks) const {
2785 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"
, 2785); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0"
") (" "why call me?" ")"); do { MOZ_CrashSequence(__null, 2785
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2786 nscoord space = aAvailableSpace - mGridGap * (aRange.Extent() - 1);
2787 const TrackSize::StateBits selector = SelectorForPhase(aPhase, aConstraint);
2788 for (auto i : aRange.Range()) {
2789 const TrackSize& sz = mSizes[i];
2790 space -= StartSizeInDistribution(aPhase, sz);
2791 if (space <= 0) {
2792 return 0;
2793 }
2794 // Only flex tracks can be modified during step 4.
2795 if (aStep == TrackSizingStep::Flex &&
2796 !(sz.mState & TrackSize::eFlexMaxSizing)) {
2797 continue;
2798 }
2799 if (sz.mState & selector) {
2800 aGrowableTracks.AppendElement(i);
2801 }
2802 }
2803 return aGrowableTracks.IsEmpty() ? 0 : space;
2804 }
2805
2806 void CopyPlanToSize(TrackSizingPhase aPhase, const TrackPlan& aTrackPlan,
2807 bool aNeedInfinitelyGrowableFlag) {
2808 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", 2808)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrackPlan.Length() == mSizes.Length()"
")"); do { MOZ_CrashSequence(__null, 2808); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2809 auto plan = aTrackPlan.begin();
2810 auto sz = mSizes.begin();
2811 for (; plan != aTrackPlan.end() && sz != mSizes.end(); plan++, sz++) {
2812 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", 2812)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "plan->mBase >= 0"
")"); do { MOZ_CrashSequence(__null, 2812); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2813 switch (aPhase) {
2814 case TrackSizingPhase::IntrinsicMinimums:
2815 case TrackSizingPhase::ContentBasedMinimums:
2816 case TrackSizingPhase::MaxContentMinimums:
2817 sz->mBase = plan->mBase;
2818 break;
2819 case TrackSizingPhase::IntrinsicMaximums:
2820 if (plan->mState & TrackSize::eModified) {
2821 if (sz->mLimit == NS_UNCONSTRAINEDSIZE &&
2822 aNeedInfinitelyGrowableFlag) {
2823 sz->mState |= TrackSize::eInfinitelyGrowable;
2824 }
2825 sz->mLimit = plan->mBase;
2826 }
2827 break;
2828 case TrackSizingPhase::MaxContentMaximums:
2829 if (plan->mState & TrackSize::eModified) {
2830 sz->mLimit = plan->mBase;
2831 }
2832 sz->mState &= ~TrackSize::eInfinitelyGrowable;
2833 break;
2834 }
2835 }
2836 }
2837
2838 /**
2839 * Distribute aAvailableSpace to the planned base size for aGrowableTracks
2840 * up to their limits, then distribute the remaining space beyond the limits.
2841 */
2842 void DistributeToTrackSizes(
2843 TrackSizingStep aStep, TrackSizingPhase aPhase, nscoord aAvailableSpace,
2844 TrackPlan& aTrackPlan, ItemPlan& aItemPlan,
2845 const nsTArray<uint32_t>& aGrowableTracks, SizingConstraint aConstraint,
2846 const TrackSizingFunctions& aFunctions,
2847 const FitContentClamper& aFitContentClamper) const {
2848 aItemPlan.Initialize(aPhase, aGrowableTracks, *this);
2849 nscoord space = aAvailableSpace;
2850 if (aStep == TrackSizingStep::Flex) {
2851 space = aTrackPlan.DistributeToFlexTrackSizes(space, aGrowableTracks,
2852 aFunctions, *this);
2853 } else {
2854 space = aItemPlan.GrowTracksToLimit(space, aGrowableTracks,
2855 aFitContentClamper);
2856 }
2857
2858 if (space > 0) {
2859 uint32_t numGrowable =
2860 aItemPlan.MarkExcludedTracks(aPhase, aGrowableTracks, aConstraint);
2861 aItemPlan.GrowSelectedTracksUnlimited(space, aGrowableTracks, numGrowable,
2862 aFitContentClamper);
2863 }
2864
2865 for (uint32_t track : aGrowableTracks) {
2866 nscoord& plannedSize = aTrackPlan[track].mBase;
2867 nscoord itemIncurredSize = aItemPlan[track].mBase;
2868 if (plannedSize < itemIncurredSize) {
2869 plannedSize = itemIncurredSize;
2870 }
2871 }
2872 }
2873
2874 /**
2875 * Distribute aAvailableSize to the tracks. This implements 12.6 at:
2876 * https://drafts.csswg.org/css-grid-2/#algo-grow-tracks
2877 */
2878 void DistributeFreeSpace(nscoord aAvailableSize) {
2879 const uint32_t numTracks = mSizes.Length();
2880 if (MOZ_UNLIKELY(numTracks == 0 || aAvailableSize <= 0)(__builtin_expect(!!(numTracks == 0 || aAvailableSize <= 0
), 0))
) {
2881 return;
2882 }
2883 if (aAvailableSize == NS_UNCONSTRAINEDSIZE) {
2884 for (TrackSize& sz : mSizes) {
2885 sz.mBase = sz.mLimit;
2886 }
2887 } else {
2888 // Compute free space and count growable tracks.
2889 nscoord space = aAvailableSize;
2890 uint32_t numGrowable = numTracks;
2891 for (const TrackSize& sz : mSizes) {
2892 space -= sz.mBase;
2893 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", 2893)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "sz.mBase <= sz.mLimit"
")"); do { MOZ_CrashSequence(__null, 2893); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2894 if (sz.mBase == sz.mLimit) {
2895 --numGrowable;
2896 }
2897 }
2898 // Distribute the free space evenly to the growable tracks. If not exactly
2899 // divisable the remainder is added to the leading tracks.
2900 while (space > 0 && numGrowable) {
2901 nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
2902 for (TrackSize& sz : mSizes) {
2903 if (sz.mBase == sz.mLimit) {
2904 continue;
2905 }
2906 nscoord newBase = sz.mBase + spacePerTrack;
2907 if (newBase >= sz.mLimit) {
2908 space -= sz.mLimit - sz.mBase;
2909 sz.mBase = sz.mLimit;
2910 --numGrowable;
2911 } else {
2912 space -= spacePerTrack;
2913 sz.mBase = newBase;
2914 }
2915 if (space <= 0) {
2916 break;
2917 }
2918 }
2919 }
2920 }
2921 }
2922
2923 /**
2924 * Implements "12.7.1. Find the Size of an 'fr'".
2925 * https://drafts.csswg.org/css-grid-2/#algo-find-fr-size
2926 * (The returned value is a 'nscoord' divided by a factor - a floating type
2927 * is used to avoid intermediary rounding errors.)
2928 */
2929 float FindFrUnitSize(const LineRange& aRange,
2930 const nsTArray<uint32_t>& aFlexTracks,
2931 const TrackSizingFunctions& aFunctions,
2932 nscoord aSpaceToFill) const;
2933
2934 /**
2935 * Implements the "find the used flex fraction" part of StretchFlexibleTracks.
2936 * (The returned value is a 'nscoord' divided by a factor - a floating type
2937 * is used to avoid intermediary rounding errors.)
2938 */
2939 float FindUsedFlexFraction(GridReflowInput& aGridRI,
2940 const nsTArray<GridItemInfo>& aGridItems,
2941 const nsTArray<uint32_t>& aFlexTracks,
2942 const TrackSizingFunctions& aFunctions,
2943 nscoord aAvailableSize) const;
2944
2945 /**
2946 * Implements "12.7. Expand Flexible Tracks"
2947 * https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
2948 */
2949 void StretchFlexibleTracks(GridReflowInput& aGridRI,
2950 const nsTArray<GridItemInfo>& aGridItems,
2951 const TrackSizingFunctions& aFunctions,
2952 nscoord aAvailableSize);
2953
2954 /**
2955 * Implements "12.3. Track Sizing Algorithm"
2956 * https://drafts.csswg.org/css-grid-2/#algo-track-sizing
2957 */
2958 void CalculateSizes(GridReflowInput& aGridRI,
2959 nsTArray<GridItemInfo>& aGridItems,
2960 const TrackSizingFunctions& aFunctions,
2961 nscoord aContentBoxSize, LineRange GridArea::* aRange,
2962 SizingConstraint aConstraint);
2963
2964 /**
2965 * Apply 'align/justify-content', whichever is relevant for this axis.
2966 * https://drafts.csswg.org/css-align-3/#propdef-align-content
2967 */
2968 void AlignJustifyContent(const nsStylePosition* aStyle,
2969 StyleContentDistribution aAligmentStyleValue,
2970 WritingMode aWM, nscoord aContentBoxSize,
2971 bool aIsSubgridded);
2972
2973 /**
2974 * Return the sum of the resolved track and gap sizes (without any packing
2975 * space introduced by align-content or justify-content.
2976 */
2977 nscoord TotalTrackSizeWithoutAlignment(
2978 const nsGridContainerFrame* aGridContainerFrame) const;
2979
2980 nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const {
2981 if (MOZ_UNLIKELY(mSizes.IsEmpty())(__builtin_expect(!!(mSizes.IsEmpty()), 0))) {
2982 // https://drafts.csswg.org/css-grid-2/#grid-definition
2983 // "... the explicit grid still contains one grid line in each axis."
2984 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", 2984
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLine == 0" ") ("
"We should only resolve line 1 in an empty grid" ")"); do { MOZ_CrashSequence
(__null, 2984); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2985 return nscoord(0);
2986 }
2987 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"
, 2987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aLine <= mSizes.Length()"
") (" "mSizes is too small" ")"); do { MOZ_CrashSequence(__null
, 2987); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2988 if (aSide == GridLineSide::BeforeGridGap) {
2989 if (aLine == 0) {
2990 return nscoord(0);
2991 }
2992 const TrackSize& sz = mSizes[aLine - 1];
2993 return sz.mPosition + sz.mBase;
2994 }
2995 if (aLine == mSizes.Length()) {
2996 return mContentBoxSize;
2997 }
2998 return mSizes[aLine].mPosition;
2999 }
3000
3001 nscoord SumOfGridTracksAndGaps() const {
3002 return SumOfGridTracks() + SumOfGridGaps();
3003 }
3004
3005 nscoord SumOfGridTracks() const {
3006 nscoord result = 0;
3007 for (const TrackSize& size : mSizes) {
3008 result += size.mBase;
3009 }
3010 return result;
3011 }
3012
3013 nscoord SumOfGridGaps() const {
3014 auto len = mSizes.Length();
3015 return MOZ_LIKELY(len > 1)(__builtin_expect(!!(len > 1), 1)) ? (len - 1) * mGridGap : 0;
3016 }
3017
3018 /**
3019 * Break before aRow, i.e. set the eBreakBefore flag on aRow and set the grid
3020 * gap before aRow to zero (and shift all rows after it by the removed gap).
3021 */
3022 void BreakBeforeRow(uint32_t aRow) {
3023 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", 3024
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3024 "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", 3024
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3025 nscoord prevRowEndPos = 0;
3026 if (aRow != 0) {
3027 auto& prevSz = mSizes[aRow - 1];
3028 prevRowEndPos = prevSz.mPosition + prevSz.mBase;
3029 }
3030 auto& sz = mSizes[aRow];
3031 const nscoord gap = sz.mPosition - prevRowEndPos;
3032 sz.mState |= TrackSize::eBreakBefore;
3033 if (gap != 0) {
3034 for (uint32_t i = aRow, len = mSizes.Length(); i < len; ++i) {
3035 mSizes[i].mPosition -= gap;
3036 }
3037 }
3038 }
3039
3040 /**
3041 * Set the size of aRow to aSize and adjust the position of all rows after it.
3042 */
3043 void ResizeRow(uint32_t aRow, nscoord aNewSize) {
3044 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", 3045
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3045); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3045 "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", 3045
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAxis == LogicalAxis::Block"
") (" "Should only be fragmenting in the block axis (between rows)"
")"); do { MOZ_CrashSequence(__null, 3045); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3046 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", 3046)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewSize >= 0" ")"
); do { MOZ_CrashSequence(__null, 3046); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3047 auto& sz = mSizes[aRow];
3048 nscoord delta = aNewSize - sz.mBase;
3049 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"
, 3049); } } while (false)
;
3050 sz.mBase = aNewSize;
3051 const uint32_t numRows = mSizes.Length();
3052 for (uint32_t r = aRow + 1; r < numRows; ++r) {
3053 mSizes[r].mPosition += delta;
3054 }
3055 }
3056
3057 nscoord ResolveSize(const LineRange& aRange) const {
3058 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", 3058)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCanResolveLineRangeSize"
")"); do { MOZ_CrashSequence(__null, 3058); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3059 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"
, 3059); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRange.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 3059); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3060 return aRange.ToLength(mSizes);
3061 }
3062
3063 // Returns the offset for the given track and baseline sharing group, or the
3064 // opposite group in the same track if unavailable.
3065 // Returns `Nothing()` if neither is set.
3066 Maybe<nscoord> GetBaseline(uint32_t aTrack,
3067 BaselineSharingGroup aBaselineSharingGroup) const {
3068 if (aTrack >= mBaselines.Length()) {
3069 return {};
3070 }
3071
3072 const auto& trackBaselines = mBaselines[aTrack];
3073 if (auto b = trackBaselines[aBaselineSharingGroup]) {
3074 return b;
3075 }
3076 if (auto b = trackBaselines[GetOppositeBaselineSharingGroup(
3077 aBaselineSharingGroup)]) {
3078 // First and last baseline offsets are from the start or end edges
3079 // respectively and requesting the opposite baseline requires adjusting
3080 // the offset to the opposite side.
3081 return Some(mSizes[aTrack].mBase - *b);
3082 }
3083
3084 return {};
3085 }
3086
3087#ifdef DEBUG1
3088 void Dump() const;
3089#endif
3090
3091 TrackPlan mSizes;
3092 nscoord mContentBoxSize;
3093 nscoord mGridGap;
3094
3095 // Stores per-track baselines for grid baseline calculations.
3096 CopyableTArray<PerBaseline<Maybe<nscoord>>> mBaselines;
3097
3098 // The union of the track min/max-sizing state bits in this axis.
3099 TrackSize::StateBits mStateUnion;
3100 LogicalAxis mAxis;
3101 // Used for aligning a baseline-aligned subtree of items. The only possible
3102 // values are StyleAlignFlags::{START,END,CENTER,AUTO}. AUTO means there are
3103 // no baseline-aligned items in any track in that axis.
3104 // There is one alignment value for each BaselineSharingGroup.
3105 PerBaseline<StyleAlignFlags> mBaselineSubtreeAlign;
3106 // True if track positions and sizes are final in this axis.
3107 bool mCanResolveLineRangeSize;
3108 // True if this axis has masonry layout.
3109 bool mIsMasonry;
3110};
3111
3112#ifdef DEBUG1
3113void nsGridContainerFrame::Tracks::Dump() const {
3114 const size_t numTracks = mSizes.Length();
3115 const char* trackName = mAxis == LogicalAxis::Inline ? "column" : "row";
3116
3117 auto BaselineToStr = [](Maybe<nscoord> aBaseline) {
3118 if (!aBaseline) {
3119 return std::string("not set");
3120 }
3121
3122 return std::to_string(*aBaseline);
3123 };
3124
3125 auto CoordToStr = [](nscoord aCoord) {
3126 return aCoord == NS_UNCONSTRAINEDSIZE ? std::string("unconstrained")
3127 : std::to_string(aCoord);
3128 };
3129
3130 fmt::print("{} {} {}{}, track union bits: ", numTracks,
3131 mIsMasonry ? "masonry" : "grid", trackName,
3132 numTracks > 1 ? "s" : "");
3133 TrackSize::DumpStateBits(mStateUnion);
3134 printf("\n");
3135
3136 for (uint32_t i = 0; i < numTracks; ++i) {
3137 fmt::print(" {} {}: ", trackName, i);
3138 mSizes[i].Dump();
3139 printf("\n");
3140 }
3141
3142 fmt::println(" first baseline: {}, last baseline: {}",
3143 BaselineToStr(GetBaseline(0, BaselineSharingGroup::First)),
3144 BaselineToStr(GetBaseline(mBaselines.Length() - 1,
3145 BaselineSharingGroup::Last)));
3146 fmt::println(" {} gap: {}, content-box {}-size: {}", trackName,
3147 CoordToStr(mGridGap),
3148 mAxis == LogicalAxis::Inline ? "inline" : "block",
3149 CoordToStr(mContentBoxSize));
3150}
3151#endif
3152
3153/**
3154 * Grid data shared by all continuations, owned by the first-in-flow.
3155 * The data is initialized from the first-in-flow's GridReflowInput at
3156 * the end of its reflow. Fragmentation will modify mRows.mSizes -
3157 * the mPosition to remove the row gap at the break boundary, the mState
3158 * by setting the eBreakBefore flag, and mBase is modified when we decide
3159 * to grow a row. mOriginalRowData is setup by the first-in-flow and
3160 * not modified after that. It's used for undoing the changes to mRows.
3161 * mCols, mGridItems, mAbsPosItems are used for initializing the grid
3162 * reflow input for continuations, see GridReflowInput::Initialize below.
3163 */
3164struct nsGridContainerFrame::SharedGridData {
3165 SharedGridData()
3166 : mCols(LogicalAxis::Inline),
3167 mRows(LogicalAxis::Block),
3168 mGenerateComputedGridInfo(false) {}
3169 Tracks mCols;
3170 Tracks mRows;
3171 struct RowData {
3172 nscoord mBase; // the original track size
3173 nscoord mGap; // the original gap before a track
3174 };
3175 nsTArray<RowData> mOriginalRowData;
3176 nsTArray<GridItemInfo> mGridItems;
3177 nsTArray<GridItemInfo> mAbsPosItems;
3178 bool mGenerateComputedGridInfo;
3179
3180 /**
3181 * Only set on the first-in-flow. Continuations will Initialize() their
3182 * GridReflowInput from it.
3183 */
3184 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, SharedGridData)static const mozilla::FramePropertyDescriptor<SharedGridData
>* Prop() { static const auto descriptor = mozilla::FramePropertyDescriptor
<SharedGridData>::NewWithDestructor<DeleteValue>(
); return &descriptor; }
3185};
3186
3187struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
3188 GridReflowInput(nsGridContainerFrame* aFrame, const ReflowInput& aRI)
3189 : GridReflowInput(aFrame, *aRI.mRenderingContext, &aRI,
3190 aRI.mStylePosition, aRI.GetWritingMode()) {}
3191 GridReflowInput(nsGridContainerFrame* aFrame, gfxContext& aRC)
3192 : GridReflowInput(aFrame, aRC, nullptr, aFrame->StylePosition(),
3193 aFrame->GetWritingMode()) {}
3194
3195 /**
3196 * Initialize our track sizes and grid item info using the shared
3197 * state from aGridContainerFrame first-in-flow.
3198 */
3199 void InitializeForContinuation(nsGridContainerFrame* aGridContainerFrame,
3200 nscoord aConsumedBSize) {
3201 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"
, 3202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridContainerFrame->GetPrevInFlow()"
") (" "don't call this on the first-in-flow" ")"); do { MOZ_CrashSequence
(__null, 3202); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3202 "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"
, 3202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridContainerFrame->GetPrevInFlow()"
") (" "don't call this on the first-in-flow" ")"); do { MOZ_CrashSequence
(__null, 3202); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3203 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"
, 3204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()"
") (" "shouldn't have any item data yet" ")"); do { MOZ_CrashSequence
(__null, 3204); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3204 "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"
, 3204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.IsEmpty() && mAbsPosItems.IsEmpty()"
") (" "shouldn't have any item data yet" ")"); do { MOZ_CrashSequence
(__null, 3204); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3205
3206 // Get the SharedGridData from the first-in-flow. Also calculate the number
3207 // of fragments before this so that we can figure out our start row below.
3208 uint32_t fragment = 0;
3209 nsIFrame* firstInFlow = aGridContainerFrame;
3210 for (auto pif = aGridContainerFrame->GetPrevInFlow(); pif;
3211 pif = pif->GetPrevInFlow()) {
3212 ++fragment;
3213 firstInFlow = pif;
3214 }
3215 mSharedGridData = firstInFlow->GetProperty(SharedGridData::Prop());
3216 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"
, 3216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSharedGridData"
") (" "first-in-flow must have SharedGridData" ")"); do { MOZ_CrashSequence
(__null, 3216); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3217
3218 // Find the start row for this fragment and undo breaks after that row
3219 // since the breaks might be different from the last reflow.
3220 auto& rowSizes = mSharedGridData->mRows.mSizes;
3221 const uint32_t numRows = rowSizes.Length();
3222 mStartRow = numRows;
3223 for (uint32_t row = 0, breakCount = 0; row < numRows; ++row) {
3224 if (rowSizes[row].mState & TrackSize::eBreakBefore) {
3225 if (fragment == ++breakCount) {
3226 mStartRow = row;
3227 mFragBStart = rowSizes[row].mPosition;
3228 // Restore the original size for |row| and grid gaps / state after it.
3229 const auto& origRowData = mSharedGridData->mOriginalRowData;
3230 rowSizes[row].mBase = origRowData[row].mBase;
3231 nscoord prevEndPos = rowSizes[row].mPosition + rowSizes[row].mBase;
3232 while (++row < numRows) {
3233 auto& sz = rowSizes[row];
3234 const auto& orig = origRowData[row];
3235 sz.mPosition = prevEndPos + orig.mGap;
3236 sz.mBase = orig.mBase;
3237 sz.mState &= ~TrackSize::eBreakBefore;
3238 prevEndPos = sz.mPosition + sz.mBase;
3239 }
3240 break;
3241 }
3242 }
3243 }
3244 if (mStartRow == numRows || aGridContainerFrame->IsRowMasonry()) {
3245 // All of the grid's rows fit inside of previous grid-container fragments,
3246 // or it's a masonry axis.
3247 mFragBStart = aConsumedBSize;
3248 }
3249
3250 // Copy the shared track state.
3251 // XXX consider temporarily swapping the array elements instead and swapping
3252 // XXX them back after we're done reflowing, for better performance.
3253 // XXX (bug 1252002)
3254 mCols = mSharedGridData->mCols;
3255 mRows = mSharedGridData->mRows;
3256
3257 if (firstInFlow->GetProperty(UsedTrackSizes::Prop())) {
3258 auto* prop = aGridContainerFrame->GetOrCreateDeletableProperty(
3259 UsedTrackSizes::Prop());
3260 prop->mCanResolveLineRangeSize = {true, true};
3261 prop->mTrackPlans[LogicalAxis::Inline].Assign(mCols.mSizes);
3262 prop->mTrackPlans[LogicalAxis::Block].Assign(mRows.mSizes);
3263 }
3264
3265 // Copy item data from each child's first-in-flow data in mSharedGridData.
3266 // XXX NOTE: This is O(n^2) in the number of items. (bug 1252186)
3267 mIter.Reset();
3268 for (; !mIter.AtEnd(); mIter.Next()) {
3269 nsIFrame* child = *mIter;
3270 nsIFrame* childFirstInFlow = child->FirstInFlow();
3271 DebugOnly<size_t> len = mGridItems.Length();
3272 for (auto& itemInfo : mSharedGridData->mGridItems) {
3273 if (itemInfo.mFrame == childFirstInFlow) {
3274 auto item =
3275 mGridItems.AppendElement(GridItemInfo(child, itemInfo.mArea));
3276 // Copy the item's baseline data so that the item's last fragment can
3277 // do 'last baseline' alignment if necessary.
3278 item->mState[LogicalAxis::Block] |=
3279 itemInfo.mState[LogicalAxis::Block] & ItemState::eAllBaselineBits;
3280 item->mState[LogicalAxis::Inline] |=
3281 itemInfo.mState[LogicalAxis::Inline] &
3282 ItemState::eAllBaselineBits;
3283 item->mBaselineOffset[LogicalAxis::Block] =
3284 itemInfo.mBaselineOffset[LogicalAxis::Block];
3285 item->mBaselineOffset[LogicalAxis::Inline] =
3286 itemInfo.mBaselineOffset[LogicalAxis::Inline];
3287 item->mState[LogicalAxis::Block] |=
3288 itemInfo.mState[LogicalAxis::Block] & ItemState::eAutoPlacement;
3289 item->mState[LogicalAxis::Inline] |=
3290 itemInfo.mState[LogicalAxis::Inline] & ItemState::eAutoPlacement;
3291 break;
3292 }
3293 }
3294 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", 3294
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridItems.Length() == len + 1"
") (" "can't find GridItemInfo" ")"); do { MOZ_CrashSequence
(__null, 3294); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3295 }
3296
3297 if (auto* absCB = aGridContainerFrame->GetAbsoluteContainingBlock()) {
3298 // Prepare absolute frames before constructing GridItemInfo.
3299 absCB->PrepareAbsoluteFrames(aGridContainerFrame);
3300 }
3301 // XXX NOTE: This is O(n^2) in the number of abs.pos. items. (bug 1252186)
3302 const nsFrameList& absPosChildren =
3303 aGridContainerFrame->GetChildList(FrameChildListID::Absolute);
3304 for (auto f : absPosChildren) {
3305 nsIFrame* childFirstInFlow = f->FirstInFlow();
3306 DebugOnly<size_t> len = mAbsPosItems.Length();
3307 for (auto& itemInfo : mSharedGridData->mAbsPosItems) {
3308 if (itemInfo.mFrame == childFirstInFlow) {
3309 mAbsPosItems.AppendElement(GridItemInfo(f, itemInfo.mArea));
3310 break;
3311 }
3312 }
3313 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", 3313
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAbsPosItems.Length() == len + 1"
") (" "can't find GridItemInfo" ")"); do { MOZ_CrashSequence
(__null, 3313); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3314 }
3315
3316 // Copy in the computed grid info state bit
3317 if (mSharedGridData->mGenerateComputedGridInfo) {
3318 aGridContainerFrame->AddStateBits(NS_STATE_GRID_COMPUTED_INFO);
3319 }
3320 }
3321
3322 /**
3323 * Calculate our track sizes in the given axis.
3324 */
3325 void CalculateTrackSizesForAxis(LogicalAxis aAxis, const Grid& aGrid,
3326 nscoord aCBSize,
3327 SizingConstraint aConstraint);
3328
3329 /**
3330 * Invalidate track sizes for the given axis by clearing track sizing bits for
3331 * all grid items and mark the track sizes and positions as needing recompute.
3332 *
3333 * This helper must be called before invoking CalculateTrackSizesForAxis()
3334 * again in aAxis; otherwise, assertions will fire.
3335 */
3336 void InvalidateTrackSizesForAxis(LogicalAxis aAxis);
3337
3338 /**
3339 * Return the percentage basis for a grid item in its writing-mode based on
3340 * track sizes and the grid area occupied by the grid item.
3341 *
3342 * @param aAxis the axis we're currently calculating track sizes for
3343 */
3344 LogicalSize PercentageBasisFor(LogicalAxis aAxis,
3345 const GridItemInfo& aGridItem) const;
3346
3347 /**
3348 * Return the containing block for a grid item occupying aArea.
3349 */
3350 LogicalRect ContainingBlockFor(const GridArea& aArea) const;
3351
3352 /**
3353 * Return the containing block for an abs.pos. grid item occupying aArea.
3354 * Any 'auto' lines in the grid area will be aligned with grid container
3355 * containing block on that side.
3356 * @param aGridOrigin the origin of the grid
3357 * @param aGridCB the grid container containing block (its padding area)
3358 */
3359 LogicalRect ContainingBlockForAbsPos(const GridArea& aArea,
3360 const LogicalPoint& aGridOrigin,
3361 const LogicalRect& aGridCB) const;
3362
3363 /**
3364 * Apply `align/justify-content` alignment in our masonry axis.
3365 * This aligns the "masonry box" within our content box size.
3366 */
3367 void AlignJustifyContentInMasonryAxis(nscoord aMasonryBoxSize,
3368 nscoord aContentBoxSize);
3369 /**
3370 * Apply `align/justify-tracks` alignment in our masonry axis.
3371 */
3372 void AlignJustifyTracksInMasonryAxis(const LogicalSize& aContentSize,
3373 const nsSize& aContainerSize);
3374
3375 // Recursive helper for CollectSubgridItemsForAxis().
3376 static void CollectSubgridItemsForAxisHelper(
3377 LogicalAxis aAxis, WritingMode aContainerWM,
3378 const LineRange& aRangeInAxis, const LineRange& aRangeInOppositeAxis,
3379 const GridItemInfo& aItem, const nsTArray<GridItemInfo>& aItems,
3380 nsTArray<GridItemInfo>& aResult) {
3381 const auto oppositeAxis = GetOrthogonalAxis(aAxis);
3382 bool itemIsSubgridInOppositeAxis = aItem.IsSubgrid(oppositeAxis);
3383 auto subgridWM = aItem.mFrame->GetWritingMode();
3384 bool isOrthogonal = subgridWM.IsOrthogonalTo(aContainerWM);
3385 bool isSameDirInAxis =
3386 subgridWM.ParallelAxisStartsOnSameSide(aAxis, aContainerWM);
3387 bool isSameDirInOppositeAxis =
3388 subgridWM.ParallelAxisStartsOnSameSide(oppositeAxis, aContainerWM);
3389 if (isOrthogonal) {
3390 // We'll Transpose the area below so these needs to be transposed as well.
3391 std::swap(isSameDirInAxis, isSameDirInOppositeAxis);
3392 }
3393 uint32_t offsetInAxis = aRangeInAxis.mStart;
3394 uint32_t gridEndInAxis = aRangeInAxis.Extent();
3395 uint32_t offsetInOppositeAxis = aRangeInOppositeAxis.mStart;
3396 uint32_t gridEndInOppositeAxis = aRangeInOppositeAxis.Extent();
3397 for (const auto& subgridItem : aItems) {
3398 auto newItem = aResult.AppendElement(
3399 isOrthogonal ? subgridItem.Transpose() : subgridItem);
3400 if (MOZ_UNLIKELY(!isSameDirInAxis)(__builtin_expect(!!(!isSameDirInAxis), 0))) {
3401 newItem->ReverseDirection(aAxis, gridEndInAxis);
3402 }
3403 newItem->mArea.LineRangeForAxis(aAxis).Translate(offsetInAxis);
3404 if (itemIsSubgridInOppositeAxis) {
3405 if (MOZ_UNLIKELY(!isSameDirInOppositeAxis)(__builtin_expect(!!(!isSameDirInOppositeAxis), 0))) {
3406 newItem->ReverseDirection(oppositeAxis, gridEndInOppositeAxis);
3407 }
3408 LineRange& range = newItem->mArea.LineRangeForAxis(oppositeAxis);
3409 range.Translate(offsetInOppositeAxis);
3410 }
3411 if (newItem->IsSubgrid(aAxis)) {
3412 auto* subgrid =
3413 subgridItem.SubgridFrame()->GetProperty(Subgrid::Prop());
3414 CollectSubgridItemsForAxisHelper(
3415 aAxis, aContainerWM, newItem->mArea.LineRangeForAxis(aAxis),
3416 newItem->mArea.LineRangeForAxis(oppositeAxis), *newItem,
3417 subgrid->mGridItems, aResult);
3418 }
3419 }
3420 }
3421
3422 // Copy all descendant items from all our subgrid children that are subgridded
3423 // in aAxis recursively into aResult. All item grid area's and state are
3424 // translated to our coordinates.
3425 void CollectSubgridItemsForAxis(LogicalAxis aAxis,
3426 nsTArray<GridItemInfo>& aResult) const {
3427 for (const auto& item : mGridItems) {
3428 if (item.IsSubgrid(aAxis)) {
3429 const auto oppositeAxis = GetOrthogonalAxis(aAxis);
3430 auto* subgrid = item.SubgridFrame()->GetProperty(Subgrid::Prop());
3431 CollectSubgridItemsForAxisHelper(
3432 aAxis, mWM, item.mArea.LineRangeForAxis(aAxis),
3433 item.mArea.LineRangeForAxis(oppositeAxis), item,
3434 subgrid->mGridItems, aResult);
3435 }
3436 }
3437 }
3438
3439 /**
3440 * Recursive helper for CopyBaselineMetricsToSubgridItems().
3441 *
3442 * @param aAxis The LogicalAxis for the axis whose baseline metrics we're
3443 * copying here (with respect to the outermost parent grid's
3444 * writing mode).
3445 * @param aContainerWM The writing mode of that outermost parent grid.
3446 * @param aSubgridFrame The subgrid whose subgrid-items we're considering
3447 * in this recursive traversal (whose items we're copying over
3448 * baseline-alignment metrics for).
3449 * @param aContainerGridItems The outermost parent grid's array of
3450 * GridItemInfo objects. (The final portion of this array is
3451 * all for subgrid items, and that's the portion that we're
3452 * recursively iterating over.)
3453 * @param aContainerGridItemsIdx [in/out] The index for the item that we're
3454 * currently considering in aContainerGridItemsIdx. When
3455 * this function returns, this will be the index just beyond the
3456 * last item that we handled here, i.e. the index of the next
3457 * item to be handled.
3458 */
3459 static void CopyBaselineMetricsToSubgridItemsHelper(
3460 LogicalAxis aAxis, WritingMode aContainerWM, nsIFrame* aSubgridFrame,
3461 const nsTArray<GridItemInfo>& aContainerGridItems,
3462 size_t& aContainerGridItemsIdx) {
3463 // Get the canonical GridItemInfo structs for the grid items that live
3464 // inside of aSubgridFrame:
3465 Subgrid* subgridProp = aSubgridFrame->GetProperty(Subgrid::Prop());
3466 nsTArray<GridItemInfo>& subgridItems = subgridProp->mGridItems;
3467
3468 // Use aSubgridFrame's writing-mode to determine subgridAxis.
3469 // Grids & subgrids store various data on a per-LogicalAxis basis, with
3470 // respect to their own WritingMode. Here, subgridAxis is aSubgridFrame's
3471 // axis that maps to the same physical axis that aAxis does for the
3472 // outermost parent grid.
3473 auto subgridWM = aSubgridFrame->GetWritingMode();
3474 bool isOrthogonal = subgridWM.IsOrthogonalTo(aContainerWM);
3475 LogicalAxis subgridAxis = isOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
3476
3477 // Do a parallel walk through (1) subgridItems and (2) the portion of
3478 // aContainerGridItems that starts at offset aContainerGridItems,
3479 // descending to traverse child subgrids own items as we encounter them in
3480 // subgridItems. We expect to have an exact correspondence, because this
3481 // is precisely how we built up this portion of aContainerGridItems in
3482 // CollectSubgridItemsForAxis. (But if we happen to overstep the end of an
3483 // array, or find a GridItemInfo for a frame that we don't expect, we
3484 // gracefully bail out.)
3485 for (auto& subgridItem : subgridItems) {
3486 if (MOZ_UNLIKELY(aContainerGridItemsIdx >=(__builtin_expect(!!(aContainerGridItemsIdx >= aContainerGridItems
.Length()), 0))
3487 aContainerGridItems.Length())(__builtin_expect(!!(aContainerGridItemsIdx >= aContainerGridItems
.Length()), 0))
) {
3488 // We failed to make the same traversal as CollectSubgridItemsForAxis;
3489 // whoops! This shouldn't happen; but if it does, we gracefully bail
3490 // out, instead of crashing.
3491 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"
, 3491); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Out-of-bounds aContainerGridItemsIdx"
")"); do { MOZ_CrashSequence(__null, 3491); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3492 return;
3493 }
3494 const auto& itemFromContainer =
3495 aContainerGridItems[aContainerGridItemsIdx];
3496 aContainerGridItemsIdx++;
3497
3498 if (MOZ_UNLIKELY(subgridItem.mFrame != itemFromContainer.mFrame)(__builtin_expect(!!(subgridItem.mFrame != itemFromContainer.
mFrame), 0))
) {
3499 // We failed to make the same traversal as CollectSubgridItemsForAxis;
3500 // whoops! This shouldn't happen; but if it does, we gracefully bail
3501 // out, instead of copying baseline-alignment data for the wrong frame.
3502 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"
, 3502); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Found unexpected frame during traversal"
")"); do { MOZ_CrashSequence(__null, 3502); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3503 return;
3504 }
3505
3506 // This pattern of bits will be truthy if the item is baseline-aligned in
3507 // this axis (in which case the exact pattern of bits will have some
3508 // additional significance that doesn't matter here, but we do need to
3509 // copy it over).
3510 const auto baselineStateBits =
3511 itemFromContainer.mState[aAxis] & ItemState::eAllBaselineBits;
3512
3513 if (subgridItem.IsSubgrid(subgridAxis)) {
3514 // This item is in fact a nested subgrid. It shouldn't itself be
3515 // baseline-aligned, but we need to make a recursive call to copy
3516 // baseline metrics to its items.
3517 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", 3519
); 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, 3519); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3518 "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", 3519
); 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, 3519); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3519 "(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", 3519
); 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, 3519); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3520 CopyBaselineMetricsToSubgridItemsHelper(
3521 aAxis, aContainerWM, subgridItem.SubgridFrame(),
3522 aContainerGridItems, aContainerGridItemsIdx);
3523 } else if (baselineStateBits) {
3524 // This item is a baseline-aligned grid item (in the subgrid that we're
3525 // traversing). Copy over its baseline metrics.
3526 subgridItem.mState[subgridAxis] |= baselineStateBits;
3527 subgridItem.mBaselineOffset[subgridAxis] =
3528 itemFromContainer.mBaselineOffset[aAxis];
3529 }
3530 }
3531 }
3532
3533 /**
3534 * This function here is responsible for propagating baseline-alignment
3535 * metrics for subgrid-items from mGridItems over to the "canonical"
3536 * GridItemInfo structs for those grid items (which live on the subgrid that
3537 * owns them). The outermost parent grid *computes* those metrics as part of
3538 * doing track sizing, but it does this using *temporary* GridItemInfo
3539 * objects for any grid items that live in subgrids (aka subgrid items). So
3540 * that's why we need to rescue this baseline-alignment information before
3541 * those temporary objects are discarded.
3542 *
3543 * (The temporary subgrid-items all live at the end of mGridItems; they were
3544 * appended there by CollectSubgridItemsForAxis(). So, it's important that
3545 * we perform the exact same traversal that CollectSubgridItemsForAxis() did,
3546 * in order to properly match up the temporary & canonical GridItemInfo
3547 * objects for these subgrid items.)
3548 */
3549 // traversal that CollectSubgridItemsForAxis (and its recursive helper) does.
3550 void CopyBaselineMetricsToSubgridItems(LogicalAxis aAxis,
3551 size_t aOriginalLength) {
3552 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"
, 3555); 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, 3555); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3553 "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"
, 3555); 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, 3555); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3554 "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"
, 3555); 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, 3555); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3555 "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"
, 3555); 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, 3555); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3556
3557 // This index 'subgridItemIdx' traverses the final portion of mGridItems,
3558 // the portion that currently has temporary GridItemInfo structs that we
3559 // built for the items that live in our subgrids. (Our caller is about to
3560 // discard this temporary portion of mGridItems, and we're trying to
3561 // transfer some baseline-alignment data to the canonical GridItemInfo
3562 // structs before that happens.)
3563 //
3564 // Our recursive helper updates subgridItemIdx internally. When this index
3565 // reaches mGridItems.Length(), we can stop looping; that means we've
3566 // finished copying out all the data from these temporary structs.
3567 size_t subgridItemIdx = aOriginalLength;
3568
3569 for (size_t i = 0;
3570 (i < aOriginalLength && subgridItemIdx < mGridItems.Length()); i++) {
3571 const auto& item = mGridItems[i];
3572 if (item.IsSubgrid(aAxis)) {
3573 CopyBaselineMetricsToSubgridItemsHelper(aAxis, mWM, item.SubgridFrame(),
3574 mGridItems, subgridItemIdx);
3575 }
3576 }
3577 }
3578
3579 Tracks& TracksFor(LogicalAxis aAxis) {
3580 return aAxis == LogicalAxis::Block ? mRows : mCols;
3581 }
3582 const Tracks& TracksFor(LogicalAxis aAxis) const {
3583 return aAxis == LogicalAxis::Block ? mRows : mCols;
3584 }
3585
3586 CSSOrderAwareFrameIterator mIter;
3587 const nsStylePosition* const mGridStyle;
3588 Tracks mCols;
3589 Tracks mRows;
3590 TrackSizingFunctions mColFunctions;
3591 TrackSizingFunctions mRowFunctions;
3592 /**
3593 * Info about each (normal flow) grid item.
3594 */
3595 nsTArray<GridItemInfo> mGridItems;
3596 /**
3597 * Info about each grid-aligned abs.pos. child.
3598 */
3599 nsTArray<GridItemInfo> mAbsPosItems;
3600
3601 /**
3602 * @note mReflowInput may be null when using the 2nd ctor above. In this case
3603 * we'll construct a dummy parent reflow input if we need it to calculate
3604 * min/max-content contributions when sizing tracks.
3605 */
3606 const ReflowInput* const mReflowInput;
3607 gfxContext& mRenderingContext;
3608 nsGridContainerFrame* const mFrame;
3609 /** [weak] owned by mFrame's first-in-flow. */
3610 SharedGridData* mSharedGridData = nullptr;
3611 /** Computed border+padding with mSkipSides applied. */
3612 LogicalMargin mBorderPadding;
3613 /**
3614 * BStart of this fragment in "grid space" (i.e. the concatenation of content
3615 * areas of all fragments). Equal to mRows.mSizes[mStartRow].mPosition,
3616 * or, if this fragment starts after the last row, the ConsumedBSize().
3617 */
3618 nscoord mFragBStart = 0;
3619 /** The start row for this fragment. */
3620 uint32_t mStartRow = 0;
3621 /**
3622 * The start row for the next fragment, if any. If mNextFragmentStartRow ==
3623 * mStartRow then there are no rows in this fragment.
3624 */
3625 uint32_t mNextFragmentStartRow = 0;
3626 /** Our tentative ApplySkipSides bits. */
3627 LogicalSides mSkipSides;
3628 const WritingMode mWM;
3629 /** Initialized lazily, when we find the fragmentainer. */
3630 bool mInFragmentainer = false;
3631 /** Set when the grid itself is having its intrinsic size measured. */
3632 bool mIsGridIntrinsicSizing = false;
3633
3634 private:
3635 GridReflowInput(nsGridContainerFrame* aFrame, gfxContext& aRenderingContext,
3636 const ReflowInput* aReflowInput,
3637 const nsStylePosition* aGridStyle, const WritingMode& aWM)
3638 : mIter(aFrame, FrameChildListID::Principal),
3639 mGridStyle(aGridStyle),
3640 mCols(LogicalAxis::Inline),
3641 mRows(LogicalAxis::Block),
3642 mColFunctions(mGridStyle->mGridTemplateColumns,
3643 mGridStyle->mGridAutoColumns, aFrame->IsColSubgrid()),
3644 mRowFunctions(mGridStyle->mGridTemplateRows, mGridStyle->mGridAutoRows,
3645 aFrame->IsRowSubgrid()),
3646 mReflowInput(aReflowInput),
3647 mRenderingContext(aRenderingContext),
3648 mFrame(aFrame),
3649 mBorderPadding(aWM),
3650 mSkipSides(aFrame->GetWritingMode()),
3651 mWM(aWM) {
3652 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", 3652)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aReflowInput || aReflowInput->mFrame == mFrame"
")"); do { MOZ_CrashSequence(__null, 3652); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3653 if (aReflowInput) {
3654 mBorderPadding = aReflowInput->ComputedLogicalBorderPadding(mWM);
3655 mSkipSides = aFrame->PreReflowBlockLevelLogicalSkipSides();
3656 mBorderPadding.ApplySkipSides(mSkipSides);
3657 }
3658 mCols.mIsMasonry = aFrame->IsColMasonry();
3659 mRows.mIsMasonry = aFrame->IsRowMasonry();
3660 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"
, 3661); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mCols.mIsMasonry && mRows.mIsMasonry)"
") (" "can't have masonry layout in both axes" ")"); do { MOZ_CrashSequence
(__null, 3661); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3661 "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"
, 3661); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(mCols.mIsMasonry && mRows.mIsMasonry)"
") (" "can't have masonry layout in both axes" ")"); do { MOZ_CrashSequence
(__null, 3661); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3662 }
3663};
3664
3665using GridReflowInput = nsGridContainerFrame::GridReflowInput;
3666
3667/**
3668 * The Grid implements grid item placement and the state of the grid -
3669 * the size of the explicit/implicit grid, which cells are occupied etc.
3670 */
3671struct MOZ_STACK_CLASS nsGridContainerFrame::Grid {
3672 explicit Grid(const Grid* aParentGrid = nullptr) : mParentGrid(aParentGrid) {}
3673
3674 /**
3675 * Place all child frames into the grid and expand the (implicit) grid as
3676 * needed. The allocated GridAreas are stored in the GridAreaProperty
3677 * frame property on the child frame.
3678 * @param aRepeatSizing the container's [min-|max-]*size - used to determine
3679 * the number of repeat(auto-fill/fit) tracks.
3680 */
3681 void PlaceGridItems(GridReflowInput& aGridRI,
3682 const RepeatTrackSizingInput& aRepeatSizing);
3683
3684 void SubgridPlaceGridItems(GridReflowInput& aParentGridRI, Grid* aParentGrid,
3685 const GridItemInfo& aGridItem);
3686
3687 /**
3688 * As above but for an abs.pos. child. Any 'auto' lines will be represented
3689 * by kAutoLine in the LineRange result.
3690 * @param aGridStart the first line in the final, but untranslated grid
3691 * @param aGridEnd the last line in the final, but untranslated grid
3692 */
3693 LineRange ResolveAbsPosLineRange(const StyleGridLine& aStart,
3694 const StyleGridLine& aEnd,
3695 const LineNameMap& aNameMap,
3696 LogicalAxis aAxis, uint32_t aExplicitGridEnd,
3697 int32_t aGridStart, int32_t aGridEnd,
3698 const nsStylePosition* aStyle);
3699
3700 /**
3701 * Return a GridArea for abs.pos. item with non-auto lines placed at
3702 * a definite line (1-based) with placement errors resolved. One or both
3703 * positions may still be 'auto'.
3704 * @param aChild the abs.pos. grid item to place
3705 * @param aStyle the StylePosition() for the grid container
3706 */
3707 GridArea PlaceAbsPos(nsIFrame* aChild, const LineNameMap& aColLineNameMap,
3708 const LineNameMap& aRowLineNameMap,
3709 const nsStylePosition* aStyle);
3710
3711 /**
3712 * Find the first column in row aLockedRow starting at aStartCol where aArea
3713 * could be placed without overlapping other items. The returned column may
3714 * cause aArea to overflow the current implicit grid bounds if placed there.
3715 */
3716 uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
3717 const GridArea* aArea) const;
3718
3719 /**
3720 * Place aArea in the first column (in row aArea->mRows.mStart) starting at
3721 * aStartCol without overlapping other items. The resulting aArea may
3722 * overflow the current implicit grid bounds.
3723 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3724 * Pre-condition: aArea->mRows.IsDefinite() is true.
3725 * Post-condition: aArea->IsDefinite() is true.
3726 */
3727 void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea,
3728 uint32_t aClampMaxColLine) const;
3729
3730 /**
3731 * Find the first row in column aLockedCol starting at aStartRow where aArea
3732 * could be placed without overlapping other items. The returned row may
3733 * cause aArea to overflow the current implicit grid bounds if placed there.
3734 */
3735 uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
3736 const GridArea* aArea) const;
3737
3738 /**
3739 * Place aArea in the first row (in column aArea->mCols.mStart) starting at
3740 * aStartRow without overlapping other items. The resulting aArea may
3741 * overflow the current implicit grid bounds.
3742 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3743 * Pre-condition: aArea->mCols.IsDefinite() is true.
3744 * Post-condition: aArea->IsDefinite() is true.
3745 */
3746 void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea,
3747 uint32_t aClampMaxRowLine) const;
3748
3749 /**
3750 * Place aArea in the first column starting at aStartCol,aStartRow without
3751 * causing it to overlap other items or overflow mGridColEnd.
3752 * If there's no such column in aStartRow, continue in position 1,aStartRow+1.
3753 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3754 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3755 * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
3756 * Post-condition: aArea->IsDefinite() is true.
3757 */
3758 void PlaceAutoAutoInRowOrder(uint32_t aStartCol, uint32_t aStartRow,
3759 GridArea* aArea, uint32_t aClampMaxColLine,
3760 uint32_t aClampMaxRowLine) const;
3761
3762 /**
3763 * Place aArea in the first row starting at aStartCol,aStartRow without
3764 * causing it to overlap other items or overflow mGridRowEnd.
3765 * If there's no such row in aStartCol, continue in position aStartCol+1,1.
3766 * @param aClampMaxColLine the maximum allowed column line number (zero-based)
3767 * @param aClampMaxRowLine the maximum allowed row line number (zero-based)
3768 * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
3769 * Post-condition: aArea->IsDefinite() is true.
3770 */
3771 void PlaceAutoAutoInColOrder(uint32_t aStartCol, uint32_t aStartRow,
3772 GridArea* aArea, uint32_t aClampMaxColLine,
3773 uint32_t aClampMaxRowLine) const;
3774
3775 /**
3776 * Return aLine if it's inside the aMin..aMax range (inclusive),
3777 * otherwise return kAutoLine.
3778 */
3779 static int32_t AutoIfOutside(int32_t aLine, int32_t aMin, int32_t aMax) {
3780 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", 3780)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMin <= aMax" ")"
); do { MOZ_CrashSequence(__null, 3780); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3781 if (aLine < aMin || aLine > aMax) {
3782 return kAutoLine;
3783 }
3784 return aLine;
3785 }
3786
3787 /**
3788 * Inflate the implicit grid to include aArea.
3789 * @param aArea may be definite or auto
3790 */
3791 void InflateGridFor(const GridArea& aArea) {
3792 mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
3793 mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
3794 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", 3795)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 3795); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3795 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", 3795)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGridColEnd <= kTranslatedMaxLine && mGridRowEnd <= kTranslatedMaxLine"
")"); do { MOZ_CrashSequence(__null, 3795); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3796 }
3797
3798 /**
3799 * Calculates the empty tracks in a repeat(auto-fit).
3800 * @param aOutNumEmptyLines Outputs the number of tracks which are empty.
3801 * @param aSizingFunctions Sizing functions for the relevant axis.
3802 * @param aNumGridLines Number of grid lines for the relevant axis.
3803 * @param aIsEmptyFunc Functor to check if a cell is empty. This should be
3804 * mCellMap.IsColEmpty or mCellMap.IsRowEmpty, depending on the axis.
3805 */
3806 template <typename IsEmptyFuncT>
3807 static Maybe<nsTArray<uint32_t>> CalculateAdjustForAutoFitElements(
3808 uint32_t* aOutNumEmptyTracks, TrackSizingFunctions& aSizingFunctions,
3809 uint32_t aNumGridLines, IsEmptyFuncT aIsEmptyFunc);
3810
3811 /**
3812 * Return a line number for (non-auto) aLine, per:
3813 * https://drafts.csswg.org/css-grid-2/#line-placement
3814 * @param aLine style data for the line (must be non-auto)
3815 * @param aNth a number of lines to find from aFromIndex, negative if the
3816 * search should be in reverse order. In the case aLine has
3817 * a specified line name, it's permitted to pass in zero which
3818 * will be treated as one.
3819 * @param aFromIndex the zero-based index to start counting from
3820 * @param aLineNameList the explicit named lines
3821 * @param aSide the axis+edge we're resolving names for (e.g. if we're
3822 resolving a grid-row-start line, pass LogicalSide::BStart)
3823 * @param aExplicitGridEnd the last line in the explicit grid
3824 * @param aStyle the StylePosition() for the grid container
3825 * @return a definite line (1-based), clamped to
3826 * the mClampMinLine..mClampMaxLine range
3827 */
3828 int32_t ResolveLine(const StyleGridLine& aLine, int32_t aNth,
3829 uint32_t aFromIndex, const LineNameMap& aNameMap,
3830 LogicalSide aSide, uint32_t aExplicitGridEnd,
3831 const nsStylePosition* aStyle);
3832
3833 /**
3834 * Helper method for ResolveLineRange.
3835 * @see ResolveLineRange
3836 * @return a pair (start,end) of lines
3837 */
3838 typedef std::pair<int32_t, int32_t> LinePair;
3839 LinePair ResolveLineRangeHelper(const StyleGridLine& aStart,
3840 const StyleGridLine& aEnd,
3841 const LineNameMap& aNameMap,
3842 LogicalAxis aAxis, uint32_t aExplicitGridEnd,
3843 const nsStylePosition* aStyle);
3844
3845 /**
3846 * Return a LineRange based on the given style data. Non-auto lines
3847 * are resolved to a definite line number (1-based) per:
3848 * https://drafts.csswg.org/css-grid-2/#line-placement
3849 * with placement errors corrected per:
3850 * https://drafts.csswg.org/css-grid-2/#grid-placement-errors
3851 * @param aStyle the StylePosition() for the grid container
3852 * @param aStart style data for the start line
3853 * @param aEnd style data for the end line
3854 * @param aLineNameList the explicit named lines
3855 * @param aAxis the axis we're resolving names in
3856 * @param aExplicitGridEnd the last line in the explicit grid
3857 * @param aStyle the StylePosition() for the grid container
3858 */
3859 LineRange ResolveLineRange(const StyleGridLine& aStart,
3860 const StyleGridLine& aEnd,
3861 const LineNameMap& aNameMap, LogicalAxis aAxis,
3862 uint32_t aExplicitGridEnd,
3863 const nsStylePosition* aStyle);
3864
3865 /**
3866 * Return a GridArea with non-auto lines placed at a definite line (1-based)
3867 * with placement errors resolved. One or both positions may still
3868 * be 'auto'.
3869 * @param aChild the grid item
3870 * @param aStyle the StylePosition() for the grid container
3871 */
3872 GridArea PlaceDefinite(nsIFrame* aChild, const LineNameMap& aColLineNameMap,
3873 const LineNameMap& aRowLineNameMap,
3874 const nsStylePosition* aStyle);
3875
3876 bool HasImplicitNamedArea(nsAtom* aName) const {
3877 return mAreas && mAreas->has(aName);
3878 }
3879
3880 // Return true if aString ends in aSuffix and has at least one character
3881 // before the suffix. Assign aIndex to where the suffix starts.
3882 static bool IsNameWithSuffix(nsAtom* aString, const nsString& aSuffix,
3883 uint32_t* aIndex) {
3884 if (StringEndsWith(nsDependentAtomString(aString), aSuffix)) {
3885 *aIndex = aString->GetLength() - aSuffix.Length();
3886 return *aIndex != 0;
3887 }
3888 return false;
3889 }
3890
3891 static bool IsNameWithEndSuffix(nsAtom* aString, uint32_t* aIndex) {
3892 return IsNameWithSuffix(aString, u"-end"_ns, aIndex);
3893 }
3894
3895 static bool IsNameWithStartSuffix(nsAtom* aString, uint32_t* aIndex) {
3896 return IsNameWithSuffix(aString, u"-start"_ns, aIndex);
3897 }
3898
3899 // Return the relevant parent LineNameMap for the given subgrid axis aAxis.
3900 const LineNameMap* ParentLineMapForAxis(bool aIsOrthogonal,
3901 LogicalAxis aAxis) const {
3902 if (!mParentGrid) {
3903 return nullptr;
3904 }
3905 bool isRows = aIsOrthogonal == (aAxis == LogicalAxis::Inline);
3906 return isRows ? mParentGrid->mRowNameMap : mParentGrid->mColNameMap;
3907 }
3908
3909 void SetLineMaps(const LineNameMap* aColNameMap,
3910 const LineNameMap* aRowNameMap) {
3911 mColNameMap = aColNameMap;
3912 mRowNameMap = aRowNameMap;
3913 }
3914
3915 /**
3916 * A CellMap holds state for each cell in the grid.
3917 * It's row major. It's sparse in the sense that it only has enough rows to
3918 * cover the last row that has a grid item. Each row only has enough entries
3919 * to cover columns that are occupied *on that row*, i.e. it's not a full
3920 * matrix covering the entire implicit grid. An absent Cell means that it's
3921 * unoccupied by any grid item.
3922 */
3923 struct CellMap {
3924 struct Cell {
3925 constexpr Cell() : mIsOccupied(false) {}
3926 bool mIsOccupied : 1;
3927 };
3928
3929 void Fill(const GridArea& aGridArea) {
3930 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", 3930)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 3930); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3931 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", 3931)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.mRows.mStart < aGridArea.mRows.mEnd"
")"); do { MOZ_CrashSequence(__null, 3931); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3932 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", 3932)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridArea.mCols.mStart < aGridArea.mCols.mEnd"
")"); do { MOZ_CrashSequence(__null, 3932); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3933 const auto numRows = aGridArea.mRows.mEnd;
3934 const auto numCols = aGridArea.mCols.mEnd;
3935 mCells.EnsureLengthAtLeast(numRows);
3936 for (auto i = aGridArea.mRows.mStart; i < numRows; ++i) {
3937 nsTArray<Cell>& cellsInRow = mCells[i];
3938 cellsInRow.EnsureLengthAtLeast(numCols);
3939 for (auto j = aGridArea.mCols.mStart; j < numCols; ++j) {
3940 cellsInRow[j].mIsOccupied = true;
3941 }
3942 }
3943 }
3944
3945 uint32_t IsEmptyCol(uint32_t aCol) const {
3946 for (auto& row : mCells) {
3947 if (aCol < row.Length() && row[aCol].mIsOccupied) {
3948 return false;
3949 }
3950 }
3951 return true;
3952 }
3953 uint32_t IsEmptyRow(uint32_t aRow) const {
3954 if (aRow >= mCells.Length()) {
3955 return true;
3956 }
3957 for (const Cell& cell : mCells[aRow]) {
3958 if (cell.mIsOccupied) {
3959 return false;
3960 }
3961 }
3962 return true;
3963 }
3964#ifdef DEBUG1
3965 void Dump() const {
3966 const size_t numRows = mCells.Length();
3967 for (size_t i = 0; i < numRows; ++i) {
3968 const nsTArray<Cell>& cellsInRow = mCells[i];
3969 const size_t numCols = cellsInRow.Length();
3970 printf("%lu:\t", (unsigned long)i + 1);
3971 for (size_t j = 0; j < numCols; ++j) {
3972 printf(cellsInRow[j].mIsOccupied ? "X " : ". ");
3973 }
3974 printf("\n");
3975 }
3976 }
3977#endif
3978
3979 nsTArray<nsTArray<Cell>> mCells;
3980 };
3981
3982 /**
3983 * State for each cell in the grid.
3984 */
3985 CellMap mCellMap;
3986 /**
3987 * @see HasImplicitNamedArea.
3988 */
3989 ImplicitNamedAreas* mAreas;
3990 /**
3991 * The last column grid line (1-based) in the explicit grid.
3992 * (i.e. the number of explicit columns + 1)
3993 */
3994 uint32_t mExplicitGridColEnd;
3995 /**
3996 * The last row grid line (1-based) in the explicit grid.
3997 * (i.e. the number of explicit rows + 1)
3998 */
3999 uint32_t mExplicitGridRowEnd;
4000 // Same for the implicit grid, except these become zero-based after
4001 // resolving definite lines.
4002 uint32_t mGridColEnd;
4003 uint32_t mGridRowEnd;
4004
4005 /**
4006 * Offsets from the start of the implicit grid to the start of the translated
4007 * explicit grid. They are zero if there are no implicit lines before 1,1.
4008 * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the
4009 * corresponding GridArea::mCols will be 0 / 3 in the zero-based translated
4010 * grid.
4011 */
4012 uint32_t mExplicitGridOffsetCol;
4013 uint32_t mExplicitGridOffsetRow;
4014
4015 /**
4016 * Our parent grid if any.
4017 */
4018 const Grid* mParentGrid;
4019
4020 /**
4021 * Our LineNameMaps.
4022 */
4023 const LineNameMap* mColNameMap;
4024 const LineNameMap* mRowNameMap;
4025};
4026
4027/**
4028 * Compute margin+border+padding for aGridItem.mFrame (a subgrid) and store it
4029 * on its Subgrid property (and return that property).
4030 * aPercentageBasis is in the grid item's writing-mode.
4031 */
4032static Subgrid* SubgridComputeMarginBorderPadding(
4033 const GridItemInfo& aGridItem, const LogicalSize& aPercentageBasis) {
4034 auto* subgridFrame = aGridItem.SubgridFrame();
4035 auto cbWM = aGridItem.mFrame->GetParent()->GetWritingMode();
4036 auto* subgrid = subgridFrame->GetProperty(Subgrid::Prop());
4037 auto wm = subgridFrame->GetWritingMode();
4038 auto pmPercentageBasis = cbWM.IsOrthogonalTo(wm) ? aPercentageBasis.BSize(wm)
4039 : aPercentageBasis.ISize(wm);
4040 SizeComputationInput sz(subgridFrame, nullptr, cbWM, pmPercentageBasis);
4041 subgrid->mMarginBorderPadding =
4042 sz.ComputedLogicalMargin(cbWM) + sz.ComputedLogicalBorderPadding(cbWM);
4043 if (aGridItem.mFrame == subgridFrame) {
4044 return subgrid;
4045 }
4046
4047 if (ScrollContainerFrame* scrollContainerFrame =
4048 aGridItem.mFrame->GetScrollTargetFrame()) {
4049 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"
, 4052); 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, 4052); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4050 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"
, 4052); 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, 4052); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4051 "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"
, 4052); 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, 4052); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
4052 "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"
, 4052); 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, 4052); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
4053 // Add the margin and border from the scroller frame.
4054 SizeComputationInput szOuterFrame(scrollContainerFrame, nullptr, cbWM,
4055 pmPercentageBasis);
4056 subgrid->mMarginBorderPadding +=
4057 szOuterFrame.ComputedLogicalMargin(cbWM) +
4058 szOuterFrame.ComputedLogicalBorderPadding(cbWM) +
4059 LogicalMargin(cbWM,
4060 scrollContainerFrame->IntrinsicScrollbarGutterSize());
4061 }
4062
4063 if (nsFieldSetFrame* f = do_QueryFrame(aGridItem.mFrame)) {
4064 const auto* inner = f->GetInner();
4065 auto wm = inner->GetWritingMode();
4066 LogicalPoint pos = inner->GetLogicalPosition(aGridItem.mFrame->GetSize());
4067 // The legend is always on the BStart side and it inflates the fieldset's
4068 // "border area" size. The inner frame's b-start pos equals that size.
4069 LogicalMargin offsets(wm, pos.B(wm), 0, 0, 0);
4070 subgrid->mMarginBorderPadding += offsets.ConvertTo(cbWM, wm);
4071 }
4072
4073 return subgrid;
4074}
4075
4076static void CopyUsedTrackSizes(TrackPlan& aResult,
4077 const nsGridContainerFrame* aUsedTrackSizesFrame,
4078 const UsedTrackSizes* aUsedTrackSizes,
4079 const nsGridContainerFrame* aSubgridFrame,
4080 const Subgrid* aSubgrid,
4081 LogicalAxis aSubgridAxis) {
4082 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", 4083)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
")"); do { MOZ_CrashSequence(__null, 4083); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4083 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", 4083)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubgridFrame->ParentGridContainerForSubgrid() == aUsedTrackSizesFrame"
")"); do { MOZ_CrashSequence(__null, 4083); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4084 aResult.SetLength(aSubgridAxis == LogicalAxis::Inline
4085 ? aSubgrid->mGridColEnd
4086 : aSubgrid->mGridRowEnd);
4087 auto parentAxis =
4088 aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aSubgridAxis) : aSubgridAxis;
4089 const auto& parentSizes = aUsedTrackSizes->mTrackPlans[parentAxis];
4090 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"
, 4090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUsedTrackSizes->mCanResolveLineRangeSize[parentAxis]"
")"); do { MOZ_CrashSequence(__null, 4090); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4091 if (parentSizes.IsEmpty()) {
4092 return;
4093 }
4094 const auto& range = aSubgrid->mArea.LineRangeForAxis(parentAxis);
4095 const auto cbwm = aUsedTrackSizesFrame->GetWritingMode();
4096 const auto wm = aSubgridFrame->GetWritingMode();
4097 // Recompute the MBP to resolve percentages against the resolved track sizes.
4098 if (parentAxis == LogicalAxis::Inline) {
4099 // Find the subgrid's grid item frame in its parent grid container. This
4100 // is usually the same as aSubgridFrame but it may also have a ScrollFrame,
4101 // FieldSetFrame etc. We just loop until we see the first ancestor
4102 // GridContainerFrame and pick the last frame we saw before that.
4103 // Note that all subgrids are inside a parent (sub)grid container.
4104 const nsIFrame* outerGridItemFrame = aSubgridFrame;
4105 for (nsIFrame* parent = aSubgridFrame->GetParent();
4106 parent != aUsedTrackSizesFrame; parent = parent->GetParent()) {
4107 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"
, 4107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 4107); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4108 outerGridItemFrame = parent;
4109 }
4110 auto sizeInAxis = range.ToLength(aUsedTrackSizes->mTrackPlans[parentAxis]);
4111 LogicalSize pmPercentageBasis =
4112 aSubgrid->mIsOrthogonal ? LogicalSize(wm, nscoord(0), sizeInAxis)
4113 : LogicalSize(wm, sizeInAxis, nscoord(0));
4114 GridItemInfo info(const_cast<nsIFrame*>(outerGridItemFrame),
4115 aSubgrid->mArea);
4116 SubgridComputeMarginBorderPadding(info, pmPercentageBasis);
4117 }
4118 const LogicalMargin& mbp = aSubgrid->mMarginBorderPadding;
4119 nscoord startMBP;
4120 nscoord endMBP;
4121 if (MOZ_LIKELY(cbwm.ParallelAxisStartsOnSameSide(parentAxis, wm))(__builtin_expect(!!(cbwm.ParallelAxisStartsOnSameSide(parentAxis
, wm)), 1))
) {
4122 startMBP = mbp.Start(parentAxis, cbwm);
4123 endMBP = mbp.End(parentAxis, cbwm);
4124 uint32_t i = range.mStart;
4125 nscoord startPos = parentSizes[i].mPosition + startMBP;
4126 for (auto& sz : aResult) {
4127 sz = parentSizes[i++];
4128 sz.mPosition -= startPos;
4129 }
4130 } else {
4131 startMBP = mbp.End(parentAxis, cbwm);
4132 endMBP = mbp.Start(parentAxis, cbwm);
4133 uint32_t i = range.mEnd - 1;
4134 const auto& parentEnd = parentSizes[i];
4135 nscoord parentEndPos = parentEnd.mPosition + parentEnd.mBase - startMBP;
4136 for (auto& sz : aResult) {
4137 sz = parentSizes[i--];
4138 sz.mPosition = parentEndPos - (sz.mPosition + sz.mBase);
4139 }
4140 }
4141 auto& startTrack = aResult[0];
4142 startTrack.mPosition = 0;
4143 startTrack.mBase -= startMBP;
4144 if (MOZ_UNLIKELY(startTrack.mBase < nscoord(0))(__builtin_expect(!!(startTrack.mBase < nscoord(0)), 0))) {
4145 // Our MBP doesn't fit in the start track. Adjust the track position
4146 // to maintain track alignment with our parent.
4147 startTrack.mPosition = startTrack.mBase;
4148 startTrack.mBase = nscoord(0);
4149 }
4150 auto& endTrack = aResult.LastElement();
4151 endTrack.mBase -= endMBP;
4152 if (MOZ_UNLIKELY(endTrack.mBase < nscoord(0))(__builtin_expect(!!(endTrack.mBase < nscoord(0)), 0))) {
4153 endTrack.mBase = nscoord(0);
4154 }
4155}
4156
4157void nsGridContainerFrame::UsedTrackSizes::ResolveTrackSizesForAxis(
4158 nsGridContainerFrame* aFrame, LogicalAxis aAxis, gfxContext& aRC) {
4159 if (mCanResolveLineRangeSize[aAxis]) {
4160 return;
4161 }
4162 if (!aFrame->IsSubgrid()) {
4163 // We can't resolve sizes in this axis at this point. aFrame is the top grid
4164 // container, which will store its final track sizes later once they're
4165 // resolved in this axis (in GridReflowInput::CalculateTrackSizesForAxis).
4166 // The single caller of this method only needs track sizes for
4167 // calculating a CB size and it will treat it as indefinite when
4168 // this happens.
4169 return;
4170 }
4171 auto* parent = aFrame->ParentGridContainerForSubgrid();
4172 auto* parentSizes =
4173 parent->GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
4174 auto* subgrid = aFrame->GetProperty(Subgrid::Prop());
4175 const auto parentAxis =
4176 subgrid->mIsOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
4177 parentSizes->ResolveTrackSizesForAxis(parent, parentAxis, aRC);
4178 if (!parentSizes->mCanResolveLineRangeSize[parentAxis]) {
4179 if (aFrame->IsSubgrid(aAxis)) {
4180 ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC,
4181 NS_UNCONSTRAINEDSIZE);
4182 }
4183 return;
4184 }
4185 if (aFrame->IsSubgrid(aAxis)) {
4186 CopyUsedTrackSizes(mTrackPlans[aAxis], parent, parentSizes, aFrame, subgrid,
4187 aAxis);
4188 mCanResolveLineRangeSize[aAxis] = true;
4189 } else {
4190 const auto& range = subgrid->mArea.LineRangeForAxis(parentAxis);
4191 nscoord contentBoxSize =
4192 range.ToLength(parentSizes->mTrackPlans[parentAxis]);
4193 auto parentWM = aFrame->GetParent()->GetWritingMode();
4194 contentBoxSize -=
4195 subgrid->mMarginBorderPadding.StartEnd(parentAxis, parentWM);
4196 contentBoxSize = std::max(nscoord(0), contentBoxSize);
4197 ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC,
4198 contentBoxSize);
4199 }
4200}
4201
4202void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
4203 nsGridContainerFrame* aFrame, LogicalAxis aAxis, Subgrid* aSubgrid,
4204 gfxContext& aRC, nscoord aContentBoxSize) {
4205 GridReflowInput gridRI(aFrame, aRC);
4206 gridRI.mGridItems = aSubgrid->mGridItems.Clone();
4207 Grid grid;
4208 grid.mGridColEnd = aSubgrid->mGridColEnd;
4209 grid.mGridRowEnd = aSubgrid->mGridRowEnd;
4210 gridRI.CalculateTrackSizesForAxis(aAxis, grid, aContentBoxSize,
4211 SizingConstraint::NoConstraint);
4212 const auto& tracks = gridRI.TracksFor(aAxis);
4213 mTrackPlans[aAxis].Assign(tracks.mSizes);
4214 mCanResolveLineRangeSize[aAxis] = tracks.mCanResolveLineRangeSize;
4215 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"
, 4215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCanResolveLineRangeSize[aAxis]"
")"); do { MOZ_CrashSequence(__null, 4215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4216}
4217
4218void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
4219 LogicalAxis aAxis, const Grid& aGrid, nscoord aContentBoxSize,
4220 SizingConstraint aConstraint) {
4221 auto& tracks = TracksFor(aAxis);
4222 const auto& sizingFunctions =
4223 aAxis == LogicalAxis::Inline ? mColFunctions : mRowFunctions;
4224 const auto& gapStyle = aAxis == LogicalAxis::Inline ? mGridStyle->mColumnGap
4225 : mGridStyle->mRowGap;
4226 if (tracks.mIsMasonry) {
4227 // See comment on nsGridContainerFrame::MasonryLayout().
4228 tracks.Initialize(sizingFunctions, gapStyle, 2, aContentBoxSize);
4229 tracks.mCanResolveLineRangeSize = true;
4230 return;
4231 }
4232 uint32_t gridEnd =
4233 aAxis == LogicalAxis::Inline ? aGrid.mGridColEnd : aGrid.mGridRowEnd;
4234 Maybe<TrackSizingFunctions> fallbackTrackSizing;
4235
4236 bool useParentGaps = false;
4237 const bool isSubgriddedAxis = mFrame->IsSubgrid(aAxis);
4238 if (MOZ_LIKELY(!isSubgriddedAxis)(__builtin_expect(!!(!isSubgriddedAxis), 1))) {
4239 tracks.Initialize(sizingFunctions, gapStyle, gridEnd, aContentBoxSize);
4240 } else {
4241 tracks.mGridGap =
4242 nsLayoutUtils::ResolveGapToLength(gapStyle, aContentBoxSize);
4243 tracks.mContentBoxSize = aContentBoxSize;
4244 const auto* subgrid = mFrame->GetProperty(Subgrid::Prop());
4245 tracks.mSizes.SetLength(gridEnd);
4246 auto* parent = mFrame->ParentGridContainerForSubgrid();
4247 auto parentAxis = subgrid->mIsOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
4248 const auto* parentSizes = parent->GetUsedTrackSizes();
4249 if (parentSizes && parentSizes->mCanResolveLineRangeSize[parentAxis]) {
4250 CopyUsedTrackSizes(tracks.mSizes, parent, parentSizes, mFrame, subgrid,
4251 aAxis);
4252 useParentGaps = gapStyle.IsNormal();
4253 } else {
4254 fallbackTrackSizing.emplace(TrackSizingFunctions::ForSubgridFallback(
4255 mFrame, subgrid, parent, parentAxis));
4256 tracks.Initialize(*fallbackTrackSizing, gapStyle, gridEnd,
4257 aContentBoxSize);
4258 }
4259 }
4260
4261 // We run the Track Sizing Algorithm in non-subgridded axes, and in some
4262 // cases in a subgridded axis when our parent track sizes aren't resolved yet.
4263 if (MOZ_LIKELY(!isSubgriddedAxis)(__builtin_expect(!!(!isSubgriddedAxis), 1)) || fallbackTrackSizing.isSome()) {
4264 const size_t origGridItemCount = mGridItems.Length();
4265 const bool hasSubgridItems = mFrame->HasSubgridItems(aAxis);
4266 if (hasSubgridItems) {
4267 AutoTArray<GridItemInfo, 8> collectedItems;
4268 CollectSubgridItemsForAxis(aAxis, collectedItems);
4269 mGridItems.AppendElements(collectedItems);
4270 }
4271 tracks.CalculateSizes(
4272 *this, mGridItems,
4273 fallbackTrackSizing ? *fallbackTrackSizing : sizingFunctions,
4274 aContentBoxSize,
4275 aAxis == LogicalAxis::Inline ? &GridArea::mCols : &GridArea::mRows,
4276 aConstraint);
4277
4278 if (hasSubgridItems &&
4279 StaticPrefs::layout_css_grid_subgrid_baselines_enabled()) {
4280 // If any of the subgrid items are baseline-aligned, we've just recorded
4281 // their baseline-alignment offsets in our own copy of their GridItemInfo
4282 // structs. Before we get rid of those copies (via TruncateLength), we
4283 // have to copy these offsets back to the subgrids' versions of the
4284 // GridItemInfo structs.
4285 //
4286 // XXXdholbert This new behavior is behind a pref due to bug 1871719.
4287 CopyBaselineMetricsToSubgridItems(aAxis, origGridItemCount);
4288 }
4289 mGridItems.TruncateLength(origGridItemCount);
4290 }
4291 if (isSubgriddedAxis) {
4292 // XXXdholbert This is a bit hacky, but this is something that
4293 // tracks.CalculateSizes does internally (unconditionally, if there are
4294 // baseline-aligned items), and it seems like subgrids need to do it too,
4295 // or else they hit the "unexpected baseline subtree alignment"
4296 // fatal-assert when aligning their children with the baseline-alignment
4297 // information that they received from the outer grid.
4298 // (This might be entirely unnecessary? Aside from the default ::AUTO
4299 // value, it looks like the ::First entry is always set to ::START and
4300 // the ::Last entry is always set to ::END...)
4301 tracks.mBaselineSubtreeAlign[BaselineSharingGroup::First] =
4302 StyleAlignFlags::START;
4303 tracks.mBaselineSubtreeAlign[BaselineSharingGroup::Last] =
4304 StyleAlignFlags::END;
4305 }
4306
4307 if (aContentBoxSize != NS_UNCONSTRAINEDSIZE) {
4308 auto alignment = mGridStyle->UsedContentAlignment(tracks.mAxis);
4309 tracks.AlignJustifyContent(mGridStyle, alignment, mWM, aContentBoxSize,
4310 isSubgriddedAxis);
4311 } else if (!useParentGaps) {
4312 const nscoord gridGap = tracks.mGridGap;
4313 nscoord pos = 0;
4314 for (TrackSize& sz : tracks.mSizes) {
4315 sz.mPosition = pos;
4316 pos += sz.mBase + gridGap;
4317 }
4318 }
4319
4320 if (aConstraint == SizingConstraint::NoConstraint &&
4321 (mFrame->HasSubgridItems() || mFrame->IsSubgrid())) {
4322 mFrame->StoreUsedTrackSizes(aAxis, tracks.mSizes);
4323 }
4324
4325 // positions and sizes are now final
4326 tracks.mCanResolveLineRangeSize = true;
4327}
4328
4329void nsGridContainerFrame::GridReflowInput::InvalidateTrackSizesForAxis(
4330 LogicalAxis aAxis) {
4331 for (auto& item : mGridItems) {
4332 item.ResetTrackSizingBits(aAxis);
4333 }
4334 TracksFor(aAxis).mCanResolveLineRangeSize = false;
4335}
4336
4337// Align an item's margin box in its aAxis inside aCBSize.
4338static void AlignJustifySelf(StyleAlignFlags aAlignment, LogicalAxis aAxis,
4339 AlignJustifyFlags aFlags, nscoord aBaselineAdjust,
4340 nscoord aCBSize, const ReflowInput& aRI,
4341 const LogicalSize& aChildSize,
4342 LogicalPoint* aPos) {
4343 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"
, 4345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4345); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4344 "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"
, 4345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4345); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4345 "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"
, 4345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAlignment != StyleAlignFlags::AUTO"
") (" "unexpected 'auto' " "computed value for normal flow grid item"
")"); do { MOZ_CrashSequence(__null, 4345); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4346
4347 // NOTE: this is the resulting frame offset (border box).
4348 nscoord offset = CSSAlignUtils::AlignJustifySelf(
4349 aAlignment, aAxis, aFlags, aBaselineAdjust, aCBSize, aRI, aChildSize);
4350
4351 // Set the position (aPos) for the requested alignment.
4352 if (offset != 0) {
4353 WritingMode wm = aRI.GetWritingMode();
4354 nscoord& pos = aAxis == LogicalAxis::Block ? aPos->B(wm) : aPos->I(wm);
4355 pos += MOZ_LIKELY(aFlags.contains(AlignJustifyFlag::SameSide))(__builtin_expect(!!(aFlags.contains(AlignJustifyFlag::SameSide
)), 1))
? offset
4356 : -offset;
4357 }
4358}
4359
4360static void AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
4361 StyleAlignFlags aAlignSelf, nscoord aCBSize,
4362 const WritingMode aCBWM, const ReflowInput& aRI,
4363 const LogicalSize& aSize, AlignJustifyFlags aFlags,
4364 LogicalPoint* aPos) {
4365 AlignJustifyFlags flags = aFlags;
4366 if (aAlignSelf & StyleAlignFlags::SAFE) {
4367 flags += AlignJustifyFlag::OverflowSafe;
4368 }
4369 aAlignSelf &= ~StyleAlignFlags::FLAG_BITS;
4370
4371 WritingMode childWM = aRI.GetWritingMode();
4372 if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, childWM)) {
4373 flags += AlignJustifyFlag::SameSide;
4374 }
4375
4376 if (aGridItem.mState[LogicalAxis::Block] &
4377 GridItemInfo::eLastBaselineSharingGroup) {
4378 flags += AlignJustifyFlag::LastBaselineSharingGroup;
4379 }
4380
4381 // Grid's 'align-self' axis is never parallel to the container's inline axis.
4382 if (aAlignSelf == StyleAlignFlags::LEFT ||
4383 aAlignSelf == StyleAlignFlags::RIGHT) {
4384 aAlignSelf = StyleAlignFlags::START;
4385 }
4386 if (MOZ_LIKELY(aAlignSelf == StyleAlignFlags::NORMAL)(__builtin_expect(!!(aAlignSelf == StyleAlignFlags::NORMAL), 1
))
) {
4387 aAlignSelf = StyleAlignFlags::STRETCH;
4388 }
4389
4390 nscoord baselineAdjust = 0;
4391 if (aAlignSelf == StyleAlignFlags::BASELINE ||
4392 aAlignSelf == StyleAlignFlags::LAST_BASELINE) {
4393 aAlignSelf = aGridItem.GetSelfBaseline(aAlignSelf, LogicalAxis::Block,
4394 &baselineAdjust);
4395 }
4396
4397 const auto bAxisInChildWM = aCBWM.ConvertAxisTo(LogicalAxis::Block, childWM);
4398 AlignJustifySelf(aAlignSelf, bAxisInChildWM, flags, baselineAdjust, aCBSize,
4399 aRI, aSize, aPos);
4400}
4401
4402static void JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
4403 StyleAlignFlags aJustifySelf, nscoord aCBSize,
4404 const WritingMode aCBWM, const ReflowInput& aRI,
4405 const LogicalSize& aSize, AlignJustifyFlags aFlags,
4406 LogicalPoint* aPos) {
4407 AlignJustifyFlags flags = aFlags;
4408 if (aJustifySelf & StyleAlignFlags::SAFE) {
4409 flags += AlignJustifyFlag::OverflowSafe;
4410 }
4411 aJustifySelf &= ~StyleAlignFlags::FLAG_BITS;
4412
4413 WritingMode childWM = aRI.GetWritingMode();
4414 if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, childWM)) {
4415 flags += AlignJustifyFlag::SameSide;
4416 }
4417
4418 if (aGridItem.mState[LogicalAxis::Inline] &
4419 GridItemInfo::eLastBaselineSharingGroup) {
4420 flags += AlignJustifyFlag::LastBaselineSharingGroup;
4421 }
4422
4423 if (MOZ_LIKELY(aJustifySelf == StyleAlignFlags::NORMAL)(__builtin_expect(!!(aJustifySelf == StyleAlignFlags::NORMAL)
, 1))
) {
4424 aJustifySelf = StyleAlignFlags::STRETCH;
4425 }
4426
4427 nscoord baselineAdjust = 0;
4428 // Grid's 'justify-self' axis is always parallel to the container's inline
4429 // axis, so justify-self:left|right always applies.
4430 if (aJustifySelf == StyleAlignFlags::LEFT) {
4431 aJustifySelf =
4432 aCBWM.IsBidiLTR() ? StyleAlignFlags::START : StyleAlignFlags::END;
4433 } else if (aJustifySelf == StyleAlignFlags::RIGHT) {
4434 aJustifySelf =
4435 aCBWM.IsBidiLTR() ? StyleAlignFlags::END : StyleAlignFlags::START;
4436 } else if (aJustifySelf == StyleAlignFlags::BASELINE ||
4437 aJustifySelf == StyleAlignFlags::LAST_BASELINE) {
4438 aJustifySelf = aGridItem.GetSelfBaseline(aJustifySelf, LogicalAxis::Inline,
4439 &baselineAdjust);
4440 }
4441
4442 const auto iAxisInChildWM = aCBWM.ConvertAxisTo(LogicalAxis::Inline, childWM);
4443 AlignJustifySelf(aJustifySelf, iAxisInChildWM, flags, baselineAdjust, aCBSize,
4444 aRI, aSize, aPos);
4445}
4446
4447static StyleAlignFlags GetAlignJustifyValue(StyleAlignFlags aAlignment,
4448 const WritingMode aWM,
4449 const bool aIsAlign,
4450 bool* aOverflowSafe) {
4451 *aOverflowSafe = bool(aAlignment & StyleAlignFlags::SAFE);
4452 aAlignment &= ~StyleAlignFlags::FLAG_BITS;
4453
4454 // Map some alignment values to 'start' / 'end'.
4455 if (aAlignment == StyleAlignFlags::LEFT ||
4456 aAlignment == StyleAlignFlags::RIGHT) {
4457 if (aIsAlign) {
4458 // Grid's 'align-content' axis is never parallel to the inline axis.
4459 return StyleAlignFlags::START;
4460 }
4461 bool isStart = aWM.IsBidiLTR() == (aAlignment == StyleAlignFlags::LEFT);
4462 return isStart ? StyleAlignFlags::START : StyleAlignFlags::END;
4463 }
4464 if (aAlignment == StyleAlignFlags::FLEX_START) {
4465 return StyleAlignFlags::START; // same as 'start' for Grid
4466 }
4467 if (aAlignment == StyleAlignFlags::FLEX_END) {
4468 return StyleAlignFlags::END; // same as 'end' for Grid
4469 }
4470 return aAlignment;
4471}
4472
4473static Maybe<StyleAlignFlags> GetAlignJustifyDistributionFallback(
4474 const StyleContentDistribution& aDistribution, bool* aOverflowSafe) {
4475 // See "4.3. Distributed Alignment" for the default fallback alignment values:
4476 // https://drafts.csswg.org/css-align-3/#distribution-values
4477 //
4478 // TODO: Extend this function to handle explicitly specified fallback
4479 // alignment once the CSS Alignment Module introduces that syntax:
4480 // https://github.com/w3c/csswg-drafts/issues/1002.
4481 if (aDistribution.primary == StyleAlignFlags::SPACE_BETWEEN) {
4482 *aOverflowSafe = true;
4483 return Some(StyleAlignFlags::START);
4484 }
4485 if (aDistribution.primary == StyleAlignFlags::SPACE_AROUND ||
4486 aDistribution.primary == StyleAlignFlags::SPACE_EVENLY) {
4487 *aOverflowSafe = true;
4488 return Some(StyleAlignFlags::CENTER);
4489 }
4490 if (aDistribution.primary == StyleAlignFlags::STRETCH) {
4491 *aOverflowSafe = false;
4492 return Some(StyleAlignFlags::START);
4493 }
4494 return Nothing();
4495}
4496
4497//----------------------------------------------------------------------
4498
4499// Frame class boilerplate
4500// =======================
4501
4502NS_QUERYFRAME_HEAD(nsGridContainerFrame)void* nsGridContainerFrame ::QueryFrame(FrameIID id) const { switch
(id) {
4503 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)); }
4504NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)default: break; } return nsContainerFrame ::QueryFrame(id); }
4505
4506NS_IMPL_FRAMEARENA_HELPERS(nsGridContainerFrame)void* nsGridContainerFrame ::operator new(size_t sz, mozilla::
PresShell * aShell) { return aShell->AllocateFrame(nsQueryFrame
::nsGridContainerFrame_id, sz); }
4507
4508nsContainerFrame* NS_NewGridContainerFrame(PresShell* aPresShell,
4509 ComputedStyle* aStyle) {
4510 return new (aPresShell)
4511 nsGridContainerFrame(aStyle, aPresShell->GetPresContext());
4512}
4513
4514//----------------------------------------------------------------------
4515
4516// nsGridContainerFrame Method Implementations
4517// ===========================================
4518
4519/*static*/ const nsRect& nsGridContainerFrame::GridItemCB(nsIFrame* aChild) {
4520 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"
, 4520); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsAbsolutelyPositioned()"
")"); do { MOZ_CrashSequence(__null, 4520); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4521 nsRect* cb = aChild->GetProperty(GridItemContainingBlockRect());
4522 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", 4524
); 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, 4524); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4523 "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", 4524
); 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, 4524); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4524 "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", 4524
); 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, 4524); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4525 return *cb;
4526}
4527
4528void nsGridContainerFrame::AddImplicitNamedAreasInternal(
4529 LineNameList& aNameList,
4530 nsGridContainerFrame::ImplicitNamedAreas*& aAreas) {
4531 for (const auto& nameIdent : aNameList.AsSpan()) {
4532 nsAtom* name = nameIdent.AsAtom();
4533 uint32_t indexOfSuffix;
4534 if (Grid::IsNameWithStartSuffix(name, &indexOfSuffix) ||
4535 Grid::IsNameWithEndSuffix(name, &indexOfSuffix)) {
4536 // Extract the name that was found earlier.
4537 nsDependentSubstring areaName(nsDependentAtomString(name), 0,
4538 indexOfSuffix);
4539
4540 // Lazily create the ImplicitNamedAreas.
4541 if (!aAreas) {
4542 aAreas = new nsGridContainerFrame::ImplicitNamedAreas;
4543 SetProperty(nsGridContainerFrame::ImplicitNamedAreasProperty(), aAreas);
4544 }
4545
4546 RefPtr<nsAtom> name = NS_Atomize(areaName);
4547 auto addPtr = aAreas->lookupForAdd(name);
4548 if (!addPtr) {
4549 if (!aAreas->add(addPtr, name,
4550 nsGridContainerFrame::NamedArea{
4551 StyleAtom(do_AddRef(name)), {0, 0}, {0, 0}})) {
4552 MOZ_CRASH("OOM while adding grid name lists")do { do { } while (false); MOZ_ReportCrash("" "OOM while adding grid name lists"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 4552)
; AnnotateMozCrashReason("MOZ_CRASH(" "OOM while adding grid name lists"
")"); do { MOZ_CrashSequence(__null, 4552); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4553 }
4554 }
4555 }
4556 }
4557}
4558
4559void nsGridContainerFrame::AddImplicitNamedAreas(
4560 Span<LineNameList> aLineNameLists) {
4561 // https://drafts.csswg.org/css-grid-2/#implicit-named-areas
4562 // Note: recording these names for fast lookup later is just an optimization.
4563 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4564 const uint32_t len = std::min(aLineNameLists.Length(), size_t(kMaxLine));
4565 for (uint32_t i = 0; i < len; ++i) {
4566 AddImplicitNamedAreasInternal(aLineNameLists[i], areas);
4567 }
4568}
4569
4570void nsGridContainerFrame::AddImplicitNamedAreas(
4571 Span<StyleLineNameListValue> aLineNameList) {
4572 // https://drafts.csswg.org/css-grid-2/#implicit-named-areas
4573 // Note: recording these names for fast lookup later is just an optimization.
4574 uint32_t count = 0;
4575 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4576 for (const auto& nameList : aLineNameList) {
4577 if (nameList.IsRepeat()) {
4578 for (const auto& repeatNameList :
4579 nameList.AsRepeat().line_names.AsSpan()) {
4580 AddImplicitNamedAreasInternal(repeatNameList, areas);
4581 ++count;
4582 }
4583 } else {
4584 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", 4584)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "nameList.IsLineNames()"
")"); do { MOZ_CrashSequence(__null, 4584); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4585 AddImplicitNamedAreasInternal(nameList.AsLineNames(), areas);
4586 ++count;
4587 }
4588
4589 if (count >= size_t(kMaxLine)) {
4590 break;
4591 }
4592 }
4593}
4594
4595void nsGridContainerFrame::InitImplicitNamedAreas(
4596 const nsStylePosition* aStyle) {
4597 ImplicitNamedAreas* areas = GetImplicitNamedAreas();
4598 if (areas) {
4599 // Clear it, but reuse the hashtable itself for now. We'll remove it
4600 // below if it isn't needed anymore.
4601 areas->clear();
4602 }
4603 auto Add = [&](const GridTemplate& aTemplate, bool aIsSubgrid) {
4604 AddImplicitNamedAreas(aTemplate.LineNameLists(aIsSubgrid));
4605 for (auto& value : aTemplate.TrackListValues()) {
4606 if (value.IsTrackRepeat()) {
4607 AddImplicitNamedAreas(value.AsTrackRepeat().line_names.AsSpan());
4608 }
4609 }
4610
4611 if (aIsSubgrid && aTemplate.IsSubgrid()) {
4612 // For subgrid, |aTemplate.LineNameLists(aIsSubgrid)| returns an empty
4613 // list so we have to manually add each item.
4614 AddImplicitNamedAreas(aTemplate.AsSubgrid()->line_names.AsSpan());
4615 }
4616 };
4617 Add(aStyle->mGridTemplateColumns, IsColSubgrid());
4618 Add(aStyle->mGridTemplateRows, IsRowSubgrid());
4619 if (areas && areas->count() == 0) {
4620 RemoveProperty(ImplicitNamedAreasProperty());
4621 }
4622}
4623
4624int32_t nsGridContainerFrame::Grid::ResolveLine(
4625 const StyleGridLine& aLine, int32_t aNth, uint32_t aFromIndex,
4626 const LineNameMap& aNameMap, LogicalSide aSide, uint32_t aExplicitGridEnd,
4627 const nsStylePosition* aStyle) {
4628 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", 4628)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aLine.IsAuto()" ")"
); do { MOZ_CrashSequence(__null, 4628); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4629 aNth = std::clamp(aNth, kMinLine, kMaxLine);
4630 int32_t line = 0;
4631 if (aLine.LineName()->IsEmpty()) {
4632 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", 4632
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth != 0" ") (" "css-grid 9.2: <integer> must not be zero."
")"); do { MOZ_CrashSequence(__null, 4632); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4633 line = int32_t(aFromIndex) + aNth;
4634 } else {
4635 if (aNth == 0) {
4636 // <integer> was omitted; treat it as 1.
4637 aNth = 1;
4638 }
4639 bool isNameOnly = !aLine.is_span && aLine.line_num == 0;
4640 if (isNameOnly) {
4641 AutoTArray<uint32_t, 16> implicitLines;
4642 aNameMap.FindNamedAreas(aLine.ident.AsAtom(), aSide, implicitLines);
4643 if (!implicitLines.IsEmpty() ||
4644 aNameMap.HasImplicitNamedArea(aLine.LineName())) {
4645 // aName is a named area - look for explicit lines named
4646 // <name>-start/-end depending on which side we're resolving.
4647 // https://drafts.csswg.org/css-grid-2/#grid-placement-slot
4648 nsAutoString lineName(nsDependentAtomString(aLine.LineName()));
4649 if (IsStart(aSide)) {
4650 lineName.AppendLiteral("-start");
4651 } else {
4652 lineName.AppendLiteral("-end");
4653 }
4654 RefPtr<nsAtom> name = NS_Atomize(lineName);
4655 line = aNameMap.FindNamedLine(name, &aNth, aFromIndex, implicitLines);
4656 }
4657 }
4658
4659 if (line == 0) {
4660 // If LineName() ends in -start/-end, try the prefix as a named area.
4661 AutoTArray<uint32_t, 16> implicitLines;
4662 uint32_t index;
4663 bool useStart = IsNameWithStartSuffix(aLine.LineName(), &index);
4664 if (useStart || IsNameWithEndSuffix(aLine.LineName(), &index)) {
4665 auto side = MakeLogicalSide(
4666 GetAxis(aSide), useStart ? LogicalEdge::Start : LogicalEdge::End);
4667 RefPtr<nsAtom> name = NS_Atomize(nsDependentSubstring(
4668 nsDependentAtomString(aLine.LineName()), 0, index));
4669 aNameMap.FindNamedAreas(name, side, implicitLines);
4670 }
4671 line = aNameMap.FindNamedLine(aLine.LineName(), &aNth, aFromIndex,
4672 implicitLines);
4673 }
4674
4675 if (line == 0) {
4676 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", 4676
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNth != 0" ") (" "we found all N named lines but 'line' is zero!"
")"); do { MOZ_CrashSequence(__null, 4676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4677 int32_t edgeLine;
4678 if (aLine.is_span) {
4679 // https://drafts.csswg.org/css-grid-2/#grid-placement-span-int
4680 // 'span <custom-ident> N'
4681 edgeLine = IsStart(aSide) ? 1 : aExplicitGridEnd;
4682 } else {
4683 // https://drafts.csswg.org/css-grid-2/#grid-placement-int
4684 // '<custom-ident> N'
4685 edgeLine = aNth < 0 ? 1 : aExplicitGridEnd;
4686 }
4687 // "If not enough lines with that name exist, all lines in the implicit
4688 // grid are assumed to have that name..."
4689 line = edgeLine + aNth;
4690 }
4691 }
4692 // Note: at this point, 'line' might be outside of aNameMap's allowed range,
4693 // [mClampMinLin, mClampMaxLine]. This is fine; we'll clamp once we've
4694 // resolved *both* the start and end line -- in particular, we clamp in
4695 // ResolveLineRange(). If we clamped here, it'd be premature -- if one line
4696 // is definite and the other is specified as a span to some named line
4697 // (i.e. we need to perform a name-search that starts from the definite
4698 // line), then it matters whether we clamp the definite line before or after
4699 // that search. See https://bugzilla.mozilla.org/show_bug.cgi?id=1800566#c6
4700 // for more.
4701 return line;
4702}
4703
4704nsGridContainerFrame::Grid::LinePair
4705nsGridContainerFrame::Grid::ResolveLineRangeHelper(
4706 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4707 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4708 const nsStylePosition* aStyle) {
4709 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"
, 4709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(kAutoLine) > kMaxLine"
")"); do { MOZ_CrashSequence(__null, 4709); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4710 auto startNum = std::clamp(aStart.line_num, kMinLine, kMaxLine);
4711 auto endNum = std::clamp(aEnd.line_num, kMinLine, kMaxLine);
4712
4713 if (aStart.is_span) {
4714 if (aEnd.is_span || aEnd.IsAuto()) {
4715 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4716 if (aStart.LineName()->IsEmpty()) {
4717 // span <integer> / span *
4718 // span <integer> / auto
4719 return LinePair(kAutoLine, startNum);
4720 }
4721 // span <custom-ident> / span *
4722 // span <custom-ident> / auto
4723 return LinePair(kAutoLine, 1); // XXX subgrid explicit size instead of 1?
4724 }
4725
4726 uint32_t from = endNum < 0 ? aExplicitGridEnd + 1 : 0;
4727 auto end = ResolveLine(aEnd, endNum, from, aNameMap,
4728 MakeLogicalSide(aAxis, LogicalEdge::End),
4729 aExplicitGridEnd, aStyle);
4730 int32_t span = startNum == 0 ? 1 : startNum;
4731 if (end <= 1) {
4732 // The end is at or before the first explicit line, thus all lines before
4733 // it match <custom-ident> since they're implicit.
4734 int32_t start = std::max(end - span, aNameMap.mClampMinLine);
4735 return LinePair(start, end);
4736 }
4737 auto start = ResolveLine(aStart, -span, end, aNameMap,
4738 MakeLogicalSide(aAxis, LogicalEdge::Start),
4739 aExplicitGridEnd, aStyle);
4740 return LinePair(start, end);
4741 }
4742
4743 int32_t start = kAutoLine;
4744 if (aStart.IsAuto()) {
4745 if (aEnd.IsAuto()) {
4746 // auto / auto
4747 return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
4748 }
4749 if (aEnd.is_span) {
4750 if (aEnd.LineName()->IsEmpty()) {
4751 // auto / span <integer>
4752 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"
, 4752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "endNum != 0"
")"); do { MOZ_CrashSequence(__null, 4752); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4753 return LinePair(start, endNum);
4754 }
4755 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4756 // auto / span <custom-ident>
4757 return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
4758 }
4759 } else {
4760 uint32_t from = startNum < 0 ? aExplicitGridEnd + 1 : 0;
4761 start = ResolveLine(aStart, startNum, from, aNameMap,
4762 MakeLogicalSide(aAxis, LogicalEdge::Start),
4763 aExplicitGridEnd, aStyle);
4764 if (aEnd.IsAuto()) {
4765 // A "definite line / auto" should resolve the auto to 'span 1'.
4766 // The error handling in ResolveLineRange will make that happen and also
4767 // clamp the end line correctly if we return "start / start".
4768 return LinePair(start, start);
4769 }
4770 }
4771
4772 uint32_t from;
4773 int32_t nth = endNum == 0 ? 1 : endNum;
4774 if (aEnd.is_span) {
4775 if (MOZ_UNLIKELY(start < 0)(__builtin_expect(!!(start < 0), 0))) {
4776 if (aEnd.LineName()->IsEmpty()) {
4777 return LinePair(start, start + nth);
4778 }
4779 from = 0;
4780 } else {
4781 if (start >= int32_t(aExplicitGridEnd)) {
4782 // The start is at or after the last explicit line, thus all lines
4783 // after it match <custom-ident> since they're implicit.
4784 return LinePair(start, std::min(start + nth, aNameMap.mClampMaxLine));
4785 }
4786 from = start;
4787 }
4788 } else {
4789 from = endNum < 0 ? aExplicitGridEnd + 1 : 0;
4790 }
4791 auto end = ResolveLine(aEnd, nth, from, aNameMap,
4792 MakeLogicalSide(aAxis, LogicalEdge::End),
4793 aExplicitGridEnd, aStyle);
4794 if (start == int32_t(kAutoLine)) {
4795 // auto / definite line
4796 start = std::max(aNameMap.mClampMinLine, end - 1);
4797 }
4798 return LinePair(start, end);
4799}
4800
4801nsGridContainerFrame::LineRange nsGridContainerFrame::Grid::ResolveLineRange(
4802 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4803 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4804 const nsStylePosition* aStyle) {
4805 LinePair r = ResolveLineRangeHelper(aStart, aEnd, aNameMap, aAxis,
4806 aExplicitGridEnd, aStyle);
4807 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"
, 4807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r.second != int32_t(kAutoLine)"
")"); do { MOZ_CrashSequence(__null, 4807); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4808
4809 if (r.first == int32_t(kAutoLine)) {
4810 // r.second is a span, clamp it to aNameMap.mClampMaxLine - 1 so that
4811 // the returned range has a HypotheticalEnd <= aNameMap.mClampMaxLine.
4812 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
4813 r.second = std::min(r.second, aNameMap.mClampMaxLine - 1);
4814 } else {
4815 // Clamp the lines to be within our limits, per
4816 // https://drafts.csswg.org/css-grid-2/#overlarge-grids
4817 // Note that our limits here might come from the [kMinLine, kMaxLine]
4818 // extremes; or, they might just be the bounds of a subgrid's explicit
4819 // grid. We use the same clamping approach either way, per
4820 // https://drafts.csswg.org/css-grid-2/#subgrid-implicit ("using the same
4821 // procedure as for clamping placement in an overly-large grid").
4822 //
4823 // Note that these two clamped assignments might collapse our range to
4824 // have both edges pointing at the same line (spanning 0 tracks); this
4825 // might happen here if e.g. r.first were mClampMaxLine, and r.second gets
4826 // clamped from some higher number down to mClampMaxLine. We'll handle this
4827 // by shifting the inner line (r.first in this hypothetical) inwards by 1,
4828 // in the #grid-placement-errors section; that achieves the outcome of
4829 // the #overlarge-grids clamping spec text that says "its span must be
4830 // truncated to 1" when clamping an item that was completely outside the
4831 // limits.
4832 r.first =
4833 std::clamp(r.first, aNameMap.mClampMinLine, aNameMap.mClampMaxLine);
4834 r.second =
4835 std::clamp(r.second, aNameMap.mClampMinLine, aNameMap.mClampMaxLine);
4836
4837 // Handle grid placement errors.
4838 // https://drafts.csswg.org/css-grid-2/#grid-placement-errors
4839 if (r.first > r.second) {
4840 std::swap(r.first, r.second);
4841 } else if (r.first == r.second) {
4842 // (This is #grid-placement-errors fixup, but it's also where we ensure
4843 // that any #overlarge-grids fixup that we did above will end up
4844 // truncating the range to a span of 1 rather than 0 -- i.e. sliding
4845 // inwards if needed.)
4846 if (MOZ_UNLIKELY(r.first == aNameMap.mClampMaxLine)(__builtin_expect(!!(r.first == aNameMap.mClampMaxLine), 0))) {
4847 r.first = aNameMap.mClampMaxLine - 1;
4848 }
4849 r.second = r.first + 1;
4850 }
4851 }
4852 return LineRange(r.first, r.second);
4853}
4854
4855nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceDefinite(
4856 nsIFrame* aChild, const LineNameMap& aColLineNameMap,
4857 const LineNameMap& aRowLineNameMap, const nsStylePosition* aStyle) {
4858 const nsStylePosition* itemStyle = aChild->StylePosition();
4859 return GridArea(
4860 ResolveLineRange(itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
4861 aColLineNameMap, LogicalAxis::Inline,
4862 mExplicitGridColEnd, aStyle),
4863 ResolveLineRange(itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
4864 aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
4865 aStyle));
4866}
4867
4868nsGridContainerFrame::LineRange
4869nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
4870 const StyleGridLine& aStart, const StyleGridLine& aEnd,
4871 const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
4872 int32_t aGridStart, int32_t aGridEnd, const nsStylePosition* aStyle) {
4873 if (aStart.IsAuto()) {
4874 if (aEnd.IsAuto()) {
4875 return LineRange(kAutoLine, kAutoLine);
4876 }
4877 uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0;
4878 int32_t end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap,
4879 MakeLogicalSide(aAxis, LogicalEdge::End),
4880 aExplicitGridEnd, aStyle);
4881 if (aEnd.is_span) {
4882 ++end;
4883 }
4884 // A line outside the existing grid is treated as 'auto' for abs.pos (10.1).
4885 end = AutoIfOutside(end, aGridStart, aGridEnd);
4886 return LineRange(kAutoLine, end);
4887 }
4888
4889 if (aEnd.IsAuto()) {
4890 uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0;
4891 int32_t start = ResolveLine(aStart, aStart.line_num, from, aNameMap,
4892 MakeLogicalSide(aAxis, LogicalEdge::Start),
4893 aExplicitGridEnd, aStyle);
4894 if (aStart.is_span) {
4895 start = std::max(aGridEnd - start, aGridStart);
4896 }
4897 start = AutoIfOutside(start, aGridStart, aGridEnd);
4898 return LineRange(start, kAutoLine);
4899 }
4900
4901 LineRange r =
4902 ResolveLineRange(aStart, aEnd, aNameMap, aAxis, aExplicitGridEnd, aStyle);
4903 if (r.IsAuto()) {
4904 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", 4906
); 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, 4906); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4905 "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", 4906
); 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, 4906); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4906 "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", 4906
); 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, 4906); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4907 // The second span was ignored per 9.2.1. For abs.pos., 10.1 says that this
4908 // case should result in "auto / auto" unlike normal flow grid items.
4909 return LineRange(kAutoLine, kAutoLine);
4910 }
4911
4912 return LineRange(AutoIfOutside(r.mUntranslatedStart, aGridStart, aGridEnd),
4913 AutoIfOutside(r.mUntranslatedEnd, aGridStart, aGridEnd));
4914}
4915
4916nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceAbsPos(
4917 nsIFrame* aChild, const LineNameMap& aColLineNameMap,
4918 const LineNameMap& aRowLineNameMap, const nsStylePosition* aStyle) {
4919 const nsStylePosition* itemStyle = aChild->StylePosition();
4920 int32_t gridColStart = 1 - mExplicitGridOffsetCol;
4921 int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
4922 return GridArea(ResolveAbsPosLineRange(
4923 itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
4924 aColLineNameMap, LogicalAxis::Inline, mExplicitGridColEnd,
4925 gridColStart, mGridColEnd, aStyle),
4926 ResolveAbsPosLineRange(
4927 itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
4928 aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
4929 gridRowStart, mGridRowEnd, aStyle));
4930}
4931
4932uint32_t nsGridContainerFrame::Grid::FindAutoCol(uint32_t aStartCol,
4933 uint32_t aLockedRow,
4934 const GridArea* aArea) const {
4935 const uint32_t extent = aArea->mCols.Extent();
4936 const uint32_t iStart = aLockedRow;
4937 const uint32_t iEnd = iStart + aArea->mRows.Extent();
4938 uint32_t candidate = aStartCol;
4939 for (uint32_t i = iStart; i < iEnd;) {
4940 if (i >= mCellMap.mCells.Length()) {
4941 break;
4942 }
4943 const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
4944 const uint32_t len = cellsInRow.Length();
4945 const uint32_t lastCandidate = candidate;
4946 // Find the first gap in the current row that's at least 'extent' wide.
4947 // ('gap' tracks how wide the current column gap is.)
4948 for (uint32_t j = candidate, gap = 0; j < len && gap < extent; ++j) {
4949 if (!cellsInRow[j].mIsOccupied) {
4950 ++gap;
4951 continue;
4952 }
4953 candidate = j + 1;
4954 gap = 0;
4955 }
4956 if (lastCandidate < candidate && i != iStart) {
4957 // Couldn't fit 'extent' tracks at 'lastCandidate' here so we must
4958 // restart from the beginning with the new 'candidate'.
4959 i = iStart;
4960 } else {
4961 ++i;
4962 }
4963 }
4964 return candidate;
4965}
4966
4967void nsGridContainerFrame::Grid::PlaceAutoCol(uint32_t aStartCol,
4968 GridArea* aArea,
4969 uint32_t aClampMaxColLine) const {
4970 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", 4970)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mRows.IsDefinite() && aArea->mCols.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 4970); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4971 uint32_t col = FindAutoCol(aStartCol, aArea->mRows.mStart, aArea);
4972 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
4973 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", 4973)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 4973); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4974}
4975
4976uint32_t nsGridContainerFrame::Grid::FindAutoRow(uint32_t aLockedCol,
4977 uint32_t aStartRow,
4978 const GridArea* aArea) const {
4979 const uint32_t extent = aArea->mRows.Extent();
4980 const uint32_t jStart = aLockedCol;
4981 const uint32_t jEnd = jStart + aArea->mCols.Extent();
4982 const uint32_t iEnd = mCellMap.mCells.Length();
4983 uint32_t candidate = aStartRow;
4984 // Find the first gap in the rows that's at least 'extent' tall.
4985 // ('gap' tracks how tall the current row gap is.)
4986 for (uint32_t i = candidate, gap = 0; i < iEnd && gap < extent; ++i) {
4987 ++gap; // tentative, but we may reset it below if a column is occupied
4988 const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
4989 const uint32_t clampedJEnd = std::min<uint32_t>(jEnd, cellsInRow.Length());
4990 // Check if the current row is unoccupied from jStart to jEnd.
4991 for (uint32_t j = jStart; j < clampedJEnd; ++j) {
4992 if (cellsInRow[j].mIsOccupied) {
4993 // Couldn't fit 'extent' rows at 'candidate' here; we hit something
4994 // at row 'i'. So, try the row after 'i' as our next candidate.
4995 candidate = i + 1;
4996 gap = 0;
4997 break;
4998 }
4999 }
5000 }
5001 return candidate;
5002}
5003
5004void nsGridContainerFrame::Grid::PlaceAutoRow(uint32_t aStartRow,
5005 GridArea* aArea,
5006 uint32_t aClampMaxRowLine) const {
5007 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", 5007)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsDefinite() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 5007); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5008 uint32_t row = FindAutoRow(aArea->mCols.mStart, aStartRow, aArea);
5009 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
5010 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", 5010)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 5010); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5011}
5012
5013void nsGridContainerFrame::Grid::PlaceAutoAutoInRowOrder(
5014 uint32_t aStartCol, uint32_t aStartRow, GridArea* aArea,
5015 uint32_t aClampMaxColLine, uint32_t aClampMaxRowLine) const {
5016 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", 5016)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 5016); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5017 const uint32_t colExtent = aArea->mCols.Extent();
5018 const uint32_t gridRowEnd = mGridRowEnd;
5019 const uint32_t gridColEnd = mGridColEnd;
5020 uint32_t col = aStartCol;
5021 uint32_t row = aStartRow;
5022 for (; row < gridRowEnd; ++row) {
5023 col = FindAutoCol(col, row, aArea);
5024 if (col + colExtent <= gridColEnd) {
5025 break;
5026 }
5027 col = 0;
5028 }
5029 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", 5030
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "row < gridRowEnd || col == 0"
") (" "expected column 0 for placing in a new row" ")"); do {
MOZ_CrashSequence(__null, 5030); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5030 "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", 5030
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "row < gridRowEnd || col == 0"
") (" "expected column 0 for placing in a new row" ")"); do {
MOZ_CrashSequence(__null, 5030); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5031 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
5032 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
5033 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", 5033)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 5033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5034}
5035
5036void nsGridContainerFrame::Grid::PlaceAutoAutoInColOrder(
5037 uint32_t aStartCol, uint32_t aStartRow, GridArea* aArea,
5038 uint32_t aClampMaxColLine, uint32_t aClampMaxRowLine) const {
5039 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", 5039)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->mCols.IsAuto() && aArea->mRows.IsAuto()"
")"); do { MOZ_CrashSequence(__null, 5039); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5040 const uint32_t rowExtent = aArea->mRows.Extent();
5041 const uint32_t gridRowEnd = mGridRowEnd;
5042 const uint32_t gridColEnd = mGridColEnd;
5043 uint32_t col = aStartCol;
5044 uint32_t row = aStartRow;
5045 for (; col < gridColEnd; ++col) {
5046 row = FindAutoRow(col, row, aArea);
5047 if (row + rowExtent <= gridRowEnd) {
5048 break;
5049 }
5050 row = 0;
5051 }
5052 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", 5053
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "col < gridColEnd || row == 0"
") (" "expected row 0 for placing in a new column" ")"); do {
MOZ_CrashSequence(__null, 5053); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5053 "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", 5053
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "col < gridColEnd || row == 0"
") (" "expected row 0 for placing in a new column" ")"); do {
MOZ_CrashSequence(__null, 5053); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5054 aArea->mCols.ResolveAutoPosition(col, aClampMaxColLine);
5055 aArea->mRows.ResolveAutoPosition(row, aClampMaxRowLine);
5056 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", 5056)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea->IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 5056); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5057}
5058
5059template <typename IsEmptyFuncT>
5060Maybe<nsTArray<uint32_t>>
5061nsGridContainerFrame::Grid::CalculateAdjustForAutoFitElements(
5062 uint32_t* const aOutNumEmptyLines, TrackSizingFunctions& aSizingFunctions,
5063 uint32_t aNumGridLines, IsEmptyFuncT aIsEmptyFunc) {
5064 Maybe<nsTArray<uint32_t>> trackAdjust;
5065 uint32_t& numEmptyLines = *aOutNumEmptyLines;
5066 numEmptyLines = 0;
5067 if (aSizingFunctions.NumRepeatTracks() > 0) {
5068 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"
, 5068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSizingFunctions.mHasRepeatAuto"
")"); do { MOZ_CrashSequence(__null, 5068); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5069 // Since this loop is concerned with just the repeat tracks, we
5070 // iterate from 0..NumRepeatTracks() which is the natural range of
5071 // mRemoveRepeatTracks. This means we have to add
5072 // (mExplicitGridOffset + mRepeatAutoStart) to get a zero-based
5073 // index for arrays like mCellMap/aIsEmptyFunc and trackAdjust. We'll then
5074 // fill out the trackAdjust array for all the remaining lines.
5075 const uint32_t repeatStart = (aSizingFunctions.mExplicitGridOffset +
5076 aSizingFunctions.mRepeatAutoStart);
5077 const uint32_t numRepeats = aSizingFunctions.NumRepeatTracks();
5078 for (uint32_t i = 0; i < numRepeats; ++i) {
5079 if (numEmptyLines) {
5080 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", 5080)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "trackAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5080); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5081 (*trackAdjust)[repeatStart + i] = numEmptyLines;
5082 }
5083 if (aIsEmptyFunc(repeatStart + i)) {
5084 ++numEmptyLines;
5085 if (trackAdjust.isNothing()) {
5086 trackAdjust.emplace(aNumGridLines);
5087 trackAdjust->SetLength(aNumGridLines);
5088 PodZero(trackAdjust->Elements(), trackAdjust->Length());
5089 }
5090
5091 aSizingFunctions.mRemovedRepeatTracks[i] = true;
5092 }
5093 }
5094 // Fill out the trackAdjust array for all the tracks after the repeats.
5095 if (numEmptyLines) {
5096 for (uint32_t line = repeatStart + numRepeats; line < aNumGridLines;
5097 ++line) {
5098 (*trackAdjust)[line] = numEmptyLines;
5099 }
5100 }
5101 }
5102
5103 return trackAdjust;
5104}
5105
5106void nsGridContainerFrame::Grid::SubgridPlaceGridItems(
5107 GridReflowInput& aParentGridRI, Grid* aParentGrid,
5108 const GridItemInfo& aGridItem) {
5109 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"
, 5111); 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, 5111); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5110 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"
, 5111); 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, 5111); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5111 "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"
, 5111); 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, 5111); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5112 if (aGridItem.IsSubgrid(LogicalAxis::Inline)) {
5113 aParentGridRI.mFrame->AddStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
5114 }
5115 if (aGridItem.IsSubgrid(LogicalAxis::Block)) {
5116 aParentGridRI.mFrame->AddStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
5117 }
5118 auto* childGrid = aGridItem.SubgridFrame();
5119 const auto* pos = childGrid->StylePosition();
5120 childGrid->NormalizeChildLists();
5121 GridReflowInput gridRI(childGrid, aParentGridRI.mRenderingContext);
5122 childGrid->InitImplicitNamedAreas(pos);
5123
5124 const bool isOrthogonal = aParentGridRI.mWM.IsOrthogonalTo(gridRI.mWM);
5125 // Record the subgrid's GridArea in a frame property.
5126 auto* subgrid = childGrid->GetProperty(Subgrid::Prop());
5127 if (!subgrid) {
5128 subgrid = new Subgrid(aGridItem.mArea, isOrthogonal, aParentGridRI.mWM);
5129 childGrid->SetProperty(Subgrid::Prop(), subgrid);
5130 } else {
5131 subgrid->mArea = aGridItem.mArea;
5132 subgrid->mIsOrthogonal = isOrthogonal;
5133 subgrid->mGridItems.Clear();
5134 subgrid->mAbsPosItems.Clear();
5135 }
5136
5137 // Abs.pos. subgrids may have kAutoLine in their area. Map those to the edge
5138 // line in the parent's grid (zero-based line numbers).
5139 if (MOZ_UNLIKELY(subgrid->mArea.mCols.mStart == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mCols.mStart == kAutoLine
), 0))
) {
5140 subgrid->mArea.mCols.mStart = 0;
5141 }
5142 if (MOZ_UNLIKELY(subgrid->mArea.mCols.mEnd == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mCols.mEnd == kAutoLine
), 0))
) {
5143 subgrid->mArea.mCols.mEnd = aParentGrid->mGridColEnd - 1;
5144 }
5145 if (MOZ_UNLIKELY(subgrid->mArea.mRows.mStart == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mRows.mStart == kAutoLine
), 0))
) {
5146 subgrid->mArea.mRows.mStart = 0;
5147 }
5148 if (MOZ_UNLIKELY(subgrid->mArea.mRows.mEnd == kAutoLine)(__builtin_expect(!!(subgrid->mArea.mRows.mEnd == kAutoLine
), 0))
) {
5149 subgrid->mArea.mRows.mEnd = aParentGrid->mGridRowEnd - 1;
5150 }
5151
5152 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"
, 5155); 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, 5155); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5153 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"
, 5155); 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, 5155); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5154 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"
, 5155); 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, 5155); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5155 "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"
, 5155); 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, 5155); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5156
5157 // The min/sz/max sizes are the input to the "repeat-to-fill" algorithm:
5158 // https://drafts.csswg.org/css-grid-2/#auto-repeat
5159 // They're only used for auto-repeat in a non-subgridded axis so we skip
5160 // computing them otherwise.
5161 RepeatTrackSizingInput repeatSizing(gridRI.mWM);
5162 if (!childGrid->IsColSubgrid() && gridRI.mColFunctions.mHasRepeatAuto) {
5163 // FIXME: Bug 1918794. Figure out if it is fine to pass Nothing() here. It
5164 // seems we use a different way to calculate the size if the container is a
5165 // subgrid. Otherwise, we may have to know the area size that this grid item
5166 // is placed, and pass the area size as the containing block size to this
5167 // function.
5168 repeatSizing.InitFromStyle(LogicalAxis::Inline, gridRI.mWM, gridRI.mFrame,
5169 gridRI.mFrame->Style(),
5170 gridRI.mFrame->GetAspectRatio(), Nothing());
5171 }
5172 if (!childGrid->IsRowSubgrid() && gridRI.mRowFunctions.mHasRepeatAuto) {
5173 // FIXME: Bug 1918794. Same as above.
5174 repeatSizing.InitFromStyle(LogicalAxis::Block, gridRI.mWM, gridRI.mFrame,
5175 gridRI.mFrame->Style(),
5176 gridRI.mFrame->GetAspectRatio(), Nothing());
5177 }
5178
5179 PlaceGridItems(gridRI, repeatSizing);
5180
5181 subgrid->mGridItems = std::move(gridRI.mGridItems);
5182 subgrid->mAbsPosItems = std::move(gridRI.mAbsPosItems);
5183 subgrid->mGridColEnd = mGridColEnd;
5184 subgrid->mGridRowEnd = mGridRowEnd;
5185}
5186
5187void nsGridContainerFrame::Grid::PlaceGridItems(
5188 GridReflowInput& aGridRI, const RepeatTrackSizingInput& aSizes) {
5189 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"
, 5189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCellMap.mCells.IsEmpty()"
") (" "unexpected entries in cell map" ")"); do { MOZ_CrashSequence
(__null, 5189); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5190
5191 mAreas = aGridRI.mFrame->GetImplicitNamedAreas();
5192
5193 if (aGridRI.mFrame->HasSubgridItems() || aGridRI.mFrame->IsSubgrid()) {
5194 if (auto* uts = aGridRI.mFrame->GetUsedTrackSizes()) {
5195 uts->mCanResolveLineRangeSize = {false, false};
5196 uts->mTrackPlans[LogicalAxis::Inline].ClearAndRetainStorage();
5197 uts->mTrackPlans[LogicalAxis::Block].ClearAndRetainStorage();
5198 }
5199 }
5200
5201 // SubgridPlaceGridItems will set these if we find any subgrid items.
5202 aGridRI.mFrame->RemoveStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
5203 NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
5204
5205 // https://drafts.csswg.org/css-grid-2/#grid-definition
5206 // Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
5207 // This is determined by the larger of the number of rows/columns defined
5208 // by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
5209 // Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
5210 // Note that this is for a grid with a 1,1 origin. We'll change that
5211 // to a 0,0 based grid after placing definite lines.
5212 const nsStylePosition* const gridStyle = aGridRI.mGridStyle;
5213 const auto* areas = gridStyle->mGridTemplateAreas.IsNone()
5214 ? nullptr
5215 : &*gridStyle->mGridTemplateAreas.AsAreas();
5216 const LineNameMap* parentLineNameMap = nullptr;
5217 const LineRange* subgridRange = nullptr;
5218 bool subgridAxisIsSameDirection = true;
5219 bool subgridIsOrthogonal = false;
5220 if (!aGridRI.mFrame->IsColSubgrid()) {
5221 aGridRI.mColFunctions.InitRepeatTracks(
5222 gridStyle->mColumnGap, aSizes.mMin.ISize(aGridRI.mWM),
5223 aSizes.mSize.ISize(aGridRI.mWM), aSizes.mMax.ISize(aGridRI.mWM));
5224 uint32_t areaCols = areas ? areas->width + 1 : 1;
5225 mExplicitGridColEnd =
5226 aGridRI.mColFunctions.ComputeExplicitGridEnd(areaCols);
5227 } else {
5228 const auto* subgrid = aGridRI.mFrame->GetProperty(Subgrid::Prop());
5229 subgridRange = &subgrid->SubgridCols();
5230 uint32_t extent = subgridRange->Extent();
5231 mExplicitGridColEnd = extent + 1; // the grid is 1-based at this point
5232 parentLineNameMap =
5233 ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Inline);
5234 auto parentWM =
5235 aGridRI.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
5236 subgridAxisIsSameDirection =
5237 aGridRI.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, parentWM);
5238 subgridIsOrthogonal = subgrid->mIsOrthogonal;
5239 }
5240 mGridColEnd = mExplicitGridColEnd;
5241 LineNameMap colLineNameMap(gridStyle, mAreas, aGridRI.mColFunctions,
5242 parentLineNameMap, subgridRange,
5243 subgridAxisIsSameDirection, subgridIsOrthogonal);
5244
5245 if (!aGridRI.mFrame->IsRowSubgrid()) {
5246 const Maybe<nscoord> containBSize = aGridRI.mFrame->ContainIntrinsicBSize();
5247 const nscoord repeatTrackSizingBSize = [&] {
5248 // This clamping only applies to auto sizes.
5249 if (containBSize &&
5250 aSizes.mSize.BSize(aGridRI.mWM) == NS_UNCONSTRAINEDSIZE) {
5251 return CSSMinMax(*containBSize, aSizes.mMin.BSize(aGridRI.mWM),
5252 aSizes.mMax.BSize(aGridRI.mWM));
5253 }
5254 return aSizes.mSize.BSize(aGridRI.mWM);
5255 }();
5256 aGridRI.mRowFunctions.InitRepeatTracks(
5257 gridStyle->mRowGap, aSizes.mMin.BSize(aGridRI.mWM),
5258 repeatTrackSizingBSize, aSizes.mMax.BSize(aGridRI.mWM));
5259 uint32_t areaRows = areas ? areas->strings.Length() + 1 : 1;
5260 mExplicitGridRowEnd =
5261 aGridRI.mRowFunctions.ComputeExplicitGridEnd(areaRows);
5262 parentLineNameMap = nullptr;
5263 subgridRange = nullptr;
5264 } else {
5265 const auto* subgrid = aGridRI.mFrame->GetProperty(Subgrid::Prop());
5266 subgridRange = &subgrid->SubgridRows();
5267 uint32_t extent = subgridRange->Extent();
5268 mExplicitGridRowEnd = extent + 1; // the grid is 1-based at this point
5269 parentLineNameMap =
5270 ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Block);
5271 auto parentWM =
5272 aGridRI.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
5273 subgridAxisIsSameDirection =
5274 aGridRI.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, parentWM);
5275 subgridIsOrthogonal = subgrid->mIsOrthogonal;
5276 }
5277 mGridRowEnd = mExplicitGridRowEnd;
5278 LineNameMap rowLineNameMap(gridStyle, mAreas, aGridRI.mRowFunctions,
5279 parentLineNameMap, subgridRange,
5280 subgridAxisIsSameDirection, subgridIsOrthogonal);
5281
5282 const bool isSubgridOrItemInSubgrid =
5283 aGridRI.mFrame->IsSubgrid() || !!mParentGrid;
5284 auto SetSubgridChildEdgeBits =
5285 [this, isSubgridOrItemInSubgrid](GridItemInfo& aItem) -> void {
5286 if (isSubgridOrItemInSubgrid) {
5287 const auto& area = aItem.mArea;
5288 if (area.mCols.mStart == 0) {
5289 aItem.mState[LogicalAxis::Inline] |= ItemState::eStartEdge;
5290 }
5291 if (area.mCols.mEnd == mGridColEnd) {
5292 aItem.mState[LogicalAxis::Inline] |= ItemState::eEndEdge;
5293 }
5294 if (area.mRows.mStart == 0) {
5295 aItem.mState[LogicalAxis::Block] |= ItemState::eStartEdge;
5296 }
5297 if (area.mRows.mEnd == mGridRowEnd) {
5298 aItem.mState[LogicalAxis::Block] |= ItemState::eEndEdge;
5299 }
5300 }
5301 };
5302
5303 SetLineMaps(&colLineNameMap, &rowLineNameMap);
5304
5305 // https://drafts.csswg.org/css-grid-2/#line-placement
5306 // Resolve definite positions per spec chapter 8.3.
5307 int32_t minCol = 1;
5308 int32_t minRow = 1;
5309 aGridRI.mGridItems.ClearAndRetainStorage();
5310 aGridRI.mIter.Reset();
5311
5312 bool needToRecordAutoFlowCounter =
5313 gridStyle->mGridTemplateColumns.IsNone() &&
5314 !gridStyle->mGridTemplateRows.IsNone() &&
5315 !aGridRI.mFrame->Style()->HasAuthorSpecifiedGridAutoFlow();
5316
5317 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5318 nsIFrame* child = *aGridRI.mIter;
5319 GridItemInfo* info = aGridRI.mGridItems.AppendElement(GridItemInfo(
5320 child,
5321 PlaceDefinite(child, colLineNameMap, rowLineNameMap, gridStyle)));
5322 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"
, 5323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
") (" "ItemIndex() is broken" ")"); do { MOZ_CrashSequence(__null
, 5323); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
5323 "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"
, 5323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mIter.ItemIndex() == aGridRI.mGridItems.Length() - 1"
") (" "ItemIndex() is broken" ")"); do { MOZ_CrashSequence(__null
, 5323); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
5324 if (needToRecordAutoFlowCounter &&
5325 (info->mState[LogicalAxis::Inline] & ItemState::eAutoPlacement ||
5326 info->mState[LogicalAxis::Block] & ItemState::eAutoPlacement)) {
5327 aGridRI.mFrame->PresContext()->Document()->SetUseCounter(
5328 eUseCounter_custom_GridAutoFlowInitialValueChange);
5329 needToRecordAutoFlowCounter = false;
5330 }
5331
5332 GridArea& area = info->mArea;
5333 if (area.mCols.IsDefinite()) {
5334 minCol = std::min(minCol, area.mCols.mUntranslatedStart);
5335 }
5336 if (area.mRows.IsDefinite()) {
5337 minRow = std::min(minRow, area.mRows.mUntranslatedStart);
5338 }
5339 }
5340
5341 // Translate the whole grid so that the top-/left-most area is at 0,0.
5342 mExplicitGridOffsetCol = 1 - minCol; // minCol/Row is always <= 1, see above
5343 mExplicitGridOffsetRow = 1 - minRow;
5344 aGridRI.mColFunctions.mExplicitGridOffset = mExplicitGridOffsetCol;
5345 aGridRI.mRowFunctions.mExplicitGridOffset = mExplicitGridOffsetRow;
5346 const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
5347 const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
5348 const bool isRowMasonry = aGridRI.mFrame->IsRowMasonry();
5349 const bool isColMasonry = aGridRI.mFrame->IsColMasonry();
5350 const bool isMasonry = isColMasonry || isRowMasonry;
5351 mGridColEnd += offsetToColZero;
5352 mGridRowEnd += offsetToRowZero;
5353 const uint32_t gridAxisTrackCount = isRowMasonry ? mGridColEnd : mGridRowEnd;
5354 aGridRI.mIter.Reset();
5355 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5356 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5357 GridArea& area = item.mArea;
5358 if (area.mCols.IsDefinite()) {
5359 area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
5360 area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
5361 }
5362 if (area.mRows.IsDefinite()) {
5363 area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
5364 area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
5365 }
5366 if (area.IsDefinite()) {
5367 if (isMasonry) {
5368 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5369 }
5370 if (item.IsSubgrid()) {
5371 Grid grid(this);
5372 grid.SubgridPlaceGridItems(aGridRI, this, item);
5373 }
5374 mCellMap.Fill(area);
5375 InflateGridFor(area);
5376 SetSubgridChildEdgeBits(item);
5377 }
5378 }
5379
5380 // https://drafts.csswg.org/css-grid-2/#auto-placement-algo
5381 // Step 1, place 'auto' items that have one definite position -
5382 // definite row (column) for grid-auto-flow:row (column).
5383 auto flowStyle = gridStyle->mGridAutoFlow;
5384 const bool isRowOrder =
5385 isMasonry ? isRowMasonry : !!(flowStyle & StyleGridAutoFlow::ROW);
5386 const bool isSparse = !(flowStyle & StyleGridAutoFlow::DENSE);
5387 uint32_t clampMaxColLine = colLineNameMap.mClampMaxLine + offsetToColZero;
5388 uint32_t clampMaxRowLine = rowLineNameMap.mClampMaxLine + offsetToRowZero;
5389 // We need 1 cursor per row (or column) if placement is sparse.
5390 {
5391 Maybe<nsTHashMap<nsUint32HashKey, uint32_t>> cursors;
5392 if (isSparse) {
5393 cursors.emplace();
5394 }
5395 auto placeAutoMinorFunc =
5396 isRowOrder ? &Grid::PlaceAutoCol : &Grid::PlaceAutoRow;
5397 uint32_t clampMaxLine = isRowOrder ? clampMaxColLine : clampMaxRowLine;
5398 aGridRI.mIter.Reset();
5399 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5400 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5401 GridArea& area = item.mArea;
5402 LineRange& major = isRowOrder ? area.mRows : area.mCols;
5403 LineRange& minor = isRowOrder ? area.mCols : area.mRows;
5404 if (major.IsDefinite() && minor.IsAuto()) {
5405 // Items with 'auto' in the minor dimension only.
5406 const uint32_t cursor = isSparse ? cursors->Get(major.mStart) : 0;
5407 (this->*placeAutoMinorFunc)(cursor, &area, clampMaxLine);
5408 if (isMasonry) {
5409 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5410 }
5411 if (item.IsSubgrid()) {
5412 Grid grid(this);
5413 grid.SubgridPlaceGridItems(aGridRI, this, item);
5414 }
5415 mCellMap.Fill(area);
5416 SetSubgridChildEdgeBits(item);
5417 if (isSparse) {
5418 cursors->InsertOrUpdate(major.mStart, minor.mEnd);
5419 }
5420 }
5421 InflateGridFor(area); // Step 2, inflating for auto items too
5422 }
5423 }
5424
5425 // XXX NOTE possible spec issue.
5426 // XXX It's unclear if the remaining major-dimension auto and
5427 // XXX auto in both dimensions should use the same cursor or not,
5428 // XXX https://www.w3.org/Bugs/Public/show_bug.cgi?id=16044
5429 // XXX seems to indicate it shouldn't.
5430 // XXX https://drafts.csswg.org/css-grid-2/#auto-placement-algo
5431 // XXX now says it should (but didn't in earlier versions)
5432
5433 // Step 3, place the remaining grid items
5434 uint32_t cursorMajor = 0; // for 'dense' these two cursors will stay at 0,0
5435 uint32_t cursorMinor = 0;
5436 auto placeAutoMajorFunc =
5437 isRowOrder ? &Grid::PlaceAutoRow : &Grid::PlaceAutoCol;
5438 uint32_t clampMaxMajorLine = isRowOrder ? clampMaxRowLine : clampMaxColLine;
5439 aGridRI.mIter.Reset();
5440 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5441 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5442 GridArea& area = item.mArea;
5443 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", 5444
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aGridRI.mIter == item.mFrame"
") (" "iterator out of sync with aState.mGridItems" ")"); do
{ MOZ_CrashSequence(__null, 5444); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5444 "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", 5444
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aGridRI.mIter == item.mFrame"
") (" "iterator out of sync with aState.mGridItems" ")"); do
{ MOZ_CrashSequence(__null, 5444); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5445 LineRange& major = isRowOrder ? area.mRows : area.mCols;
5446 LineRange& minor = isRowOrder ? area.mCols : area.mRows;
5447 if (major.IsAuto()) {
5448 if (minor.IsDefinite()) {
5449 // Items with 'auto' in the major dimension only.
5450 if (isSparse) {
5451 if (minor.mStart < cursorMinor) {
5452 ++cursorMajor;
5453 }
5454 cursorMinor = minor.mStart;
5455 }
5456 (this->*placeAutoMajorFunc)(cursorMajor, &area, clampMaxMajorLine);
5457 if (isSparse) {
5458 cursorMajor = major.mStart;
5459 }
5460 } else {
5461 // Items with 'auto' in both dimensions.
5462 if (isRowOrder) {
5463 PlaceAutoAutoInRowOrder(cursorMinor, cursorMajor, &area,
5464 clampMaxColLine, clampMaxRowLine);
5465 } else {
5466 PlaceAutoAutoInColOrder(cursorMajor, cursorMinor, &area,
5467 clampMaxColLine, clampMaxRowLine);
5468 }
5469 if (isSparse) {
5470 cursorMajor = major.mStart;
5471 cursorMinor = minor.mEnd;
5472#ifdef DEBUG1
5473 uint32_t gridMajorEnd = isRowOrder ? mGridRowEnd : mGridColEnd;
5474 uint32_t gridMinorEnd = isRowOrder ? mGridColEnd : mGridRowEnd;
5475 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"
, 5477); 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, 5477); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5476 "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"
, 5477); 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, 5477); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5477 "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"
, 5477); 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, 5477); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5478 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", 5479
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMinor <= gridMinorEnd"
") (" "we shouldn't add implicit minor tracks for auto/auto"
")"); do { MOZ_CrashSequence(__null, 5479); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5479 "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", 5479
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cursorMinor <= gridMinorEnd"
") (" "we shouldn't add implicit minor tracks for auto/auto"
")"); do { MOZ_CrashSequence(__null, 5479); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5480#endif
5481 }
5482 }
5483 if (isMasonry) {
5484 item.MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5485 }
5486 if (item.IsSubgrid()) {
5487 Grid grid(this);
5488 grid.SubgridPlaceGridItems(aGridRI, this, item);
5489 }
5490 mCellMap.Fill(area);
5491 InflateGridFor(area);
5492 SetSubgridChildEdgeBits(item);
5493 // XXXmats it might be possible to optimize this a bit for masonry layout
5494 // if this item was placed in the 2nd row && !isSparse, or the 1st row
5495 // is full. Still gotta inflate the grid for all items though to make
5496 // the grid large enough...
5497 }
5498 }
5499
5500 // Force all items into the 1st/2nd track and have span 1 in the masonry axis.
5501 // (See comment on nsGridContainerFrame::MasonryLayout().)
5502 if (isMasonry) {
5503 auto masonryAxis = isRowMasonry ? LogicalAxis::Block : LogicalAxis::Inline;
5504 aGridRI.mIter.Reset();
5505 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
5506 auto& item = aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
5507 auto& masonryRange = item.mArea.LineRangeForAxis(masonryAxis);
5508 masonryRange.mStart = std::min(masonryRange.mStart, 1U);
5509 masonryRange.mEnd = masonryRange.mStart + 1U;
5510 }
5511 }
5512
5513 if (auto* absCB = aGridRI.mFrame->GetAbsoluteContainingBlock();
5514 absCB && absCB->PrepareAbsoluteFrames(aGridRI.mFrame)) {
5515 // 10.1. With a Grid Container as Containing Block
5516 // https://drafts.csswg.org/css-grid-2/#abspos-items
5517 // We only resolve definite lines here; we'll align auto positions to the
5518 // grid container later during reflow.
5519 const nsFrameList& children = absCB->GetChildList();
5520 const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
5521 const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
5522 // Untranslate the grid again temporarily while resolving abs.pos. lines.
5523 AutoRestore<uint32_t> zeroOffsetGridColEnd(mGridColEnd);
5524 AutoRestore<uint32_t> zeroOffsetGridRowEnd(mGridRowEnd);
5525 mGridColEnd -= offsetToColZero;
5526 mGridRowEnd -= offsetToRowZero;
5527 aGridRI.mAbsPosItems.ClearAndRetainStorage();
5528 for (nsIFrame* child : children) {
5529 GridItemInfo* info = aGridRI.mAbsPosItems.AppendElement(GridItemInfo(
5530 child,
5531 PlaceAbsPos(child, colLineNameMap, rowLineNameMap, gridStyle)));
5532 GridArea& area = info->mArea;
5533 if (area.mCols.mUntranslatedStart != int32_t(kAutoLine)) {
5534 area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
5535 if (isColMasonry) {
5536 // XXXmats clamp any non-auto line to 0 or 1. This is intended to
5537 // allow authors to address the start/end of the masonry box.
5538 // This is experimental at this point though and needs author feedback
5539 // and spec work to sort out what is desired and how it should work.
5540 // See https://github.com/w3c/csswg-drafts/issues/4650
5541 area.mCols.mStart = std::min(area.mCols.mStart, 1U);
5542 }
5543 }
5544 if (area.mCols.mUntranslatedEnd != int32_t(kAutoLine)) {
5545 area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
5546 if (isColMasonry) {
5547 // ditto
5548 area.mCols.mEnd = std::min(area.mCols.mEnd, 1U);
5549 }
5550 }
5551 if (area.mRows.mUntranslatedStart != int32_t(kAutoLine)) {
5552 area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
5553 if (isRowMasonry) {
5554 // ditto
5555 area.mRows.mStart = std::min(area.mRows.mStart, 1U);
5556 }
5557 }
5558 if (area.mRows.mUntranslatedEnd != int32_t(kAutoLine)) {
5559 area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
5560 if (isRowMasonry) {
5561 // ditto
5562 area.mRows.mEnd = std::min(area.mRows.mEnd, 1U);
5563 }
5564 }
5565 if (isMasonry) {
5566 info->MaybeInhibitSubgridInMasonry(aGridRI.mFrame, gridAxisTrackCount);
5567 }
5568
5569 // An abs.pos. subgrid with placement auto/1 or -1/auto technically
5570 // doesn't span any parent tracks. Inhibit subgridding in this case.
5571 if (info->IsSubgrid(LogicalAxis::Inline)) {
5572 if (info->mArea.mCols.mStart == zeroOffsetGridColEnd.SavedValue() ||
5573 info->mArea.mCols.mEnd == 0) {
5574 info->InhibitSubgrid(aGridRI.mFrame, LogicalAxis::Inline);
5575 }
5576 }
5577 if (info->IsSubgrid(LogicalAxis::Block)) {
5578 if (info->mArea.mRows.mStart == zeroOffsetGridRowEnd.SavedValue() ||
5579 info->mArea.mRows.mEnd == 0) {
5580 info->InhibitSubgrid(aGridRI.mFrame, LogicalAxis::Block);
5581 }
5582 }
5583
5584 if (info->IsSubgrid()) {
5585 Grid grid(this);
5586 grid.SubgridPlaceGridItems(aGridRI, this, *info);
5587 }
5588 }
5589 }
5590
5591 // Count empty 'auto-fit' tracks in the repeat() range.
5592 // |colAdjust| will have a count for each line in the grid of how many
5593 // tracks were empty between the start of the grid and that line.
5594
5595 Maybe<nsTArray<uint32_t>> colAdjust;
5596 uint32_t numEmptyCols = 0;
5597 if (aGridRI.mColFunctions.mHasRepeatAuto &&
5598 gridStyle->mGridTemplateColumns.GetRepeatAutoValue()->count.IsAutoFit()) {
5599 const auto& cellMap = mCellMap;
5600 colAdjust = CalculateAdjustForAutoFitElements(
5601 &numEmptyCols, aGridRI.mColFunctions, mGridColEnd + 1,
5602 [&cellMap](uint32_t i) -> bool { return cellMap.IsEmptyCol(i); });
5603 }
5604
5605 // Do similar work for the row tracks, with the same logic.
5606 Maybe<nsTArray<uint32_t>> rowAdjust;
5607 uint32_t numEmptyRows = 0;
5608 if (aGridRI.mRowFunctions.mHasRepeatAuto &&
5609 gridStyle->mGridTemplateRows.GetRepeatAutoValue()->count.IsAutoFit()) {
5610 const auto& cellMap = mCellMap;
5611 rowAdjust = CalculateAdjustForAutoFitElements(
5612 &numEmptyRows, aGridRI.mRowFunctions, mGridRowEnd + 1,
5613 [&cellMap](uint32_t i) -> bool { return cellMap.IsEmptyRow(i); });
5614 }
5615 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", 5615)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(numEmptyCols > 0) == colAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5615); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5616 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", 5616)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(numEmptyRows > 0) == rowAdjust.isSome()"
")"); do { MOZ_CrashSequence(__null, 5616); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5617 // Remove the empty 'auto-fit' tracks we found above, if any.
5618 if (numEmptyCols || numEmptyRows) {
5619 // Adjust the line numbers in the grid areas.
5620 for (auto& item : aGridRI.mGridItems) {
5621 if (numEmptyCols) {
5622 item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
5623 }
5624 if (numEmptyRows) {
5625 item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
5626 }
5627 }
5628 for (auto& item : aGridRI.mAbsPosItems) {
5629 if (numEmptyCols) {
5630 item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
5631 }
5632 if (numEmptyRows) {
5633 item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
5634 }
5635 }
5636 // Adjust the grid size.
5637 mGridColEnd -= numEmptyCols;
5638 mExplicitGridColEnd -= numEmptyCols;
5639 mGridRowEnd -= numEmptyRows;
5640 mExplicitGridRowEnd -= numEmptyRows;
5641 // Adjust the track mapping to unmap the removed tracks.
5642 auto colRepeatCount = aGridRI.mColFunctions.NumRepeatTracks();
5643 aGridRI.mColFunctions.SetNumRepeatTracks(colRepeatCount - numEmptyCols);
5644 auto rowRepeatCount = aGridRI.mRowFunctions.NumRepeatTracks();
5645 aGridRI.mRowFunctions.SetNumRepeatTracks(rowRepeatCount - numEmptyRows);
5646 }
5647
5648 // Update the line boundaries of the implicit grid areas, if needed.
5649 if (mAreas && aGridRI.mFrame->HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO)) {
5650 for (auto iter = mAreas->iter(); !iter.done(); iter.next()) {
5651 auto& areaInfo = iter.get().value();
5652
5653 // Resolve the lines for the area. We use the name of the area as the
5654 // name of the lines, knowing that the line placement algorithm will
5655 // add the -start and -end suffixes as appropriate for layout.
5656 StyleGridLine lineStartAndEnd;
5657 lineStartAndEnd.ident._0 = areaInfo.name;
5658
5659 LineRange columnLines =
5660 ResolveLineRange(lineStartAndEnd, lineStartAndEnd, colLineNameMap,
5661 LogicalAxis::Inline, mExplicitGridColEnd, gridStyle);
5662
5663 LineRange rowLines =
5664 ResolveLineRange(lineStartAndEnd, lineStartAndEnd, rowLineNameMap,
5665 LogicalAxis::Block, mExplicitGridRowEnd, gridStyle);
5666
5667 // Put the resolved line indices back into the area structure.
5668 areaInfo.columns.start = columnLines.mStart + mExplicitGridOffsetCol;
5669 areaInfo.columns.end = columnLines.mEnd + mExplicitGridOffsetCol;
5670 areaInfo.rows.start = rowLines.mStart + mExplicitGridOffsetRow;
5671 areaInfo.rows.end = rowLines.mEnd + mExplicitGridOffsetRow;
5672 }
5673 }
5674}
5675
5676void nsGridContainerFrame::Tracks::Initialize(
5677 const TrackSizingFunctions& aFunctions,
5678 const NonNegativeLengthPercentageOrNormal& aGridGap, uint32_t aNumTracks,
5679 nscoord aContentBoxSize) {
5680 mSizes.SetLength(aNumTracks);
5681 mSizes.ZeroInitialize();
5682 for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
5683 auto& sz = mSizes[i];
5684 mStateUnion |= sz.Initialize(aContentBoxSize, aFunctions.SizingFor(i));
5685 if (mIsMasonry) {
5686 sz.mBase = aContentBoxSize;
5687 sz.mLimit = aContentBoxSize;
5688 }
5689 }
5690 mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize);
5691 mContentBoxSize = aContentBoxSize;
5692}
5693
5694/**
5695 * Reflow aChild in the given aAvailableSize.
5696 */
5697static nscoord MeasuringReflow(nsIFrame* aChild,
5698 const ReflowInput* aReflowInput, gfxContext* aRC,
5699 const LogicalSize& aAvailableSize,
5700 const LogicalSize& aCBSize,
5701 nscoord aIMinSizeClamp = NS_MAXSIZE,
5702 nscoord aBMinSizeClamp = NS_MAXSIZE) {
5703 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"
, 5703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsGridItem()"
") (" "aChild should be a grid item!" ")"); do { MOZ_CrashSequence
(__null, 5703); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5704 auto* parent = static_cast<nsGridContainerFrame*>(aChild->GetParent());
5705 nsPresContext* pc = aChild->PresContext();
5706 Maybe<ReflowInput> dummyParentState;
5707 const ReflowInput* rs = aReflowInput;
5708 if (!aReflowInput) {
5709 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", 5709)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW)"
")"); do { MOZ_CrashSequence(__null, 5709); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5710 dummyParentState.emplace(
5711 pc, parent, aRC,
5712 LogicalSize(parent->GetWritingMode(), 0, NS_UNCONSTRAINEDSIZE),
5713 ReflowInput::InitFlag::DummyParentReflowInput);
5714 rs = dummyParentState.ptr();
5715 }
5716#ifdef DEBUG1
5717 // This will suppress various ABSURD_SIZE warnings for this reflow.
5718 parent->SetProperty(nsContainerFrame::DebugReflowingWithInfiniteISize(),
5719 true);
5720#endif
5721 auto wm = aChild->GetWritingMode();
5722 ComputeSizeFlags csFlags = ComputeSizeFlag::IsGridMeasuringReflow;
5723 // Shrink-wrap grid items that will be aligned (rather than stretched) in
5724 // their own inline axis.
5725 if (!parent->GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
5726 csFlags += ComputeSizeFlag::ShrinkWrap;
5727 }
5728 if (aAvailableSize.ISize(wm) == INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60))) {
5729 csFlags += ComputeSizeFlag::ShrinkWrap;
5730 }
5731 if (aIMinSizeClamp != NS_MAXSIZE) {
5732 csFlags += ComputeSizeFlag::IClampMarginBoxMinSize;
5733 }
5734 if (aBMinSizeClamp != NS_MAXSIZE) {
5735 csFlags += ComputeSizeFlag::BClampMarginBoxMinSize;
5736 aChild->SetProperty(nsIFrame::BClampMarginBoxMinSizeProperty(),
5737 aBMinSizeClamp);
5738 } else {
5739 aChild->RemoveProperty(nsIFrame::BClampMarginBoxMinSizeProperty());
5740 }
5741 ReflowInput childRI(pc, *rs, aChild, aAvailableSize, Some(aCBSize), {}, {},
5742 csFlags);
5743
5744 // FIXME (perf): It would be faster to do this only if the previous reflow of
5745 // the child was not a measuring reflow, and only if the child does some of
5746 // the things that are affected by ComputeSizeFlag::IsGridMeasuringReflow.
5747 childRI.SetBResize(true);
5748 // Not 100% sure this is needed, but be conservative for now:
5749 childRI.SetBResizeForPercentages(true);
5750
5751 ReflowOutput childSize(childRI);
5752 nsReflowStatus childStatus;
5753 const nsIFrame::ReflowChildFlags flags =
5754 nsIFrame::ReflowChildFlags::NoMoveFrame |
5755 nsIFrame::ReflowChildFlags::NoDeleteNextInFlowChild;
5756
5757 // Reflowing the child might invalidate the cache, so we declare the variable
5758 // inside the if-statement to ensure it isn't accessed after it may have
5759 // become invalid.
5760 if (const GridItemCachedBAxisMeasurement* cachedMeasurement =
5761 aChild->GetProperty(GridItemCachedBAxisMeasurement::Prop());
5762 cachedMeasurement && cachedMeasurement->IsValidFor(aChild, aCBSize)) {
5763 childSize.BSize(wm) = cachedMeasurement->BSize();
5764 childSize.ISize(wm) = aChild->ISize(wm);
5765 nsContainerFrame::FinishReflowChild(aChild, pc, childSize, &childRI, wm,
5766 LogicalPoint(wm), nsSize(), flags);
5767 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->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
5768 "[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->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
5769 "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->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
5770 cachedMeasurement->BSize(), 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->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
;
5771 return cachedMeasurement->BSize();
5772 }
5773
5774 parent->ReflowChild(aChild, pc, childSize, childRI, wm, LogicalPoint(wm),
5775 nsSize(), flags, childStatus);
5776 nsContainerFrame::FinishReflowChild(aChild, pc, childSize, &childRI, wm,
5777 LogicalPoint(wm), nsSize(), flags);
5778#ifdef DEBUG1
5779 parent->RemoveProperty(nsContainerFrame::DebugReflowingWithInfiniteISize());
5780#endif
5781
5782 if (GridItemCachedBAxisMeasurement* cachedMeasurement =
5783 aChild->GetProperty(GridItemCachedBAxisMeasurement::Prop())) {
5784 cachedMeasurement->Update(aChild, aCBSize, childSize.BSize(wm));
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", cachedMeasurement->BSize(),
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", cachedMeasurement->BSize(),
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", cachedMeasurement->BSize(),
aChild, aCBSize.ISize(wm)); } } while (0);
5788 cachedMeasurement->BSize(), 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", cachedMeasurement->BSize(),
aChild, aCBSize.ISize(wm)); } } while (0);
;
5789 } else {
5790 cachedMeasurement = new GridItemCachedBAxisMeasurement(aChild, aCBSize,
5791 childSize.BSize(wm));
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", cachedMeasurement->BSize(), 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", cachedMeasurement->BSize(), 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", cachedMeasurement->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
5797 cachedMeasurement->BSize(), 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", cachedMeasurement->BSize(), aChild, aCBSize
.ISize(wm)); } } while (0);
;
5798 }
5799
5800 return childSize.BSize(wm);
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 nscoord size = nsLayoutUtils::IntrinsicForAxis(
5920 axis, rc, child, aConstraint, Some(aPercentageBasis),
5921 nsLayoutUtils::BAIL_IF_REFLOW_NEEDED, aMinSizeClamp, aOverrides);
5922 auto childWM = child->GetWritingMode();
5923 const bool isOrthogonal = childWM.IsOrthogonalTo(gridWM);
5924 auto childAxis = isOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
5925 if (size == NS_INTRINSIC_ISIZE_UNKNOWN && childAxis == LogicalAxis::Block) {
5926 if (aGridRI.mIsGridIntrinsicSizing && aAxis == LogicalAxis::Block) {
5927 // We may reach here while computing the grid container's min-content
5928 // contribution in ComputeIntrinsicISize(), potentially during row size
5929 // resolution. In this context, the main reason for computing row sizes is
5930 // to transfer the child's block-size to the inline-axis via aspect-ratio,
5931 // contributing to the grid container's intrinsic inline-size in a later
5932 // column size resolution. Since an indefinite block-size cannot be
5933 // transferred in this way, we can safely skip MeasuringReflow() and
5934 // simply use zero as a dummy value because the value does not affect the
5935 // result.
5936 size = 0;
5937 } else {
5938 // We need to reflow the child to find its BSize contribution.
5939 nscoord availISize = INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60));
5940 nscoord availBSize = NS_UNCONSTRAINEDSIZE;
5941 // The next two variables are MinSizeClamp values in the child's axes.
5942 nscoord iMinSizeClamp = NS_MAXSIZE;
5943 nscoord bMinSizeClamp = NS_MAXSIZE;
5944 LogicalSize cbSize = aPercentageBasis;
5945 // Below, we try to resolve the child's grid-area size in its inline-axis
5946 // to use as the CB/Available size in the MeasuringReflow that follows.
5947 if (child->GetParent() != aGridRI.mFrame) {
5948 // This item is a child of a subgrid descendant.
5949 auto* subgridFrame =
5950 static_cast<nsGridContainerFrame*>(child->GetParent());
5951 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", 5951)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgridFrame->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 5951); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5952 auto* uts =
5953 subgridFrame->GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
5954 // The grid-item's inline-axis as expressed in the subgrid's WM.
5955 const auto subgridAxis = childWM.ConvertAxisTo(
5956 LogicalAxis::Inline, subgridFrame->GetWritingMode());
5957 uts->ResolveTrackSizesForAxis(subgridFrame, subgridAxis, *rc);
5958 if (uts->mCanResolveLineRangeSize[subgridAxis]) {
5959 auto* subgrid =
5960 subgridFrame->GetProperty(nsGridContainerFrame::Subgrid::Prop());
5961 const GridItemInfo* originalItem = nullptr;
5962 for (const auto& item : subgrid->mGridItems) {
5963 if (item.mFrame == child) {
5964 originalItem = &item;
5965 break;
5966 }
5967 }
5968 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"
, 5968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "originalItem"
") (" "huh?" ")"); do { MOZ_CrashSequence(__null, 5968); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5969 const auto& range = originalItem->mArea.LineRangeForAxis(subgridAxis);
5970 const nscoord sz = range.ToLength(uts->mTrackPlans[subgridAxis]);
5971 if (childWM.IsOrthogonalTo(subgridFrame->GetWritingMode())) {
5972 availBSize = sz;
5973 cbSize.BSize(childWM) = sz;
5974 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
5975 bMinSizeClamp = sz;
5976 }
5977 } else {
5978 availISize = sz;
5979 cbSize.ISize(childWM) = sz;
5980 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
5981 iMinSizeClamp = sz;
5982 }
5983 }
5984 }
5985 } else {
5986 const LogicalAxis inlineAxisInChildWM =
5987 isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
5988 const nscoord colSize = cbSize.Size(inlineAxisInChildWM, childWM);
5989 if (colSize != NS_UNCONSTRAINEDSIZE) {
5990 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"
, 5991); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mCols.mCanResolveLineRangeSize"
") (" "Grid column sizes should be resolvable!" ")"); do { MOZ_CrashSequence
(__null, 5991); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5991 "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"
, 5991); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mCols.mCanResolveLineRangeSize"
") (" "Grid column sizes should be resolvable!" ")"); do { MOZ_CrashSequence
(__null, 5991); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5992 if (isOrthogonal) {
5993 availBSize = colSize;
5994 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
5995 bMinSizeClamp = colSize;
5996 }
5997 } else {
5998 availISize = colSize;
5999 if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
6000 iMinSizeClamp = colSize;
6001 }
6002 }
6003 }
6004 }
6005 if (isOrthogonal == (aAxis == LogicalAxis::Inline)) {
6006 bMinSizeClamp = aMinSizeClamp;
6007 } else {
6008 iMinSizeClamp = aMinSizeClamp;
6009 }
6010 LogicalSize availableSize(childWM, availISize, availBSize);
6011 size = ::MeasuringReflow(child, aGridRI.mReflowInput, rc, availableSize,
6012 cbSize, iMinSizeClamp, bMinSizeClamp);
6013 }
6014 size += child->GetLogicalUsedMargin(childWM).BStartEnd(childWM);
6015 nscoord overflow = size - aMinSizeClamp;
6016 if (MOZ_UNLIKELY(overflow > 0)(__builtin_expect(!!(overflow > 0), 0))) {
6017 nscoord contentSize = child->ContentBSize(childWM);
6018 nscoord newContentSize = std::max(nscoord(0), contentSize - overflow);
6019 // XXXmats deal with percentages better, see bug 1300369 comment 27.
6020 size -= contentSize - newContentSize;
6021 }
6022 }
6023 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", 6024)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6024 "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", 6024)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6025 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", 6027
); 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, 6027); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6026 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", 6027
); 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, 6027); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6027 "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", 6027
); 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, 6027); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6028 size += aGridItem.mBaselineOffset[aAxis];
6029 size += extraMargin;
6030 return std::max(size, 0);
6031}
6032
6033struct CachedIntrinsicSizes {
6034 CachedIntrinsicSizes() = delete;
6035 CachedIntrinsicSizes(const GridItemInfo& aGridItem,
6036 const GridReflowInput& aGridRI, const LogicalAxis aAxis)
6037 : mPercentageBasis(aGridRI.PercentageBasisFor(aAxis, aGridItem)) {}
6038
6039 void EnsureContributions(EnumSet<GridIntrinsicSizeType> aTypes,
6040 const GridItemInfo& aGridItem,
6041 const GridReflowInput& aGridRI, LogicalAxis aAxis) {
6042 // max-content and min-content should behave as initial value in block axis.
6043 // XXXalaskanemily: The specifics might have changed in the spec?
6044 // https://drafts.csswg.org/css-sizing-3/#valdef-width-min-content
6045 // https://drafts.csswg.org/css-sizing-3/#valdef-width-max-content
6046
6047 // If we need to calculate GridIntrinsicSizeType::MinContribution, we might
6048 // need to substitute GridIntrinsicSizeType::MinContentContribution instead.
6049 // Per https://drafts.csswg.org/css-grid-2/#algo-single-span-items
6050 // Section "For auto minimums":
6051 // * "if the item's computed preferred size behaves as auto or depends on
6052 // the size of its containing block in the relevant axis," then we do in
6053 // fact need the used minimum size."
6054 // * "...else the item's minimum contribution is its min-content
6055 // contribution" in which case we make a recursive call to compute
6056 // GridIntrinsicSizeType::MinContentContribution instead, and do a fixup
6057 // to place that value in the MinContentContribution slot.
6058 // Note that we use BehavesLikeInitialValue and HasPercent to implement
6059 // the spec check for "behaves as auto or depends on the size of its
6060 // containing block".
6061 // We make a similar check in MinContributionDependsOnAutoMinSize as
6062 // an earlier test for whether we need the used minimum size.
6063 if (aTypes.contains(GridIntrinsicSizeType::MinContribution)) {
6064 nsIFrame* const child = aGridItem.mFrame;
6065 const nsStylePosition* const stylePos = child->StylePosition();
6066 const auto anchorResolutionParams =
6067 AnchorPosResolutionParams::From(child);
6068 const WritingMode cbwm = aGridRI.mWM;
6069 auto styleSize = stylePos->Size(aAxis, cbwm, anchorResolutionParams);
6070 const LogicalAxis axisInItemWM =
6071 cbwm.ConvertAxisTo(aAxis, child->GetWritingMode());
6072 // FIXME: Bug 567039: moz-fit-content and -moz-available are not
6073 // supported for block size dimension on sizing properties (e.g. height),
6074 // so we treat it as `auto`.
6075 if (!styleSize->BehavesLikeInitialValue(axisInItemWM) &&
6076 !styleSize->HasPercent()) {
6077 // Calculate without MinSize, but ensuring MinContentContribution.
6078 aTypes -= GridIntrinsicSizeType::MinContribution;
6079 aTypes += GridIntrinsicSizeType::MinContentContribution;
6080 EnsureContributions(aTypes, aGridItem, aGridRI, aAxis);
6081 // Copy the MinSize from the MinContentContribution.
6082 mSizes[GridIntrinsicSizeType::MinContribution] =
6083 mSizes[GridIntrinsicSizeType::MinContentContribution];
6084 return;
6085 }
6086 }
6087
6088 for (const GridIntrinsicSizeType type : aTypes) {
6089 if (mSizes[type].isNothing()) {
6090 mSizes[type].emplace(ComputeContribution(
6091 type, aGridItem, aGridRI, aAxis, mPercentageBasis, mMinSizeClamp));
6092 }
6093 }
6094 }
6095
6096 private:
6097 // Computes the MinSize, MinContentContribution, or MaxContentContribution of
6098 // an item in the given axis.
6099 // This helps to implement EnsureContributions. It's here to prevent other
6100 // places from using it, as it is not general purpose and requires that the
6101 // caller has made checks for when we will use the MinContentContribution as
6102 // the MinSize, as EnsureContributions does.
6103 static nscoord ComputeContribution(GridIntrinsicSizeType aType,
6104 const GridItemInfo& aGridItem,
6105 const GridReflowInput& aGridRI,
6106 LogicalAxis aAxis,
6107 const LogicalSize& aPercentageBasis,
6108 nscoord aMinSizeClamp) {
6109 const WritingMode containerWM = aGridRI.mWM;
6110 gfxContext* const rc = &aGridRI.mRenderingContext;
6111 switch (aType) {
6112 case GridIntrinsicSizeType::MinContentContribution:
6113 return ContentContribution(aGridItem, aGridRI, aAxis, aPercentageBasis,
6114 IntrinsicISizeType::MinISize, aMinSizeClamp);
6115 case GridIntrinsicSizeType::MaxContentContribution:
6116 return ContentContribution(aGridItem, aGridRI, aAxis, aPercentageBasis,
6117 IntrinsicISizeType::PrefISize,
6118 aMinSizeClamp);
6119 case GridIntrinsicSizeType::MinContribution: {
6120 // Compute the min-size contribution for a grid item, as defined at
6121 // https://drafts.csswg.org/css-grid-2/#min-size-contribution
6122 nsIFrame* const child = aGridItem.mFrame;
6123 const nsStylePosition* const stylePos = child->StylePosition();
6124 const auto anchorResolutionParams =
6125 AnchorPosResolutionParams::From(child);
6126 const LogicalAxis axisInItemWM =
6127 containerWM.ConvertAxisTo(aAxis, child->GetWritingMode());
6128#ifdef DEBUG1
6129 // The caller must handle this case separately.
6130 // See EnsureContributions.
6131 {
6132 const auto styleSize =
6133 stylePos->Size(aAxis, containerWM, anchorResolutionParams);
6134 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"
, 6136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6136); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6135 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"
, 6136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6136); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6136 "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"
, 6136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "styleSize->BehavesLikeInitialValue(axisInItemWM) || styleSize->HasPercent()"
") (" "Should have been caught in EnsureContributions" ")");
do { MOZ_CrashSequence(__null, 6136); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6137 }
6138#endif
6139 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6140 // This calculates the min-content contribution from either a definite
6141 // min-width (or min-height depending on aAxis), or the
6142 // "specified / transferred size" for min-width:auto if
6143 // overflow == visible (as min-width:0 otherwise), or
6144 // NS_UNCONSTRAINEDSIZE for other min-width intrinsic values
6145 // (which results in always taking the "content size" part below).
6146 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", 6147)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6147); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6147 "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", 6147)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItem.mBaselineOffset[aAxis] >= 0"
") (" "baseline offset should be non-negative at this point"
")"); do { MOZ_CrashSequence(__null, 6147); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6148 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", 6150
); 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, 6150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6149 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", 6150
); 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, 6150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6150 "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", 6150
); 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, 6150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6151 const auto styleMinSize =
6152 stylePos->MinSize(aAxis, containerWM, anchorResolutionParams);
6153
6154 // max-content and min-content should behave as initial value in block
6155 // axis.
6156 // FIXME: Bug 567039: moz-fit-content and -moz-available are not
6157 // supported for block size dimension on sizing properties
6158 // (e.g. height), so we treat it as `auto`.
6159 const bool isAuto = styleMinSize->BehavesLikeInitialValue(axisInItemWM);
6160 nscoord s = aGridItem.mBaselineOffset[aAxis];
6161
6162 // Check if the min-size style of the grid item is auto and the
6163 // minimum contribution is content-based.
6164 // While the eContentBasedAutoMinSize flag is not synonymous with
6165 // an item having content-based automatic minimum contribution,
6166 // the previous checks should catch the other cases in which the
6167 // automatic minimum contribution is zero instead.
6168 //
6169 // See bug 1951821 for this discrepency between the flag's usage
6170 // and the specification:
6171 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6172 if (!isAuto ||
6173 (aGridItem.mState[aAxis] & ItemState::eContentBasedAutoMinSize)) {
6174 nscoord contrib = nsLayoutUtils::MinSizeContributionForAxis(
6175 containerWM.PhysicalAxis(aAxis), rc, child,
6176 IntrinsicISizeType::MinISize, aPercentageBasis);
6177 if (contrib == NS_UNCONSTRAINEDSIZE) {
6178 s = contrib;
6179 } else {
6180 s += contrib;
6181 }
6182
6183 if ((axisInItemWM == LogicalAxis::Inline &&
6184 nsIFrame::ToExtremumLength(*styleMinSize)) ||
6185 (isAuto && !child->StyleDisplay()->IsScrollableOverflow())) {
6186 // "if the item's computed preferred size behaves as auto or
6187 // depends on the size of its containing block in the relevant
6188 // axis, its minimum contribution is the outer size that would
6189 // result from assuming the item's used minimum size as its
6190 // preferred size"
6191 //
6192 // The "auto or depends on the size of its containing block" is
6193 // checked above with ItemState::eContentBasedAutoMinSize.
6194 //
6195 // https://drafts.csswg.org/css-grid-2/#minimum-contribution
6196 StyleSizeOverrides overrides;
6197 if (axisInItemWM == LogicalAxis::Inline) {
6198 overrides.mStyleISize.emplace(*styleMinSize.get());
6199 } else {
6200 overrides.mStyleBSize.emplace(*styleMinSize.get());
6201 }
6202 // Now calculate the "content size" part and return whichever is
6203 // smaller.
6204 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"
, 6204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isAuto || s == NS_UNCONSTRAINEDSIZE"
")"); do { MOZ_CrashSequence(__null, 6204); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6205 s = std::min(s, ContentContribution(aGridItem, aGridRI, aAxis,
6206 aPercentageBasis,
6207 IntrinsicISizeType::MinISize,
6208 aMinSizeClamp, overrides));
6209 }
6210 }
6211 return s;
6212 }
6213 }
6214 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"
, 6214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected contribution type" ")"
); do { MOZ_CrashSequence(__null, 6214); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); __builtin_unreachable
(); } while (false)
;
6215 }
6216
6217 public:
6218 EnumeratedArray<GridIntrinsicSizeType, nscoord> SizesOrDefault() const {
6219 EnumeratedArray<GridIntrinsicSizeType, nscoord> sizes;
6220 for (GridIntrinsicSizeType type : kAllGridIntrinsicSizeTypes) {
6221 sizes[type] = mSizes[type].valueOr(0);
6222 }
6223 return sizes;
6224 }
6225
6226 EnumeratedArray<GridIntrinsicSizeType, Maybe<nscoord>> mSizes;
6227
6228 // The item's percentage basis for intrinsic sizing purposes.
6229 const LogicalSize mPercentageBasis;
6230
6231 // "if the grid item spans only grid tracks that have a fixed max track
6232 // sizing function, its automatic minimum size in that dimension is
6233 // further clamped to less than or equal to the size necessary to fit its
6234 // margin box within the resulting grid area (flooring at zero)"
6235 // https://drafts.csswg.org/css-grid-2/#min-size-auto
6236 // This is the clamp value to use for that:
6237 nscoord mMinSizeClamp = NS_MAXSIZE;
6238};
6239
6240void nsGridContainerFrame::Tracks::CalculateSizes(
6241 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
6242 const TrackSizingFunctions& aFunctions, nscoord aContentBoxSize,
6243 LineRange GridArea::* aRange, SizingConstraint aConstraint) {
6244 // Implement the intrinsic sizing algorithm, step 12.5 as described in:
6245 // https://drafts.csswg.org/css-grid-2/#algo-content
6246 nscoord percentageBasis = aContentBoxSize;
6247 if (percentageBasis == NS_UNCONSTRAINEDSIZE) {
6248 percentageBasis = 0;
6249 }
6250 // 12.5 step 1: Shim baseline-aligned items so their intrinsic size
6251 // contributions reflect their baseline alignment
6252 // https://drafts.csswg.org/css-grid-2/#algo-baseline-shims
6253 InitializeItemBaselines(aGridRI, aGridItems);
6254
6255 // 12.5 steps 2-5
6256 ResolveIntrinsicSize(aGridRI, aGridItems, aFunctions, aRange, percentageBasis,
6257 aConstraint);
6258
6259 // Neither 12.6 nor 12.7 will occur under min content constraint.
6260 if (aConstraint != SizingConstraint::MinContent) {
6261 nscoord freeSpace = aContentBoxSize;
6262 if (freeSpace != NS_UNCONSTRAINEDSIZE) {
6263 freeSpace -= SumOfGridGaps();
6264 }
6265 // 12.6 maximize tracks by distributing free space.
6266 // https://drafts.csswg.org/css-grid-2/#algo-grow-tracks
6267 DistributeFreeSpace(freeSpace);
6268
6269 // 12.7 Expand flexible tracks.
6270 // https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
6271 StretchFlexibleTracks(aGridRI, aGridItems, aFunctions, freeSpace);
6272 }
6273}
6274
6275TrackSize::StateBits nsGridContainerFrame::Tracks::StateBitsForRange(
6276 const LineRange& aRange) const {
6277 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"
, 6277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aRange.IsAuto()"
") (" "must have a definite range" ")"); do { MOZ_CrashSequence
(__null, 6277); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6278 TrackSize::StateBits state = TrackSize::StateBits::eNone;
6279 for (auto i : aRange.Range()) {
6280 state |= mSizes[i].mState;
6281 }
6282 return state;
6283}
6284
6285static void AddSubgridContribution(TrackSize& aSize,
6286 nscoord aMarginBorderPadding) {
6287 if (aSize.mState & TrackSize::eIntrinsicMinSizing) {
6288 aSize.mBase = std::max(aSize.mBase, aMarginBorderPadding);
6289 aSize.mLimit = std::max(aSize.mLimit, aSize.mBase);
6290 }
6291 // XXX maybe eFlexMaxSizing too?
6292 // (once we implement https://github.com/w3c/csswg-drafts/issues/2177)
6293 if (aSize.mState &
6294 (TrackSize::eIntrinsicMaxSizing | TrackSize::eApplyFitContentClamping)) {
6295 aSize.mLimit = std::max(aSize.mLimit, aMarginBorderPadding);
6296 }
6297}
6298
6299Maybe<nscoord> nsGridContainerFrame::Tracks::ComputeMinSizeClamp(
6300 const TrackSizingFunctions& aFunctions, nscoord aPercentageBasis,
6301 const LineRange& aLineRange, const TrackSize::StateBits aState) const {
6302 if (!TrackSize::IsDefiniteMaxSizing(aState)) {
6303 return Nothing();
6304 }
6305 nscoord minSizeClamp = 0;
6306 for (auto i : aLineRange.Range()) {
6307 minSizeClamp +=
6308 aFunctions.MaxSizingFor(i).AsBreadth().Resolve(aPercentageBasis);
6309 }
6310 minSizeClamp += mGridGap * (aLineRange.Extent() - 1);
6311 return Some(minSizeClamp);
6312}
6313
6314void nsGridContainerFrame::Tracks::ResolveIntrinsicSizeForNonSpanningItems(
6315 GridReflowInput& aGridRI, const TrackSizingFunctions& aFunctions,
6316 nscoord aPercentageBasis, SizingConstraint aConstraint,
6317 const LineRange& aRange, const GridItemInfo& aGridItem) {
6318 // Calculate track sizes for fit non-spanning items.
6319 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
6320 CachedIntrinsicSizes cache{aGridItem, aGridRI, mAxis};
6321 TrackSize& sz = mSizes[aRange.mStart];
6322
6323 // Contribution type to use as the base size.
6324 // This is a Maybe as we might not need to calculate a contribution at all,
6325 // for instance if the base sizing function is a definite length.
6326 Maybe<GridIntrinsicSizeType> baseSizeType;
6327 if (sz.mState & TrackSize::eAutoMinSizing) {
6328 // "For auto minimums:"
6329 // "If the track has an 'auto' min track sizing function and the grid
6330 // container is being sized under a min-/max-content constraint, set
6331 // the track's base size to the maximum of its items' limited
6332 // min-content contributions"
6333 if (aGridItem.MinContributionDependsOnAutoMinSize(aGridRI.mWM, mAxis)) {
6334 // Clamp it if it's spanning a definite track max-sizing function.
6335 if (const Maybe<nscoord> minSizeClamp =
6336 ComputeMinSizeClamp(aFunctions, aPercentageBasis, aRange)) {
6337 cache.mMinSizeClamp = *minSizeClamp;
6338 aGridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
6339 }
6340 // Use the content-based contribution.
6341 baseSizeType.emplace((aConstraint == SizingConstraint::MaxContent)
6342 ? GridIntrinsicSizeType::MaxContentContribution
6343 : GridIntrinsicSizeType::MinContentContribution);
6344 } else {
6345 // Use the minimum contribution.
6346 // Note that this could still become MinContentContribution in practice.
6347 // MinContributionDependsOnAutoMinSize can return false when the item's
6348 // size depends on the size of its containing block. In that case, using
6349 // EnsureContributions to compute MinSize will instead compute
6350 // MinContentContribution, which will then be placed in the MinSize
6351 // slot on the cache.
6352 baseSizeType.emplace(GridIntrinsicSizeType::MinContribution);
6353 }
6354 } else if (sz.mState & TrackSize::eMinContentMinSizing) {
6355 // "For min-content minimums:"
6356 // "If the track has a 'min-content' min track sizing function, set its
6357 // base size to the maximum of the items' min-content contributions"
6358 baseSizeType.emplace(GridIntrinsicSizeType::MinContentContribution);
6359 } else if (sz.mState & TrackSize::eMaxContentMinSizing) {
6360 // "For max-content minimums:"
6361 // "If the track has a 'max-content' min track sizing function, set its
6362 // base size to the maximum of the items' max-content contributions"
6363 baseSizeType.emplace(GridIntrinsicSizeType::MaxContentContribution);
6364 }
6365
6366 // Size of fit-content maximum, if any.
6367 Maybe<nscoord> fitContentClamp;
6368 // Contribution type to use as the growth limit.
6369 // This is a Maybe as we might not need to calculate a contribution at all,
6370 // for instance if the growth limit sizing function is a definite length.
6371 Maybe<GridIntrinsicSizeType> limitType;
6372 if (sz.mState & TrackSize::eMinContentMaxSizing) {
6373 // "For min-content maximums:"
6374 // "If the track has a 'min-content' max track sizing function, set its
6375 // growth limit to the maximum of the items' min-content contributions"
6376 limitType.emplace(GridIntrinsicSizeType::MinContentContribution);
6377 } else if (sz.mState &
6378 (TrackSize::eAutoMaxSizing | TrackSize::eMaxContentMaxSizing)) {
6379 // "For max-content maximums:"
6380 // "If the track has a 'max-content' max track sizing function, set its
6381 // growth limit to the maximum of the items' max-content contributions"
6382 limitType.emplace(GridIntrinsicSizeType::MaxContentContribution);
6383 if (MOZ_UNLIKELY(sz.mState & TrackSize::eApplyFitContentClamping)(__builtin_expect(!!(sz.mState & TrackSize::eApplyFitContentClamping
), 0))
) {
6384 // "For fit-content() maximums, furthermore clamp this growth limit by
6385 // the fit-content() argument."
6386 fitContentClamp.emplace(aFunctions.SizingFor(aRange.mStart)
6387 .AsFitContent()
6388 .AsBreadth()
6389 .Resolve(aPercentageBasis));
6390 }
6391 }
6392
6393 // Even if it was possible to use the minimum contribution as the limit in
6394 // the spec, this could get trashed by the checks for whether the item's auto
6395 // minimum size depends on the size implemented in
6396 // GridItemInfo::MinContributionDependsOnAutoMinSize and
6397 // CachedIntrinsicSizes::EnsureContributions.
6398 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", 6400
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6399 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", 6400
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6400 "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", 6400
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "limitType != Some(GridIntrinsicSizeType::MinContribution)"
") (" "We should never be using the minimum contribution as the limit size."
")"); do { MOZ_CrashSequence(__null, 6400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6401
6402 // Accumulate the required size types and compute the contributions.
6403 {
6404 EnumSet<GridIntrinsicSizeType> sizeTypesToCalculate;
6405 for (const auto& maybeType : {baseSizeType, limitType}) {
6406 if (maybeType) {
6407 sizeTypesToCalculate += *maybeType;
6408 }
6409 }
6410 cache.EnsureContributions(sizeTypesToCalculate, aGridItem, aGridRI, mAxis);
6411 }
6412
6413 if (baseSizeType) {
6414 sz.mBase = std::max(sz.mBase, *cache.mSizes[*baseSizeType]);
6415 }
6416
6417 // Limit based on max size type.
6418 if (limitType) {
6419 if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
6420 sz.mLimit = 0; // Use only the contribution instead.
6421 }
6422 sz.mLimit = std::max(sz.mLimit, *cache.mSizes[*limitType]);
6423 if (fitContentClamp) {
6424 // "furthermore clamp this growth limit by the fit-content() argument."
6425 sz.mLimit = std::min(sz.mLimit, *fitContentClamp);
6426 }
6427 }
6428
6429 // "In all cases, if a track's growth limit is now less than its base size,
6430 // increase the growth limit to match the base size."
6431 sz.mLimit = std::max(sz.mLimit, sz.mBase);
6432}
6433
6434void nsGridContainerFrame::Tracks::CalculateItemBaselines(
6435 nsTArray<ItemBaselineData>& aBaselineItems,
6436 BaselineSharingGroup aBaselineGroup) {
6437 if (aBaselineItems.IsEmpty()) {
6438 return;
6439 }
6440
6441 // Sort the collected items on their baseline track.
6442 std::sort(aBaselineItems.begin(), aBaselineItems.end(),
6443 ItemBaselineData::IsBaselineTrackLessThan);
6444
6445 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"
, 6445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSizes.Length() > 0"
") (" "having an item implies at least one track" ")"); do {
MOZ_CrashSequence(__null, 6445); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6446
6447 // Make sure we have enough space to store the baselines. Use the highest
6448 // track number (+1 to account for the 0 based indexing).
6449 auto baselineCount = aBaselineItems.LastElement().mBaselineTrack + 1;
6450 mBaselines.EnsureLengthAtLeast(baselineCount);
6451
6452 nscoord maxBaseline = 0;
6453 nscoord maxDescent = 0;
6454 uint32_t currentTrack = kAutoLine; // guaranteed to not match any item
6455 uint32_t trackStartIndex = 0;
6456 for (uint32_t i = 0, len = aBaselineItems.Length(); true; ++i) {
6457 // Find the maximum baseline and descent in the current track.
6458 if (i != len) {
6459 const ItemBaselineData& item = aBaselineItems[i];
6460 if (currentTrack == item.mBaselineTrack) {
6461 maxBaseline = std::max(maxBaseline, item.mBaseline);
6462 maxDescent = std::max(maxDescent, item.mSize - item.mBaseline);
6463 continue;
6464 }
6465 }
6466 // Iterate the current track again and update the baseline offsets making
6467 // all items baseline-aligned within this group in this track.
6468 for (uint32_t j = trackStartIndex; j < i; ++j) {
6469 const ItemBaselineData& item = aBaselineItems[j];
6470 item.mGridItem->mBaselineOffset[mAxis] = maxBaseline - item.mBaseline;
6471 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", 6471)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mGridItem->mBaselineOffset[mAxis] >= 0"
")"); do { MOZ_CrashSequence(__null, 6471); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6472 }
6473 if (i != 0) {
6474 // Store the size of this baseline-aligned subtree.
6475 mSizes[currentTrack].mBaselineSubtreeSize[aBaselineGroup] =
6476 maxBaseline + maxDescent;
6477
6478 // Record the baseline for the current track.
6479 mBaselines[currentTrack][aBaselineGroup] = Some(maxBaseline);
6480 }
6481 if (i == len) {
6482 break;
6483 }
6484 // Initialize data for the next track with baseline-aligned items.
6485 const ItemBaselineData& item = aBaselineItems[i];
6486 currentTrack = item.mBaselineTrack;
6487 trackStartIndex = i;
6488 maxBaseline = item.mBaseline;
6489 maxDescent = item.mSize - item.mBaseline;
6490 }
6491}
6492
6493void nsGridContainerFrame::Tracks::InitializeItemBaselines(
6494 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems) {
6495 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"
, 6495); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mIsMasonry"
")"); do { MOZ_CrashSequence(__null, 6495); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6496 if (aGridRI.mFrame->IsSubgrid(mAxis)) {
6497 // A grid container's subgridded axis doesn't have a baseline.
6498 return;
6499 }
6500
6501 nsTArray<ItemBaselineData> firstBaselineItems;
6502 nsTArray<ItemBaselineData> lastBaselineItems;
6503 const WritingMode containerWM = aGridRI.mWM;
6504 ComputedStyle* containerStyle = aGridRI.mFrame->Style();
6505
6506 for (GridItemInfo& gridItem : aGridItems) {
6507 if (gridItem.IsSubgrid(mAxis)) {
6508 // A subgrid itself is never baseline-aligned.
6509 continue;
6510 }
6511
6512 nsIFrame* child = gridItem.mFrame;
6513 uint32_t baselineTrack = kAutoLine;
6514 auto state = ItemState(0);
6515 const auto childWM = child->GetWritingMode();
6516
6517 const bool isOrthogonal = containerWM.IsOrthogonalTo(childWM);
6518 const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
6519 const bool itemHasBaselineParallelToTrack = isInlineAxis == isOrthogonal;
6520
6521 // [align|justify]-self:[last ]baseline.
6522 auto selfAlignment =
6523 child->StylePosition()->UsedSelfAlignment(mAxis, containerStyle);
6524 selfAlignment &= ~StyleAlignFlags::FLAG_BITS;
6525 if (selfAlignment == StyleAlignFlags::BASELINE) {
6526 state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
6527 } else if (selfAlignment == StyleAlignFlags::LAST_BASELINE) {
6528 state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
6529 }
6530
6531 // https://drafts.csswg.org/css-align-3/#baseline-align-content
6532 // Baseline content-alignment can only apply if the align-content axis is
6533 // parallel with the box’s block axis; otherwise the fallback alignment is
6534 // used.
6535 if (!isInlineAxis) {
6536 // Handle align-content:[last ]baseline (if present)
6537 auto alignContent = child->StylePosition()->mAlignContent.primary;
6538 alignContent &= ~StyleAlignFlags::FLAG_BITS;
6539 if (alignContent == StyleAlignFlags::BASELINE ||
6540 alignContent == StyleAlignFlags::LAST_BASELINE) {
6541 const auto selfAlignEdge = alignContent == StyleAlignFlags::BASELINE
6542 ? StyleAlignFlags::SELF_START
6543 : StyleAlignFlags::SELF_END;
6544 bool validCombo = selfAlignment == StyleAlignFlags::NORMAL ||
6545 selfAlignment == StyleAlignFlags::STRETCH ||
6546 selfAlignment == selfAlignEdge;
6547 if (!validCombo) {
6548 // We're doing alignment in the axis that's orthogonal to mAxis here.
6549 LogicalAxis alignAxis = GetOrthogonalAxis(mAxis);
6550 // |sameSide| is true if the container's start side in this axis is
6551 // the same as the child's start side, in the child's parallel axis.
6552 bool sameSide =
6553 containerWM.ParallelAxisStartsOnSameSide(alignAxis, childWM);
6554 if (selfAlignment == StyleAlignFlags::LEFT) {
6555 selfAlignment = containerWM.IsBidiLTR() ? StyleAlignFlags::START
6556 : StyleAlignFlags::END;
6557 } else if (selfAlignment == StyleAlignFlags::RIGHT) {
6558 selfAlignment = StyleAlignFlags::START;
6559 }
6560
6561 if (selfAlignment == StyleAlignFlags::START ||
6562 selfAlignment == StyleAlignFlags::FLEX_START) {
6563 validCombo =
6564 sameSide == (alignContent == StyleAlignFlags::BASELINE);
6565 } else if (selfAlignment == StyleAlignFlags::END ||
6566 selfAlignment == StyleAlignFlags::FLEX_END) {
6567 validCombo =
6568 sameSide == (alignContent == StyleAlignFlags::LAST_BASELINE);
6569 }
6570 }
6571 if (validCombo) {
6572 const GridArea& area = gridItem.mArea;
6573 if (alignContent == StyleAlignFlags::BASELINE) {
6574 state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
6575 baselineTrack = area.mRows.mStart;
Value stored to 'baselineTrack' is never read
6576 } else if (alignContent == StyleAlignFlags::LAST_BASELINE) {
6577 state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
6578 baselineTrack = area.mRows.mEnd - 1;
6579 }
6580 }
6581 }
6582 }
6583
6584 if (state & ItemState::eIsBaselineAligned) {
6585 // The item is baseline aligned, so calculate the baseline sharing group.
6586 // <https://drafts.csswg.org/css-align-3/#baseline-terms>
6587 bool isFirstBaseline = (state & ItemState::eFirstBaseline) != 0;
6588 BaselineSharingGroup baselineAlignment = isFirstBaseline
6589 ? BaselineSharingGroup::First
6590 : BaselineSharingGroup::Last;
6591 // Baseline alignment occurs along `mAxis`, but baselines are defined in
6592 // the orthogonal axis (the axis of the baseline context that defines the
6593 // baseline sharing group).
6594 auto baselineWM = WritingMode::DetermineWritingModeForBaselineSynthesis(
6595 containerWM, childWM, GetOrthogonalAxis(mAxis));
6596
6597 auto sameSideInBaselineWM =
6598 containerWM.ParallelAxisStartsOnSameSide(mAxis, baselineWM);
6599 auto baselineSharingGroup = BaselineSharingGroup::First;
6600 if (sameSideInBaselineWM != isFirstBaseline) {
6601 baselineSharingGroup = BaselineSharingGroup::Last;
6602 state |= ItemState::eLastBaselineSharingGroup;
6603
6604 baselineTrack = (isInlineAxis ? gridItem.mArea.mCols.mEnd
6605 : gridItem.mArea.mRows.mEnd) -
6606 1;
6607 } else {
6608 baselineTrack = isInlineAxis ? gridItem.mArea.mCols.mStart
6609 : gridItem.mArea.mRows.mStart;
6610 }
6611
6612 // XXXmats if |child| is a descendant of a subgrid then the metrics
6613 // below needs to account for the accumulated MPB somehow...
6614
6615 auto* rc = &aGridRI.mRenderingContext;
6616 // XXX figure out if we can avoid/merge this reflow with the main reflow.
6617 // XXX (after bug 1174569 is sorted out)
6618 //
6619 // XXX How should we handle percentage padding here? (bug 1330866)
6620 // XXX (see ::ContentContribution and how it deals with percentages)
6621 // XXX What if the true baseline after line-breaking differs from this
6622 // XXX hypothetical baseline based on an infinite inline size?
6623 // XXX Maybe we should just call ::ContentContribution here instead?
6624 const LogicalSize cbSize = aGridRI.PercentageBasisFor(mAxis, gridItem);
6625 LogicalSize avail(childWM, INFINITE_ISIZE_COORDnscoord(NS_MAXSIZE - (1000000 * 60)), NS_UNCONSTRAINEDSIZE);
6626 const LogicalAxis inlineAxisInChildWM =
6627 isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
6628 const nscoord colSize = cbSize.Size(inlineAxisInChildWM, childWM);
6629 if (colSize != NS_UNCONSTRAINEDSIZE) {
6630 avail.Size(inlineAxisInChildWM, childWM) = colSize;
6631 }
6632 ::MeasuringReflow(child, aGridRI.mReflowInput, rc, avail, cbSize);
6633
6634 nsGridContainerFrame* grid = do_QueryFrame(child);
6635 auto frameSize =
6636 isInlineAxis ? child->ISize(containerWM) : child->BSize(containerWM);
6637 auto margin = child->GetLogicalUsedMargin(containerWM);
6638 auto alignSize =
6639 frameSize + (isInlineAxis ? margin.IStartEnd(containerWM)
6640 : margin.BStartEnd(containerWM));
6641
6642 Maybe<nscoord> baseline;
6643 if (grid) {
6644 baseline.emplace((isOrthogonal == isInlineAxis)
6645 ? grid->GetBBaseline(baselineAlignment)
6646 : grid->GetIBaseline(baselineAlignment));
6647 } else {
6648 if (itemHasBaselineParallelToTrack) {
6649 baseline = child->GetNaturalBaselineBOffset(
6650 childWM, baselineAlignment, BaselineExportContext::Other);
6651 }
6652
6653 if (!baseline) {
6654 // If baseline alignment is specified on a grid item whose size in
6655 // that axis depends on the size of an intrinsically-sized track, that
6656 // item does not participate in baseline alignment, and instead uses
6657 // its fallback alignment as if that were originally specified.
6658 // https://drafts.csswg.org/css-grid-2/#row-align
6659
6660 // Check if the item crosses any tracks that are intrinsically sized.
6661 auto range = gridItem.mArea.LineRangeForAxis(mAxis).Range();
6662 auto isTrackAutoSize =
6663 std::find_if(range.begin(), range.end(), [&](auto track) {
6664 constexpr auto intrinsicSizeFlags =
6665 TrackSize::eIntrinsicMinSizing |
6666 TrackSize::eIntrinsicMaxSizing |
6667 TrackSize::eApplyFitContentClamping |
6668 TrackSize::eFlexMaxSizing;
6669 return (mSizes[track].mState & intrinsicSizeFlags) != 0;
6670 }) != range.end();
6671
6672 // If either the track or the item is not auto sized, then the item
6673 // participates in baseline alignment.
6674 if (!isTrackAutoSize ||
6675 !gridItem.IsBSizeDependentOnContainerSize(containerWM)) {
6676 // We're synthesizing the baseline from the child's border-box
6677 // (frameSize is the size of the border-box). See:
6678 // https://drafts.csswg.org/css-align-3/#baseline-export.
6679
6680 if (containerWM.IsCentralBaseline()) {
6681 // We want to use the exact same central position within the
6682 // frame, regardless of which side we're measuring from. To
6683 // achieve that, we round *up* if we're in the first baseline
6684 // sharing group, and *down* if we're in the last baseline sharing
6685 // group.
6686 const bool isFirstBaselineSharingGroup =
6687 baselineSharingGroup == BaselineSharingGroup::First;
6688 baseline.emplace(frameSize / 2 + (isFirstBaselineSharingGroup
6689 ? 0
6690 : frameSize % 2));
6691 } else {
6692 // The baseline offset is measured from the block-{start,end} edge
6693 // of the container, using the block axis of 'baselineWM' (which
6694 // may differ from the child or container’s writing mode).
6695 //
6696 // If we're synthesizing a baseline from the edge nearest to the
6697 // container's reference side (start for the first baseline group,
6698 // end for the last), the offset is `0`. Otherwise, it's from the
6699 // opposite edge, so we use `frameSize`.
6700 //
6701 // This logic depends on whether we're in the first or last
6702 // baseline-sharing group, and whether the line is inverted (e.g.,
6703 // in vertical-rl mode), which affects which edge is considered
6704 // the "start" or "end".
6705 baseline.emplace((isFirstBaseline == baselineWM.IsLineInverted())
6706 ? 0
6707 : frameSize);
6708 }
6709 }
6710 }
6711 }
6712
6713 if (baseline) {
6714 nscoord finalBaseline = *baseline;
6715 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", 6716)
; MOZ_PretendNoReturn(); } } while (0)
6716 "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", 6716)
; MOZ_PretendNoReturn(); } } while (0)
;
6717
6718 nscoord marginAdjust = 0;
6719 if (baselineSharingGroup == BaselineSharingGroup::First) {
6720 marginAdjust = isInlineAxis ? margin.IStart(containerWM)
6721 : margin.BStart(containerWM);
6722 } else {
6723 marginAdjust = isInlineAxis ? margin.IEnd(containerWM)
6724 : margin.BEnd(containerWM);
6725
6726 // This flag is used in ::AlignSelf(...) to check whether the item is
6727 // last baseline aligned, but this flag should go away.
6728 state |= GridItemInfo::eEndSideBaseline;
6729 }
6730 finalBaseline += marginAdjust;
6731
6732 auto& baselineItems =
6733 (baselineSharingGroup == BaselineSharingGroup::First)
6734 ? firstBaselineItems
6735 : lastBaselineItems;
6736 baselineItems.AppendElement(ItemBaselineData{
6737 baselineTrack, finalBaseline, alignSize, &gridItem});
6738 } else {
6739 state &= ~ItemState::eAllBaselineBits;
6740 }
6741 }
6742
6743 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"
, 6746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6746); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6744 (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"
, 6746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6746); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6745 (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"
, 6746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6746); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6746 "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"
, 6746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6746); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6747 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", 6750
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6750); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6748 (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", 6750
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6750); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6749 (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", 6750
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6750); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6750 "*-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", 6750
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6750); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6751 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", 6754
); 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, 6754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6752 !(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", 6754
); 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, 6754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6753 !(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", 6754
); 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, 6754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6754 "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", 6754
); 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, 6754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6755
6756 gridItem.mState[mAxis] |= state;
6757 gridItem.mBaselineOffset[mAxis] = nscoord(0);
6758 }
6759
6760 if (firstBaselineItems.IsEmpty() && lastBaselineItems.IsEmpty()) {
6761 return;
6762 }
6763
6764 // TODO: CSS Align spec issue - how to align a baseline subtree in a track?
6765 // https://lists.w3.org/Archives/Public/www-style/2016May/0141.html
6766 mBaselineSubtreeAlign[BaselineSharingGroup::First] = StyleAlignFlags::START;
6767 mBaselineSubtreeAlign[BaselineSharingGroup::Last] = StyleAlignFlags::END;
6768
6769 CalculateItemBaselines(firstBaselineItems, BaselineSharingGroup::First);
6770 CalculateItemBaselines(lastBaselineItems, BaselineSharingGroup::Last);
6771}
6772
6773// TODO: we store the wrong baseline group offset in some cases (bug 1632200)
6774void nsGridContainerFrame::Tracks::InitializeItemBaselinesInMasonryAxis(
6775 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
6776 BaselineAlignmentSet aSet, const nsSize& aContainerSize,
6777 nsTArray<nscoord>& aTrackSizes,
6778 nsTArray<ItemBaselineData>& aFirstBaselineItems,
6779 nsTArray<ItemBaselineData>& aLastBaselineItems) {
6780 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"
, 6780); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIsMasonry"
")"); do { MOZ_CrashSequence(__null, 6780); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6781 WritingMode wm = aGridRI.mWM;
6782 ComputedStyle* containerSC = aGridRI.mFrame->Style();
6783 for (GridItemInfo& gridItem : aGridItems) {
6784 if (gridItem.IsSubgrid(mAxis)) {
6785 // A subgrid itself is never baseline-aligned.
6786 continue;
6787 }
6788 const auto& area = gridItem.mArea;
6789 if (aSet.mItemSet == BaselineAlignmentSet::LastItems) {
6790 // NOTE: eIsLastItemInMasonryTrack is set also if the item is the ONLY
6791 // item in its track; the eIsBaselineAligned check excludes it though
6792 // since it participates in the start baseline groups in that case.
6793 //
6794 // XXX what if it's the only item in THAT baseline group?
6795 // XXX should it participate in the last-item group instead then
6796 // if there are more baseline-aligned items there?
6797 if (!(gridItem.mState[mAxis] & ItemState::eIsLastItemInMasonryTrack) ||
6798 (gridItem.mState[mAxis] & ItemState::eIsBaselineAligned)) {
6799 continue;
6800 }
6801 } else {
6802 if (area.LineRangeForAxis(mAxis).mStart > 0 ||
6803 (gridItem.mState[mAxis] & ItemState::eIsBaselineAligned)) {
6804 continue;
6805 }
6806 }
6807 if (!aSet.MatchTrackAlignment(StyleAlignFlags::START)) {
6808 continue;
6809 }
6810
6811 nsIFrame* child = gridItem.mFrame;
6812 uint32_t baselineTrack = kAutoLine;
6813 auto state = ItemState(0);
6814 auto childWM = child->GetWritingMode();
6815 const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
6816 const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
6817 // XXX update the line below to include orthogonal grid/table boxes
6818 // XXX since they have baselines in both dimensions. And flexbox with
6819 // XXX reversed main/cross axis?
6820 const bool itemHasBaselineParallelToTrack = isInlineAxis == isOrthogonal;
6821 if (itemHasBaselineParallelToTrack) {
6822 const auto* pos = child->StylePosition();
6823 // [align|justify]-self:[last ]baseline.
6824 auto selfAlignment = pos->UsedSelfAlignment(mAxis, containerSC);
6825 selfAlignment &= ~StyleAlignFlags::FLAG_BITS;
6826 if (selfAlignment == StyleAlignFlags::BASELINE) {
6827 state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
6828 baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
6829 } else if (selfAlignment == StyleAlignFlags::LAST_BASELINE) {
6830 state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
6831 baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
6832 } else {
6833 // [align|justify]-content:[last ]baseline.
6834 auto childAxis = isOrthogonal ? GetOrthogonalAxis(mAxis) : mAxis;
6835 auto alignContent = pos->UsedContentAlignment(childAxis).primary;
6836 alignContent &= ~StyleAlignFlags::FLAG_BITS;
6837 if (alignContent == StyleAlignFlags::BASELINE) {
6838 state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
6839 baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
6840 } else if (alignContent == StyleAlignFlags::LAST_BASELINE) {
6841 state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
6842 baselineTrack =
6843 (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
6844 }
6845 }
6846 }
6847
6848 if (state & ItemState::eIsBaselineAligned) {
6849 // XXXmats if |child| is a descendant of a subgrid then the metrics
6850 // below needs to account for the accumulated MPB somehow...
6851
6852 nscoord baseline;
6853 nsGridContainerFrame* grid = do_QueryFrame(child);
6854 if (state & ItemState::eFirstBaseline) {
6855 if (grid) {
6856 if (isOrthogonal == isInlineAxis) {
6857 baseline = grid->GetBBaseline(BaselineSharingGroup::First);
6858 } else {
6859 baseline = grid->GetIBaseline(BaselineSharingGroup::First);
6860 }
6861 }
6862 if (grid || nsLayoutUtils::GetFirstLineBaseline(wm, child, &baseline)) {
6863 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", 6864)
; MOZ_PretendNoReturn(); } } while (0)
6864 "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", 6864)
; MOZ_PretendNoReturn(); } } while (0)
;
6865 auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
6866 nscoord alignSize;
6867 LogicalPoint pos =
6868 child->GetLogicalNormalPosition(wm, aContainerSize);
6869 baseline += pos.Pos(mAxis, wm);
6870 if (aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6871 state |= ItemState::eEndSideBaseline;
6872 // Convert to distance from the track end.
6873 baseline =
6874 aTrackSizes[gridItem.mArea
6875 .LineRangeForAxis(GetOrthogonalAxis(mAxis))
6876 .mStart] -
6877 baseline;
6878 }
6879 alignSize = frameSize;
6880 aFirstBaselineItems.AppendElement(ItemBaselineData(
6881 {baselineTrack, baseline, alignSize, &gridItem}));
6882 } else {
6883 state &= ~ItemState::eAllBaselineBits;
6884 }
6885 } else {
6886 if (grid) {
6887 if (isOrthogonal == isInlineAxis) {
6888 baseline = grid->GetBBaseline(BaselineSharingGroup::Last);
6889 } else {
6890 baseline = grid->GetIBaseline(BaselineSharingGroup::Last);
6891 }
6892 }
6893 if (grid || nsLayoutUtils::GetLastLineBaseline(wm, child, &baseline)) {
6894 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", 6895)
; MOZ_PretendNoReturn(); } } while (0)
6895 "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", 6895)
; MOZ_PretendNoReturn(); } } while (0)
;
6896 auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
6897 auto m = child->GetLogicalUsedMargin(wm);
6898 if (!grid &&
6899 aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6900 // Convert to distance from border-box end.
6901 state |= ItemState::eEndSideBaseline;
6902 LogicalPoint pos =
6903 child->GetLogicalNormalPosition(wm, aContainerSize);
6904 baseline += pos.Pos(mAxis, wm);
6905 baseline =
6906 aTrackSizes[gridItem.mArea
6907 .LineRangeForAxis(GetOrthogonalAxis(mAxis))
6908 .mStart] -
6909 baseline;
6910 } else if (grid && aSet.mTrackAlignmentSet ==
6911 BaselineAlignmentSet::StartStretch) {
6912 // Convert to distance from border-box start.
6913 baseline = frameSize - baseline;
6914 }
6915 if (aSet.mItemSet == BaselineAlignmentSet::LastItems &&
6916 aSet.mTrackAlignmentSet == BaselineAlignmentSet::StartStretch) {
6917 LogicalPoint pos =
6918 child->GetLogicalNormalPosition(wm, aContainerSize);
6919 baseline += pos.B(wm);
6920 }
6921 if (aSet.mTrackAlignmentSet == BaselineAlignmentSet::EndStretch) {
6922 state |= ItemState::eEndSideBaseline;
6923 }
6924 auto descent =
6925 baseline + ((state & ItemState::eEndSideBaseline)
6926 ? (isInlineAxis ? m.IEnd(wm) : m.BEnd(wm))
6927 : (isInlineAxis ? m.IStart(wm) : m.BStart(wm)));
6928 auto alignSize =
6929 frameSize + (isInlineAxis ? m.IStartEnd(wm) : m.BStartEnd(wm));
6930 aLastBaselineItems.AppendElement(
6931 ItemBaselineData({baselineTrack, descent, alignSize, &gridItem}));
6932 } else {
6933 state &= ~ItemState::eAllBaselineBits;
6934 }
6935 }
6936 }
6937 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"
, 6940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6938 (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"
, 6940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6939 (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"
, 6940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6940 "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"
, 6940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eFirstBaseline | ItemState::eLastBaseline)) != (ItemState::eFirstBaseline | ItemState::eLastBaseline)"
") (" "first/last baseline bits are mutually exclusive" ")")
; do { MOZ_CrashSequence(__null, 6940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6941 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", 6944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6942 (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", 6944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6943 (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", 6944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6944 "*-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", 6944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(state & (ItemState::eSelfBaseline | ItemState::eContentBaseline)) != (ItemState::eSelfBaseline | ItemState::eContentBaseline)"
") (" "*-self and *-content baseline bits are mutually exclusive"
")"); do { MOZ_CrashSequence(__null, 6944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6945 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", 6948
); 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, 6948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6946 !(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", 6948
); 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, 6948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6947 !(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", 6948
); 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, 6948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6948 "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", 6948
); 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, 6948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6949 gridItem.mState[mAxis] |= state;
6950 gridItem.mBaselineOffset[mAxis] = nscoord(0);
6951 }
6952
6953 CalculateItemBaselines(aFirstBaselineItems, BaselineSharingGroup::First);
6954 CalculateItemBaselines(aLastBaselineItems, BaselineSharingGroup::Last);
6955
6956 // TODO: make sure the mBaselines (i.e. the baselines we export from
6957 // the grid container) are offset from the correct container edge.
6958 // Also, which of the baselines do we pick to export exactly?
6959
6960 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"
, 6963); 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, 6963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6961 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"
, 6963); 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, 6963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6962 "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"
, 6963); 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, 6963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6963 "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"
, 6963); 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, 6963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6964 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"
, 6967); 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, 6967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6965 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"
, 6967); 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, 6967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6966 "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"
, 6967); 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, 6967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6967 "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"
, 6967); 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, 6967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6968}
6969
6970void nsGridContainerFrame::Tracks::AlignBaselineSubtree(
6971 const GridItemInfo& aGridItem) const {
6972 if (mIsMasonry) {
6973 return;
6974 }
6975 auto state = aGridItem.mState[mAxis];
6976 if (!(state & ItemState::eIsBaselineAligned)) {
6977 return;
6978 }
6979 const GridArea& area = aGridItem.mArea;
6980 int32_t baselineTrack;
6981 const bool isFirstBaseline = state & ItemState::eFirstBaseline;
6982 if (isFirstBaseline) {
6983 baselineTrack =
6984 mAxis == LogicalAxis::Block ? area.mRows.mStart : area.mCols.mStart;
6985 } else {
6986 baselineTrack =
6987 (mAxis == LogicalAxis::Block ? area.mRows.mEnd : area.mCols.mEnd) - 1;
6988 }
6989 const TrackSize& sz = mSizes[baselineTrack];
6990 auto baselineGroup = isFirstBaseline ? BaselineSharingGroup::First
6991 : BaselineSharingGroup::Last;
6992 nscoord delta = sz.mBase - sz.mBaselineSubtreeSize[baselineGroup];
6993 const auto subtreeAlign = mBaselineSubtreeAlign[baselineGroup];
6994 if (subtreeAlign == StyleAlignFlags::START) {
6995 if (state & ItemState::eLastBaseline) {
6996 aGridItem.mBaselineOffset[mAxis] += delta;
6997 }
6998 } else if (subtreeAlign == StyleAlignFlags::END) {
6999 if (isFirstBaseline) {
7000 aGridItem.mBaselineOffset[mAxis] += delta;
7001 }
7002 } else if (subtreeAlign == StyleAlignFlags::CENTER) {
7003 aGridItem.mBaselineOffset[mAxis] += delta / 2;
7004 } else {
7005 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"
, 7005); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected baseline subtree alignment"
")"); do { MOZ_CrashSequence(__null, 7005); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7006 }
7007}
7008
7009bool nsGridContainerFrame::Tracks::GrowSizeForSpanningItems(
7010 TrackSizingStep aStep, TrackSizingPhase aPhase,
7011 nsTArray<SpanningItemData>::iterator aIter,
7012 nsTArray<SpanningItemData>::iterator aIterEnd, nsTArray<uint32_t>& aTracks,
7013 TrackPlan& aTrackPlan, ItemPlan& aItemPlan, SizingConstraint aConstraint,
7014 bool aIsGridIntrinsicSizing, const TrackSizingFunctions& aFunctions,
7015 const FitContentClamper& aFitContentClamper,
7016 bool aNeedInfinitelyGrowableFlag) {
7017 const bool isMaxSizingPhase = aPhase == TrackSizingPhase::IntrinsicMaximums ||
7018 aPhase == TrackSizingPhase::MaxContentMaximums;
7019 bool needToUpdateSizes = false;
7020 aTrackPlan.Initialize(aPhase, *this);
7021 for (; aIter != aIterEnd; ++aIter) {
7022 const SpanningItemData& item = *aIter;
7023 if (!(item.mState & SelectorForPhase(aPhase, aConstraint))) {
7024 continue;
7025 }
7026 if (isMaxSizingPhase) {
7027 for (auto i : item.mLineRange.Range()) {
7028 aTrackPlan[i].mState |= TrackSize::eModified;
7029 }
7030 }
7031 if (aStep == TrackSizingStep::Flex && aIsGridIntrinsicSizing) {
7032 // We could only ever grow flex tracks, and when measuring we shouldn't
7033 // grow flex tracks, so the remaining space will always be zero.
7034 continue;
7035 }
7036 nscoord space = item.SizeContributionForPhase(aPhase);
7037 if (space <= 0) {
7038 continue;
7039 }
7040 aTracks.ClearAndRetainStorage();
7041 space = CollectGrowable(aStep, aPhase, space, item.mLineRange, aConstraint,
7042 aTracks);
7043 if (space > 0) {
7044 DistributeToTrackSizes(aStep, aPhase, space, aTrackPlan, aItemPlan,
7045 aTracks, aConstraint, aFunctions,
7046 aFitContentClamper);
7047 needToUpdateSizes = true;
7048 }
7049 }
7050 if (isMaxSizingPhase) {
7051 needToUpdateSizes = true;
7052 }
7053 if (needToUpdateSizes) {
7054 CopyPlanToSize(aPhase, aTrackPlan, aNeedInfinitelyGrowableFlag);
7055 }
7056 return needToUpdateSizes;
7057}
7058
7059void nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
7060 GridReflowInput& aGridRI, nsTArray<GridItemInfo>& aGridItems,
7061 const TrackSizingFunctions& aFunctions, LineRange GridArea::* aRange,
7062 nscoord aPercentageBasis, SizingConstraint aConstraint) {
7063 // Intrinsic sizing algorithm 12.5 steps 2-5
7064 // https://drafts.csswg.org/css-grid-2/#algo-content
7065 //
7066 // We're also setting eIsFlexing on the item state here to speed up
7067 // FindUsedFlexFraction later.
7068
7069 // nonFlexSpanningItems has spanning items that do not span any flex tracks.
7070 // flexSpanningItems has spanning items that span one or more flex tracks.
7071 nsTArray<SpanningItemData> nonFlexSpanningItems, flexSpanningItems;
7072 // max span of items in `nonFlexSpanningItems` and `flexSpanningItems`.
7073 uint32_t maxSpan = 0;
7074
7075 const auto orthogonalAxis = GetOrthogonalAxis(mAxis);
7076 const bool isMasonryInOtherAxis = aGridRI.mFrame->IsMasonry(orthogonalAxis);
7077
7078 for (auto& gridItem : aGridItems) {
7079 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"
, 7082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7082); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7080 (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"
, 7082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7082); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7081 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"
, 7082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7082); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7082 "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"
, 7082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & (ItemState::eContentBasedAutoMinSize | ItemState::eIsFlexing | ItemState::eClampMarginBoxMinSize))"
") (" "Why are any of these bits set already?" ")"); do { MOZ_CrashSequence
(__null, 7082); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7083
7084 const GridArea& area = gridItem.mArea;
7085 const LineRange& lineRange = area.*aRange;
7086 const TrackSize::StateBits state = StateBitsForRange(lineRange);
7087 // Set flex sizing flag as soon as possible to ensure
7088 // MinContributionDependsOnAutoMinSize will function properly.
7089 if (state & TrackSize::eFlexMaxSizing) {
7090 gridItem.mState[mAxis] |= ItemState::eIsFlexing;
7091 }
7092
7093 // If we have masonry layout in the other axis then skip this item unless
7094 // it's in the first masonry track, or has definite placement in this axis,
7095 // or spans all tracks in this axis (since that implies it will be placed
7096 // at line 1 regardless of layout results of other items).
7097 if (isMasonryInOtherAxis &&
7098 gridItem.mArea.LineRangeForAxis(orthogonalAxis).mStart != 0 &&
7099 (gridItem.mState[mAxis] & ItemState::eAutoPlacement) &&
7100 gridItem.mArea.LineRangeForAxis(mAxis).Extent() != mSizes.Length()) {
7101 continue;
7102 }
7103
7104 uint32_t span = lineRange.Extent();
7105 if (MOZ_UNLIKELY(gridItem.mState[mAxis] & ItemState::eIsSubgrid)(__builtin_expect(!!(gridItem.mState[mAxis] & ItemState::
eIsSubgrid), 0))
) {
7106 auto itemWM = gridItem.mFrame->GetWritingMode();
7107 auto percentageBasis = aGridRI.PercentageBasisFor(mAxis, gridItem);
7108
7109 if (percentageBasis.ISize(itemWM) == NS_UNCONSTRAINEDSIZE) {
7110 percentageBasis.ISize(itemWM) = nscoord(0);
7111 }
7112
7113 if (percentageBasis.BSize(itemWM) == NS_UNCONSTRAINEDSIZE) {
7114 percentageBasis.BSize(itemWM) = nscoord(0);
7115 }
7116
7117 const WritingMode wm = aGridRI.mWM;
7118 auto* subgrid =
7119 SubgridComputeMarginBorderPadding(gridItem, percentageBasis);
7120 LogicalMargin mbp = SubgridAccumulatedMarginBorderPadding(
7121 gridItem.SubgridFrame(), subgrid, wm, mAxis);
7122
7123 if (span == 1) {
7124 AddSubgridContribution(mSizes[lineRange.mStart],
7125 mbp.StartEnd(mAxis, wm));
7126 } else {
7127 AddSubgridContribution(mSizes[lineRange.mStart], mbp.Start(mAxis, wm));
7128 AddSubgridContribution(mSizes[lineRange.mEnd - 1], mbp.End(mAxis, wm));
7129 }
7130 continue;
7131 }
7132
7133 // Set eContentBasedAutoMinSize if and only if the grid item has
7134 // content-based automatic minimum size. This is the case if all of the
7135 // following are true of the item:
7136 // 1. its computed overflow is not a scrollable overflow value
7137 // 2. it spans at least one track in that axis whose min track sizing
7138 // function is auto
7139 // 3. if it spans more than one track in that axis, none of those tracks
7140 // are flexible
7141 // https://drafts.csswg.org/css-grid-2/#min-size-auto
7142 if (!gridItem.mFrame->StyleDisplay()->IsScrollableOverflow() &&
7143 state & TrackSize::eAutoMinSizing &&
7144 (span == 1 || !(state & TrackSize::eFlexMaxSizing))) {
7145 gridItem.mState[mAxis] |= ItemState::eContentBasedAutoMinSize;
7146 }
7147
7148 if (span == 1) {
7149 // Step 2. Size tracks to fit non-spanning items.
7150 // https://drafts.csswg.org/css-grid-2/#algo-single-span-items
7151 ResolveIntrinsicSizeForNonSpanningItems(aGridRI, aFunctions,
7152 aPercentageBasis, aConstraint,
7153 lineRange, gridItem);
7154 } else {
7155 // Collect information for step 3.
7156 // https://drafts.csswg.org/css-grid-2/#algo-spanning-items
7157
7158 nsTArray<SpanningItemData>* items;
7159 if (state & TrackSize::eFlexMaxSizing) {
7160 // Set eIsFlexing on the item state here to speed up
7161 // FindUsedFlexFraction later.
7162 gridItem.mState[mAxis] |= ItemState::eIsFlexing;
7163 items = &flexSpanningItems;
7164 } else {
7165 items = &nonFlexSpanningItems;
7166 }
7167
7168 if (state &
7169 (TrackSize::eIntrinsicMinSizing | TrackSize::eIntrinsicMaxSizing)) {
7170 maxSpan = std::max(maxSpan, span);
7171 CachedIntrinsicSizes cache{gridItem, aGridRI, mAxis};
7172
7173 // Calculate data for "Automatic Minimum Size" clamping, if needed.
7174 if (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize) {
7175 if (const Maybe<nscoord> minSizeClamp = ComputeMinSizeClamp(
7176 aFunctions, aPercentageBasis, lineRange, state)) {
7177 cache.mMinSizeClamp = *minSizeClamp;
7178 gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
7179 }
7180 }
7181
7182 // Collect the various grid item size contributions we need.
7183 EnumSet<GridIntrinsicSizeType> sizeTypesToCalculate;
7184 // For 3.1
7185 TrackSize::StateBits selector =
7186 SelectorForPhase(TrackSizingPhase::IntrinsicMinimums, aConstraint);
7187
7188 if (state & selector) {
7189 sizeTypesToCalculate += GridIntrinsicSizeType::MinContribution;
7190 }
7191
7192 // For 3.2 and 3.5
7193 selector =
7194 SelectorForPhase(TrackSizingPhase::IntrinsicMaximums, aConstraint) |
7195 SelectorForPhase(TrackSizingPhase::ContentBasedMinimums,
7196 aConstraint);
7197 if (state & selector) {
7198 sizeTypesToCalculate += GridIntrinsicSizeType::MinContentContribution;
7199 }
7200
7201 // For 3.3 and 3.6
7202 selector =
7203 SelectorForPhase(TrackSizingPhase::MaxContentMinimums,
7204 aConstraint) |
7205 SelectorForPhase(TrackSizingPhase::MaxContentMaximums, aConstraint);
7206 if (state & selector) {
7207 sizeTypesToCalculate += GridIntrinsicSizeType::MaxContentContribution;
7208 }
7209
7210 cache.EnsureContributions(sizeTypesToCalculate, gridItem, aGridRI,
7211 mAxis);
7212 items->AppendElement(SpanningItemData(
7213 {span, state, lineRange, cache.SizesOrDefault(), gridItem.mFrame}));
7214 }
7215 }
7216
7217 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"
, 7220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7220); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7218 !(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"
, 7220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7220); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7219 (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"
, 7220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7220); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7220 "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"
, 7220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) || (gridItem.mState[mAxis] & ItemState::eContentBasedAutoMinSize)"
") (" "clamping only applies to Automatic Minimum Size" ")")
; do { MOZ_CrashSequence(__null, 7220); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7221 }
7222
7223 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"
, 7223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxSpan != 1"
") (" "Should only count spans greater than 1" ")"); do { MOZ_CrashSequence
(__null, 7223); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7224 // Step 3 - Increase sizes to accommodate spanning items crossing
7225 // content-sized tracks.
7226 if (maxSpan) {
7227 auto fitContentClamper = [&aFunctions, aPercentageBasis](uint32_t aTrack,
7228 nscoord aMinSize,
7229 nscoord* aSize) {
7230 nscoord fitContentLimit = ::ResolveToDefiniteSize(
7231 aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
7232 if (*aSize > fitContentLimit) {
7233 *aSize = std::max(aMinSize, fitContentLimit);
7234 return true;
7235 }
7236 return false;
7237 };
7238
7239 // Step 3 should "Repeat incrementally for items with greater spans until
7240 // all items have been considered."
7241 // Sort the collected items on span length, shortest first. There's no need
7242 // for a stable sort here since the sizing isn't order dependent within
7243 // a group of items with the same span length.
7244 // We don't need to sort flexSpanningItems, those items are all considered
7245 // "together, rather than grouped by span size" for step 4.
7246 std::sort(nonFlexSpanningItems.begin(), nonFlexSpanningItems.end(),
7247 SpanningItemData::IsSpanLessThan);
7248
7249 nsTArray<uint32_t> tracks(maxSpan);
7250 TrackPlan plan(mSizes.Length());
7251 plan.SetLength(mSizes.Length());
7252 ItemPlan itemPlan(mSizes.Length());
7253 itemPlan.SetLength(mSizes.Length());
7254
7255 // Start / end iterator for items of the same span length:
7256 auto spanGroupStart = nonFlexSpanningItems.begin();
7257 auto spanGroupEnd = spanGroupStart;
7258 const auto end = nonFlexSpanningItems.end();
7259
7260 // nonFlexSpanningItems is sorted by span size. Each iteration will process
7261 // one span size.
7262 for (; spanGroupStart != end; spanGroupStart = spanGroupEnd) {
7263 const uint32_t span = spanGroupStart->mSpan;
7264 TrackSize::StateBits stateBitsForSpan = TrackSize::StateBits::eNone;
7265 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"
, 7265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "spanGroupEnd == spanGroupStart"
")"); do { MOZ_CrashSequence(__null, 7265); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7266 // Find the end of this group if items with the same span size.
7267 // Accumulate state bits for the items with this span size to avoid
7268 // calculations below that are not applicable to any of those items.
7269 do {
7270 stateBitsForSpan |= StateBitsForRange(spanGroupEnd->mLineRange);
7271 } while (++spanGroupEnd != end && spanGroupEnd->mSpan == span);
7272 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", 7273
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
") (" "Non-flex spanning items should not include any flex tracks"
")"); do { MOZ_CrashSequence(__null, 7273); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7273 "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", 7273
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(stateBitsForSpan & TrackSize::eFlexMaxSizing)"
") (" "Non-flex spanning items should not include any flex tracks"
")"); do { MOZ_CrashSequence(__null, 7273); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7274 bool updatedBase = false; // Did we update any mBase in step 3.1..3.3?
7275 TrackSizingPhase phase = TrackSizingPhase::IntrinsicMinimums;
7276 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7277 // Step 3.1 MinSize to intrinsic min-sizing.
7278 updatedBase = GrowSizeForSpanningItems(
7279 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7280 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7281 aFunctions);
7282 }
7283
7284 phase = TrackSizingPhase::ContentBasedMinimums;
7285 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7286 // Step 3.2 MinContentContribution to min-/max-content (and 'auto' when
7287 // sizing under a min-content constraint) min-sizing.
7288 updatedBase |= GrowSizeForSpanningItems(
7289 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7290 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7291 aFunctions);
7292 }
7293
7294 phase = TrackSizingPhase::MaxContentMinimums;
7295 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7296 // Step 3.3 MaxContentContribution to max-content (and 'auto' when
7297 // sizing under a max-content constraint) min-sizing.
7298 updatedBase |= GrowSizeForSpanningItems(
7299 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7300 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7301 aFunctions);
7302 }
7303
7304 if (updatedBase) {
7305 // Step 3.4
7306 for (TrackSize& sz : mSizes) {
7307 if (sz.mBase > sz.mLimit) {
7308 sz.mLimit = sz.mBase;
7309 }
7310 }
7311 }
7312
7313 phase = TrackSizingPhase::IntrinsicMaximums;
7314 bool willRunStep3_6 = false;
7315 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7316 willRunStep3_6 =
7317 stateBitsForSpan & TrackSize::eAutoOrMaxContentMaxSizing;
7318 // Step 3.5 MinContentContribution to intrinsic max-sizing.
7319 GrowSizeForSpanningItems(
7320 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7321 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7322 aFunctions, fitContentClamper, willRunStep3_6);
7323 }
7324 if (willRunStep3_6) {
7325 // Step 2.6 MaxContentContribution to max-content max-sizing.
7326 phase = TrackSizingPhase::MaxContentMaximums;
7327 GrowSizeForSpanningItems(
7328 TrackSizingStep::NotFlex, phase, spanGroupStart, spanGroupEnd,
7329 tracks, plan, itemPlan, aConstraint, aGridRI.mIsGridIntrinsicSizing,
7330 aFunctions, fitContentClamper);
7331 }
7332 }
7333
7334 // Step 4
7335 TrackSize::StateBits stateBitsForSpan = TrackSize::StateBits::eNone;
7336 for (const SpanningItemData& spanningData : flexSpanningItems) {
7337 const TrackSize::StateBits bits =
7338 StateBitsForRange(spanningData.mLineRange);
7339 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", 7340
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bits & TrackSize::eFlexMaxSizing"
") (" "All flex spanning items should have at least one flex track"
")"); do { MOZ_CrashSequence(__null, 7340); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7340 "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", 7340
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bits & TrackSize::eFlexMaxSizing"
") (" "All flex spanning items should have at least one flex track"
")"); do { MOZ_CrashSequence(__null, 7340); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7341 stateBitsForSpan |= bits;
7342 }
7343 bool updatedBase = false; // Did we update any mBase in step 4.1..4.3?
7344 TrackSizingPhase phase = TrackSizingPhase::IntrinsicMinimums;
7345 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7346 // Step 4.1 MinSize to intrinsic min-sizing.
7347 updatedBase = GrowSizeForSpanningItems(
7348 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7349 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7350 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7351 }
7352
7353 phase = TrackSizingPhase::ContentBasedMinimums;
7354 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7355 // Step 4.2 MinContentContribution to min-/max-content (and 'auto' when
7356 // sizing under a min-content constraint) min-sizing.
7357 updatedBase |= GrowSizeForSpanningItems(
7358 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7359 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7360 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7361 }
7362
7363 phase = TrackSizingPhase::MaxContentMinimums;
7364 if (stateBitsForSpan & SelectorForPhase(phase, aConstraint)) {
7365 // Step 4.3 MaxContentContribution to max-content (and 'auto' when
7366 // sizing under a max-content constraint) min-sizing.
7367 updatedBase |= GrowSizeForSpanningItems(
7368 TrackSizingStep::Flex, phase, flexSpanningItems.begin(),
7369 flexSpanningItems.end(), tracks, plan, itemPlan, aConstraint,
7370 aGridRI.mIsGridIntrinsicSizing, aFunctions);
7371 }
7372
7373 if (updatedBase) {
7374 // Step 4.4
7375 for (TrackSize& sz : mSizes) {
7376 if (sz.mBase > sz.mLimit) {
7377 sz.mLimit = sz.mBase;
7378 }
7379 }
7380 }
7381 }
7382
7383 // Step 5 - If any track still has an infinite growth limit, set its growth
7384 // limit to its base size.
7385 for (TrackSize& sz : mSizes) {
7386 if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
7387 sz.mLimit = sz.mBase;
7388 }
7389 }
7390}
7391
7392float nsGridContainerFrame::Tracks::FindFrUnitSize(
7393 const LineRange& aRange, const nsTArray<uint32_t>& aFlexTracks,
7394 const TrackSizingFunctions& aFunctions, nscoord aSpaceToFill) const {
7395 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"
, 7395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSpaceToFill > 0 && !aFlexTracks.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 7395); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7396 float flexFactorSum = 0.0f;
7397 nscoord leftOverSpace = aSpaceToFill;
7398 for (auto i : aRange.Range()) {
7399 const TrackSize& sz = mSizes[i];
7400 if (sz.mState & TrackSize::eFlexMaxSizing) {
7401 flexFactorSum += aFunctions.MaxSizingFor(i).AsFlex()._0;
7402 } else {
7403 leftOverSpace -= sz.mBase;
7404 if (leftOverSpace <= 0) {
7405 return 0.0f;
7406 }
7407 }
7408 }
7409 bool restart;
7410 float hypotheticalFrSize;
7411 nsTArray<uint32_t> flexTracks(aFlexTracks.Clone());
7412 uint32_t numFlexTracks = flexTracks.Length();
7413 do {
7414 restart = false;
7415
7416 // 12.7.1.2: If flexFactorSum is less than 1, set it to 1 instead.
7417 hypotheticalFrSize = leftOverSpace / std::max(flexFactorSum, 1.0f);
7418 for (uint32_t& track : flexTracks) {
7419 if (track == kAutoLine) {
7420 continue; // Track marked as inflexible in a prev. iter of this loop.
7421 }
7422 float flexFactor = aFunctions.MaxSizingFor(track).AsFlex()._0;
7423 const nscoord base = mSizes[track].mBase;
7424 if (flexFactor * hypotheticalFrSize < base) {
7425 // 12.7.1.4: Treat this track as inflexible.
7426 track = kAutoLine;
7427 flexFactorSum -= flexFactor;
7428 leftOverSpace -= base;
7429 --numFlexTracks;
7430 if (numFlexTracks == 0 || leftOverSpace <= 0) {
7431 return 0.0f;
7432 }
7433 restart = true;
7434 // break; XXX (bug 1176621 comment 16) measure which is more common
7435 }
7436 }
7437 } while (restart);
7438 return hypotheticalFrSize;
7439}
7440
7441float nsGridContainerFrame::Tracks::FindUsedFlexFraction(
7442 GridReflowInput& aGridRI, const nsTArray<GridItemInfo>& aGridItems,
7443 const nsTArray<uint32_t>& aFlexTracks,
7444 const TrackSizingFunctions& aFunctions, nscoord aAvailableSize) const {
7445 if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
7446 // Use all of the grid tracks and a 'space to fill' of the available space.
7447 const TranslatedLineRange range(0, mSizes.Length());
7448 return FindFrUnitSize(range, aFlexTracks, aFunctions, aAvailableSize);
7449 }
7450
7451 // The used flex fraction is the maximum of:
7452 // ... each flexible track's base size divided by its flex factor (which is
7453 // floored at 1).
7454 float fr = 0.0f;
7455 for (uint32_t track : aFlexTracks) {
7456 float flexFactor = aFunctions.MaxSizingFor(track).AsFlex()._0;
7457 float possiblyDividedBaseSize = (flexFactor > 1.0f)
7458 ? mSizes[track].mBase / flexFactor
7459 : mSizes[track].mBase;
7460 fr = std::max(fr, possiblyDividedBaseSize);
7461 }
7462 // ... the result of 'finding the size of an fr' for each item that spans
7463 // a flex track with its max-content contribution as 'space to fill'
7464 for (const GridItemInfo& item : aGridItems) {
7465 if (item.mState[mAxis] & ItemState::eIsFlexing) {
7466 // XXX optimize: bug 1194446
7467 const auto percentageBasis = aGridRI.PercentageBasisFor(mAxis, item);
7468 nscoord spaceToFill = ContentContribution(
7469 item, aGridRI, mAxis, percentageBasis, IntrinsicISizeType::PrefISize);
7470 const LineRange& range =
7471 mAxis == LogicalAxis::Inline ? item.mArea.mCols : item.mArea.mRows;
7472 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", 7472)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "range.Extent() >= 1"
")"); do { MOZ_CrashSequence(__null, 7472); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7473 const auto spannedGaps = range.Extent() - 1;
7474 if (spannedGaps > 0) {
7475 spaceToFill -= mGridGap * spannedGaps;
7476 }
7477 if (spaceToFill <= 0) {
7478 continue;
7479 }
7480 // ... and all its spanned tracks as input.
7481 nsTArray<uint32_t> itemFlexTracks;
7482 for (auto i : range.Range()) {
7483 if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
7484 itemFlexTracks.AppendElement(i);
7485 }
7486 }
7487 float itemFr =
7488 FindFrUnitSize(range, itemFlexTracks, aFunctions, spaceToFill);
7489 fr = std::max(fr, itemFr);
7490 }
7491 }
7492 return fr;
7493}
7494
7495void nsGridContainerFrame::Tracks::StretchFlexibleTracks(
7496 GridReflowInput& aGridRI, const nsTArray<GridItemInfo>& aGridItems,
7497 const TrackSizingFunctions& aFunctions, nscoord aAvailableSize) {
7498 if (aAvailableSize <= 0) {
7499 return;
7500 }
7501 nsTArray<uint32_t> flexTracks(mSizes.Length());
7502 for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
7503 if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
7504 flexTracks.AppendElement(i);
7505 }
7506 }
7507 if (flexTracks.IsEmpty()) {
7508 return;
7509 }
7510 nscoord minSize = 0;
7511 nscoord maxSize = NS_UNCONSTRAINEDSIZE;
7512 if (aGridRI.mReflowInput) {
7513 auto* ri = aGridRI.mReflowInput;
7514 minSize = mAxis == LogicalAxis::Block ? ri->ComputedMinBSize()
7515 : ri->ComputedMinISize();
7516 maxSize = mAxis == LogicalAxis::Block ? ri->ComputedMaxBSize()
7517 : ri->ComputedMaxISize();
7518 }
7519 Maybe<TrackPlan> origSizes;
7520 bool applyMinMax = (minSize != 0 || maxSize != NS_UNCONSTRAINEDSIZE) &&
7521 aAvailableSize == NS_UNCONSTRAINEDSIZE;
7522 // We iterate twice at most. The 2nd time if the grid size changed after
7523 // applying a min/max-size (can only occur if aAvailableSize is indefinite).
7524 while (true) {
7525 float fr = FindUsedFlexFraction(aGridRI, aGridItems, flexTracks, aFunctions,
7526 aAvailableSize);
7527 if (fr != 0.0f) {
7528 for (uint32_t i : flexTracks) {
7529 float flexFactor = aFunctions.MaxSizingFor(i).AsFlex()._0;
7530 nscoord flexLength = NSToCoordRound(flexFactor * fr);
7531 nscoord& base = mSizes[i].mBase;
7532 if (flexLength > base) {
7533 if (applyMinMax && origSizes.isNothing()) {
7534 origSizes.emplace(mSizes);
7535 }
7536 base = flexLength;
7537 }
7538 }
7539 }
7540 if (applyMinMax) {
7541 applyMinMax = false;
7542 // https://drafts.csswg.org/css-grid-2/#algo-flex-tracks
7543 // "If using this flex fraction would cause the grid to be smaller than
7544 // the grid container’s min-width/height (or larger than the grid
7545 // container’s max-width/height), then redo this step, treating the free
7546 // space as definite [...]"
7547 const auto sumOfGridGaps = SumOfGridGaps();
7548 nscoord newSize = SumOfGridTracks() + sumOfGridGaps;
7549 if (newSize > maxSize) {
7550 aAvailableSize = maxSize;
7551 } else if (newSize < minSize) {
7552 aAvailableSize = minSize;
7553 }
7554 if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
7555 aAvailableSize = std::max(0, aAvailableSize - sumOfGridGaps);
7556 // Restart with the original track sizes and definite aAvailableSize.
7557 if (origSizes.isSome()) {
7558 mSizes = std::move(*origSizes);
7559 origSizes.reset();
7560 } // else, no mSizes[].mBase were changed above so it's still correct
7561 if (aAvailableSize == 0) {
7562 break; // zero available size wouldn't change any sizes though...
7563 }
7564 continue;
7565 }
7566 }
7567 break;
7568 }
7569}
7570
7571void nsGridContainerFrame::Tracks::AlignJustifyContent(
7572 const nsStylePosition* aStyle, StyleContentDistribution aAligmentStyleValue,
7573 WritingMode aWM, nscoord aContentBoxSize, bool aIsSubgriddedAxis) {
7574 const bool isAlign = mAxis == LogicalAxis::Block;
7575 // Align-/justify-content doesn't apply in a subgridded axis.
7576 // Gap properties do apply though so we need to stretch/position the tracks
7577 // to center-align the gaps with the parent's gaps.
7578 if (MOZ_UNLIKELY(aIsSubgriddedAxis)(__builtin_expect(!!(aIsSubgriddedAxis), 0))) {
7579 auto& gap = isAlign ? aStyle->mRowGap : aStyle->mColumnGap;
7580 if (gap.IsNormal()) {
7581 return;
7582 }
7583 auto len = mSizes.Length();
7584 if (len <= 1) {
7585 return;
7586 }
7587 // This stores the gap deltas between the subgrid gap and the gaps in
7588 // the used track sizes (as encoded in its tracks' mPosition):
7589 nsTArray<nscoord> gapDeltas;
7590 const size_t numGaps = len - 1;
7591 gapDeltas.SetLength(numGaps);
7592 for (size_t i = 0; i < numGaps; ++i) {
7593 TrackSize& sz1 = mSizes[i];
7594 TrackSize& sz2 = mSizes[i + 1];
7595 nscoord currentGap = sz2.mPosition - (sz1.mPosition + sz1.mBase);
7596 gapDeltas[i] = mGridGap - currentGap;
7597 }
7598 // Recompute the tracks' size/position so that they end up with
7599 // a subgrid-gap centered on the original track gap.
7600 nscoord currentPos = mSizes[0].mPosition;
7601 nscoord lastHalfDelta(0);
7602 for (size_t i = 0; i < numGaps; ++i) {
7603 TrackSize& sz = mSizes[i];
7604 nscoord delta = gapDeltas[i];
7605 nscoord halfDelta;
7606 nscoord roundingError = NSCoordDivRem(delta, 2, &halfDelta);
7607 auto newSize = sz.mBase - (halfDelta + roundingError) - lastHalfDelta;
7608 lastHalfDelta = halfDelta;
7609 // If the gap delta (in particular 'halfDelta + lastHalfDelta') is larger
7610 // than the current track size, newSize can be negative. Don't let the new
7611 // track size (mBase) be negative.
7612 sz.mBase = std::max(newSize, 0);
7613 sz.mPosition = currentPos;
7614 currentPos += newSize + mGridGap;
7615 }
7616 auto& lastTrack = mSizes.LastElement();
7617 auto newSize = lastTrack.mBase - lastHalfDelta;
7618 lastTrack.mBase = std::max(newSize, 0);
7619 lastTrack.mPosition = currentPos;
7620 return;
7621 }
7622
7623 if (mSizes.IsEmpty()) {
7624 return;
7625 }
7626
7627 bool overflowSafe;
7628 auto alignment = ::GetAlignJustifyValue(aAligmentStyleValue.primary, aWM,
7629 isAlign, &overflowSafe);
7630 if (alignment == StyleAlignFlags::NORMAL) {
7631 alignment = StyleAlignFlags::STRETCH;
7632 // we may need a fallback for 'stretch' below
7633 aAligmentStyleValue = {alignment};
7634 }
7635
7636 // Compute the free space and count auto-sized tracks.
7637 size_t numAutoTracks = 0;
7638 nscoord space;
7639 if (alignment != StyleAlignFlags::START) {
7640 nscoord trackSizeSum = 0;
7641 if (aIsSubgriddedAxis) {
7642 numAutoTracks = mSizes.Length();
7643 } else {
7644 for (const TrackSize& sz : mSizes) {
7645 trackSizeSum += sz.mBase;
7646 if (sz.mState & TrackSize::eAutoMaxSizing) {
7647 ++numAutoTracks;
7648 }
7649 }
7650 }
7651 space = aContentBoxSize - trackSizeSum - SumOfGridGaps();
7652 // Use the fallback value instead when applicable.
7653 if (space < 0 ||
7654 (alignment == StyleAlignFlags::SPACE_BETWEEN && mSizes.Length() == 1)) {
7655 auto fallback = GetAlignJustifyDistributionFallback(aAligmentStyleValue,
7656 &overflowSafe);
7657 if (fallback) {
7658 alignment = *fallback;
7659 }
7660 }
7661 if (space == 0 || (space < 0 && overflowSafe)) {
7662 // XXX check that this makes sense also for [last ]baseline (bug 1151204).
7663 alignment = StyleAlignFlags::START;
7664 }
7665 }
7666
7667 // Optimize the cases where we just need to set each track's position.
7668 nscoord pos = 0;
7669 bool distribute = true;
7670 if (alignment == StyleAlignFlags::BASELINE ||
7671 alignment == StyleAlignFlags::LAST_BASELINE) {
7672 NS_WARNING("NYI: 'first/last baseline' (bug 1151204)")NS_DebugBreak(NS_DEBUG_WARNING, "NYI: 'first/last baseline' (bug 1151204)"
, nullptr, "./../../../layout/generic/nsGridContainerFrame.cpp"
, 7672)
; // XXX
7673 alignment = StyleAlignFlags::START;
7674 }
7675 if (alignment == StyleAlignFlags::START) {
7676 distribute = false;
7677 } else if (alignment == StyleAlignFlags::END) {
7678 pos = space;
7679 distribute = false;
7680 } else if (alignment == StyleAlignFlags::CENTER) {
7681 pos = space / 2;
7682 distribute = false;
7683 } else if (alignment == StyleAlignFlags::STRETCH) {
7684 distribute = numAutoTracks != 0;
7685 }
7686 if (!distribute) {
7687 for (TrackSize& sz : mSizes) {
7688 sz.mPosition = pos;
7689 pos += sz.mBase + mGridGap;
7690 }
7691 return;
7692 }
7693
7694 // Distribute free space to/between tracks and set their position.
7695 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"
, 7695); AnnotateMozCrashReason("MOZ_ASSERT" "(" "space > 0"
") (" "should've handled that on the fallback path above" ")"
); do { MOZ_CrashSequence(__null, 7695); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7696 nscoord between, roundingError;
7697 if (alignment == StyleAlignFlags::STRETCH) {
7698 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"
, 7698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numAutoTracks > 0"
") (" "we handled numAutoTracks == 0 above" ")"); do { MOZ_CrashSequence
(__null, 7698); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7699 // The outer loop typically only runs once - it repeats only in a masonry
7700 // axis when some stretchable items reach their `max-size`.
7701 // It's O(n^2) worst case; if all items are stretchable with a `max-size`
7702 // and exactly one item reaches its `max-size` each round.
7703 while (space) {
7704 pos = 0;
7705 nscoord spacePerTrack;
7706 roundingError = NSCoordDivRem(space, numAutoTracks, &spacePerTrack);
7707 space = 0;
7708 for (TrackSize& sz : mSizes) {
7709 sz.mPosition = pos;
7710 if (!(sz.mState & TrackSize::eAutoMaxSizing)) {
7711 pos += sz.mBase + mGridGap;
7712 continue;
7713 }
7714 nscoord stretch = spacePerTrack;
7715 if (roundingError) {
7716 roundingError -= 1;
7717 stretch += 1;
7718 }
7719 nscoord newBase = sz.mBase + stretch;
7720 if (mIsMasonry && (sz.mState & TrackSize::eClampToLimit)) {
7721 auto clampedSize = std::min(newBase, sz.mLimit);
7722 auto sizeOverLimit = newBase - clampedSize;
7723 if (sizeOverLimit > 0) {
7724 newBase = clampedSize;
7725 sz.mState &= ~(sz.mState & TrackSize::eAutoMaxSizing);
7726 // This repeats the outer loop to distribute the superfluous space:
7727 space += sizeOverLimit;
7728 if (--numAutoTracks == 0) {
7729 // ... except if we don't have any stretchable items left.
7730 space = 0;
7731 }
7732 }
7733 }
7734 sz.mBase = newBase;
7735 pos += newBase + mGridGap;
7736 }
7737 }
7738 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"
, 7738); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!roundingError"
") (" "we didn't distribute all rounding error?" ")"); do { MOZ_CrashSequence
(__null, 7738); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7739 return;
7740 }
7741 if (alignment == StyleAlignFlags::SPACE_BETWEEN) {
7742 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"
, 7742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSizes.Length() > 1"
") (" "should've used a fallback above" ")"); do { MOZ_CrashSequence
(__null, 7742); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7743 roundingError = NSCoordDivRem(space, mSizes.Length() - 1, &between);
7744 } else if (alignment == StyleAlignFlags::SPACE_AROUND) {
7745 roundingError = NSCoordDivRem(space, mSizes.Length(), &between);
7746 pos = between / 2;
7747 } else if (alignment == StyleAlignFlags::SPACE_EVENLY) {
7748 roundingError = NSCoordDivRem(space, mSizes.Length() + 1, &between);
7749 pos = between;
7750 } else {
7751 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"
, 7751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown align-/justify-content value"
")"); do { MOZ_CrashSequence(__null, 7751); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7752 between = 0; // just to avoid a compiler warning
7753 roundingError = 0; // just to avoid a compiler warning
7754 }
7755 between += mGridGap;
7756 for (TrackSize& sz : mSizes) {
7757 sz.mPosition = pos;
7758 nscoord spacing = between;
7759 if (roundingError) {
7760 roundingError -= 1;
7761 spacing += 1;
7762 }
7763 pos += sz.mBase + spacing;
7764 }
7765 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"
, 7765); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!roundingError"
") (" "we didn't distribute all rounding error?" ")"); do { MOZ_CrashSequence
(__null, 7765); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7766}
7767
7768nscoord nsGridContainerFrame::Tracks::TotalTrackSizeWithoutAlignment(
7769 const nsGridContainerFrame* aGridContainerFrame) const {
7770 if (aGridContainerFrame->IsSubgrid(mAxis)) {
7771 // TODO: Investigate whether GridLineEdge here may include extra packing
7772 // space introduced by align-content or justify-content, and if that could
7773 // lead to inconsistent metrics vs. the non-subgrid path.
7774 return GridLineEdge(mSizes.Length(), GridLineSide::BeforeGridGap);
7775 }
7776
7777 // This method allows for the possibility that AlignJustifyContent() might not
7778 // be called yet. Therefore, we can't use GridLineEdge() here, as mPosition
7779 // may not be calculated.
7780 return SumOfGridTracksAndGaps();
7781}
7782
7783void nsGridContainerFrame::LineRange::ToPositionAndLength(
7784 const TrackPlan& aTrackSizes, nscoord* aPos, nscoord* aLength) const {
7785 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"
, 7786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7786); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7786 "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"
, 7786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7786); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7787 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", 7787)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart < mEnd" ")"
); do { MOZ_CrashSequence(__null, 7787); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7788 nscoord startPos = aTrackSizes[mStart].mPosition;
7789 const TrackSize& sz = aTrackSizes[mEnd - 1];
7790 *aPos = startPos;
7791 *aLength = (sz.mPosition + sz.mBase) - startPos;
7792}
7793
7794nscoord nsGridContainerFrame::LineRange::ToLength(
7795 const TrackPlan& aTrackSizes) const {
7796 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"
, 7797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7797); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7797 "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"
, 7797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart != kAutoLine && mEnd != kAutoLine"
") (" "expected a definite LineRange" ")"); do { MOZ_CrashSequence
(__null, 7797); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7798 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", 7798)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStart < mEnd" ")"
); do { MOZ_CrashSequence(__null, 7798); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7799 nscoord startPos = aTrackSizes[mStart].mPosition;
7800 const TrackSize& sz = aTrackSizes[mEnd - 1];
7801 return (sz.mPosition + sz.mBase) - startPos;
7802}
7803
7804void nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos(
7805 const Tracks& aTracks, nscoord aGridOrigin, nscoord* aPos,
7806 nscoord* aLength) const {
7807 // kAutoLine for abspos children contributes the corresponding edge
7808 // of the grid container's padding-box.
7809 if (mEnd == kAutoLine) {
7810 if (mStart == kAutoLine) {
7811 // done
7812 } else {
7813 const nscoord endPos = *aPos + *aLength;
7814 auto side = mStart == aTracks.mSizes.Length()
7815 ? GridLineSide::BeforeGridGap
7816 : GridLineSide::AfterGridGap;
7817 nscoord startPos = aTracks.GridLineEdge(mStart, side);
7818 *aPos = aGridOrigin + startPos;
7819 *aLength = std::max(endPos - *aPos, 0);
7820 }
7821 } else {
7822 if (mStart == kAutoLine) {
7823 auto side =
7824 mEnd == 0 ? GridLineSide::AfterGridGap : GridLineSide::BeforeGridGap;
7825 nscoord endPos = aTracks.GridLineEdge(mEnd, side);
7826 *aLength = std::max(aGridOrigin + endPos, 0);
7827 } else if (MOZ_LIKELY(mStart != mEnd)(__builtin_expect(!!(mStart != mEnd), 1))) {
7828 nscoord pos;
7829 ToPositionAndLength(aTracks.mSizes, &pos, aLength);
7830 *aPos = aGridOrigin + pos;
7831 } else {
7832 // The grid area only covers removed 'auto-fit' tracks.
7833 nscoord pos = aTracks.GridLineEdge(mStart, GridLineSide::BeforeGridGap);
7834 *aPos = aGridOrigin + pos;
7835 *aLength = nscoord(0);
7836 }
7837 }
7838}
7839
7840LogicalSize nsGridContainerFrame::GridReflowInput::PercentageBasisFor(
7841 LogicalAxis aAxis, const GridItemInfo& aGridItem) const {
7842 auto wm = aGridItem.mFrame->GetWritingMode();
7843 const auto* itemParent = aGridItem.mFrame->GetParent();
7844 if (MOZ_UNLIKELY(itemParent != mFrame)(__builtin_expect(!!(itemParent != mFrame), 0))) {
7845 // The item comes from a descendant subgrid. Use the subgrid's
7846 // used track sizes to resolve the grid area size, if present.
7847 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", 7847)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "itemParent->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 7847); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7848 auto* subgridFrame = static_cast<const nsGridContainerFrame*>(itemParent);
7849 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"
, 7849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgridFrame->IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 7849); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7850 if (auto* uts = subgridFrame->GetUsedTrackSizes()) {
7851 auto subgridWM = subgridFrame->GetWritingMode();
7852 LogicalSize cbSize(subgridWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
7853 if (!subgridFrame->IsColSubgrid() &&
7854 uts->mCanResolveLineRangeSize[LogicalAxis::Inline]) {
7855 // NOTE: At this point aGridItem.mArea is in this->mFrame coordinates
7856 // and thus may have been transposed. The range values in a non-
7857 // subgridded axis still has its original values in subgridFrame's
7858 // coordinates though.
7859 const auto subgridIAxisInGridWM =
7860 subgridWM.ConvertAxisTo(LogicalAxis::Inline, mWM);
7861 const auto& range =
7862 aGridItem.mArea.LineRangeForAxis(subgridIAxisInGridWM);
7863 cbSize.ISize(subgridWM) =
7864 range.ToLength(uts->mTrackPlans[LogicalAxis::Inline]);
7865 }
7866 if (!subgridFrame->IsRowSubgrid() &&
7867 uts->mCanResolveLineRangeSize[LogicalAxis::Block]) {
7868 const auto subgridBAxisInGridWM =
7869 subgridWM.ConvertAxisTo(LogicalAxis::Block, mWM);
7870 const auto& range =
7871 aGridItem.mArea.LineRangeForAxis(subgridBAxisInGridWM);
7872 cbSize.BSize(subgridWM) =
7873 range.ToLength(uts->mTrackPlans[LogicalAxis::Block]);
7874 }
7875 return cbSize.ConvertTo(wm, subgridWM);
7876 }
7877
7878 return LogicalSize(wm, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
7879 }
7880
7881 // Get row size and column size for the grid area occupied by aGridItem.
7882 const nscoord colSize = mCols.mCanResolveLineRangeSize
7883 ? mCols.ResolveSize(aGridItem.mArea.mCols)
7884 : NS_UNCONSTRAINEDSIZE;
7885 const nscoord rowSize = mRows.mCanResolveLineRangeSize
7886 ? mRows.ResolveSize(aGridItem.mArea.mRows)
7887 : NS_UNCONSTRAINEDSIZE;
7888 return !wm.IsOrthogonalTo(mWM) ? LogicalSize(wm, colSize, rowSize)
7889 : LogicalSize(wm, rowSize, colSize);
7890}
7891
7892LogicalRect nsGridContainerFrame::GridReflowInput::ContainingBlockFor(
7893 const GridArea& aArea) const {
7894 nscoord i, b, iSize, bSize;
7895 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"
, 7895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea.mCols.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 7895); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7896 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"
, 7896); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aArea.mRows.Extent() > 0"
") (" "grid items cover at least one track" ")"); do { MOZ_CrashSequence
(__null, 7896); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7897 aArea.mCols.ToPositionAndLength(mCols.mSizes, &i, &iSize);
7898 aArea.mRows.ToPositionAndLength(mRows.mSizes, &b, &bSize);
7899 return LogicalRect(mWM, i, b, iSize, bSize);
7900}
7901
7902LogicalRect nsGridContainerFrame::GridReflowInput::ContainingBlockForAbsPos(
7903 const GridArea& aArea, const LogicalPoint& aGridOrigin,
7904 const LogicalRect& aGridCB) const {
7905 nscoord i = aGridCB.IStart(mWM);
7906 nscoord b = aGridCB.BStart(mWM);
7907 nscoord iSize = aGridCB.ISize(mWM);
7908 nscoord bSize = aGridCB.BSize(mWM);
7909 aArea.mCols.ToPositionAndLengthForAbsPos(mCols, aGridOrigin.I(mWM), &i,
7910 &iSize);
7911 aArea.mRows.ToPositionAndLengthForAbsPos(mRows, aGridOrigin.B(mWM), &b,
7912 &bSize);
7913 return LogicalRect(mWM, i, b, iSize, bSize);
7914}
7915
7916void nsGridContainerFrame::GridReflowInput::AlignJustifyContentInMasonryAxis(
7917 nscoord aMasonryBoxSize, nscoord aContentBoxSize) {
7918 if (aContentBoxSize == NS_UNCONSTRAINEDSIZE) {
7919 aContentBoxSize = aMasonryBoxSize;
7920 }
7921 auto& masonryAxisTracks = mRows.mIsMasonry ? mRows : mCols;
7922 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"
, 7923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7923); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7923 "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"
, 7923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7923); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7924 const auto masonryAxis = masonryAxisTracks.mAxis;
7925 const auto contentAlignment = mGridStyle->UsedContentAlignment(masonryAxis);
7926 if (contentAlignment.primary == StyleAlignFlags::NORMAL ||
7927 contentAlignment.primary == StyleAlignFlags::STRETCH) {
7928 // Stretch the "masonry box" to the full content box if it's smaller.
7929 nscoord cbSize = std::max(aMasonryBoxSize, aContentBoxSize);
7930 for (auto& sz : masonryAxisTracks.mSizes) {
7931 sz.mBase = cbSize;
7932 }
7933 return;
7934 }
7935
7936 // Save our current track sizes; replace them with one track sized to
7937 // the masonry box and align that within our content box.
7938 auto savedTrackSizes(std::move(masonryAxisTracks.mSizes));
7939 masonryAxisTracks.mSizes.AppendElement(savedTrackSizes[0]);
7940 masonryAxisTracks.mSizes[0].mBase = aMasonryBoxSize;
7941 masonryAxisTracks.AlignJustifyContent(mGridStyle, contentAlignment, mWM,
7942 aContentBoxSize, false);
7943 nscoord masonryBoxOffset = masonryAxisTracks.mSizes[0].mPosition;
7944 // Restore the original track sizes...
7945 masonryAxisTracks.mSizes = std::move(savedTrackSizes);
7946 // ...then reposition and resize all of them to the aligned result.
7947 for (auto& sz : masonryAxisTracks.mSizes) {
7948 sz.mPosition = masonryBoxOffset;
7949 sz.mBase = aMasonryBoxSize;
7950 }
7951}
7952
7953// XXX This function was gutted when the 'align-tracks' and 'justify-tracks'
7954// properties were removed in
7955// https://bugzilla.mozilla.org/show_bug.cgi?id=1900195
7956// Possibly the current design of the Masonry code doesn't make much sense now
7957// without those properties, or at the very least this function should be
7958// renamed?
7959//
7960// Note: this is called after all items have been positioned/reflowed.
7961// The masonry-axis tracks have the size of the "masonry box" at this point
7962// and are positioned according to 'align/justify-content'.
7963void nsGridContainerFrame::GridReflowInput::AlignJustifyTracksInMasonryAxis(
7964 const LogicalSize& aContentSize, const nsSize& aContainerSize) {
7965 auto& masonryAxisTracks = mRows.mIsMasonry ? mRows : mCols;
7966 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"
, 7967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7967 "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"
, 7967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisTracks.mSizes.Length() == 2"
") (" "unexpected masonry axis tracks" ")"); do { MOZ_CrashSequence
(__null, 7967); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7968 // The offset to the "masonry box" from our content-box start edge.
7969 const nscoord masonryBoxOffset = masonryAxisTracks.mSizes[0].mPosition;
7970 if (masonryBoxOffset == 0) {
7971 return;
7972 }
7973
7974 const auto masonryAxis = masonryAxisTracks.mAxis;
7975 auto gridAxis = GetOrthogonalAxis(masonryAxis);
7976 auto& gridAxisTracks = TracksFor(gridAxis);
7977 auto wm = mWM;
7978
7979 for (auto i : IntegerRange(gridAxisTracks.mSizes.Length())) {
7980 // TODO move placeholders too
7981 auto delta = masonryBoxOffset;
7982 LogicalPoint logicalDelta(wm);
7983 logicalDelta.Pos(masonryAxis, wm) = delta;
7984 for (const auto& item : mGridItems) {
7985 if (item.mArea.LineRangeForAxis(gridAxis).mStart != i) {
7986 continue;
7987 }
7988 item.mFrame->MovePositionBy(wm, logicalDelta);
7989 }
7990 }
7991}
7992
7993/**
7994 * Return a Fragmentainer object if we have a fragmentainer frame in our
7995 * ancestor chain of containing block (CB) reflow inputs. We'll only
7996 * continue traversing the ancestor chain as long as the CBs have
7997 * the same writing-mode and have overflow:visible.
7998 */
7999Maybe<nsGridContainerFrame::Fragmentainer>
8000nsGridContainerFrame::GetNearestFragmentainer(
8001 const GridReflowInput& aGridRI) const {
8002 Maybe<nsGridContainerFrame::Fragmentainer> data;
8003 const ReflowInput* gridRI = aGridRI.mReflowInput;
8004 if (!gridRI->IsInFragmentedContext()) {
8005 return data;
8006 }
8007 WritingMode wm = aGridRI.mWM;
8008 const ReflowInput* cbRI = gridRI->mCBReflowInput;
8009 for (; cbRI; cbRI = cbRI->mCBReflowInput) {
8010 ScrollContainerFrame* sf = do_QueryFrame(cbRI->mFrame);
8011 if (sf) {
8012 break;
8013 }
8014 if (wm.IsOrthogonalTo(cbRI->GetWritingMode())) {
8015 break;
8016 }
8017 LayoutFrameType frameType = cbRI->mFrame->Type();
8018 if ((frameType == LayoutFrameType::Canvas &&
8019 PresContext()->IsPaginated()) ||
8020 frameType == LayoutFrameType::ColumnSet) {
8021 data.emplace();
8022 data->mIsTopOfPage = gridRI->mFlags.mIsTopOfPage;
8023 if (gridRI->AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
8024 data->mToFragmentainerEnd = aGridRI.mFragBStart +
8025 gridRI->AvailableBSize() -
8026 aGridRI.mBorderPadding.BStart(wm);
8027 } else {
8028 // This occurs when nsColumnSetFrame reflows its last column in
8029 // unconstrained available block-size.
8030 data->mToFragmentainerEnd = NS_UNCONSTRAINEDSIZE;
8031 }
8032 const auto numRows = aGridRI.mRows.mSizes.Length();
8033 data->mCanBreakAtStart =
8034 numRows > 0 && aGridRI.mRows.mSizes[0].mPosition > 0;
8035 nscoord bSize = gridRI->ComputedBSize();
8036 data->mIsAutoBSize = bSize == NS_UNCONSTRAINEDSIZE;
8037 if (data->mIsAutoBSize) {
8038 bSize = gridRI->ComputedMinBSize();
8039 } else {
8040 bSize = gridRI->ApplyMinMaxBSize(bSize);
8041 }
8042 nscoord gridEnd =
8043 aGridRI.mRows.GridLineEdge(numRows, GridLineSide::BeforeGridGap);
8044 data->mCanBreakAtEnd = bSize > gridEnd && bSize > aGridRI.mFragBStart;
8045 break;
8046 }
8047 }
8048 return data;
8049}
8050
8051void nsGridContainerFrame::ReflowInFlowChild(
8052 nsIFrame* aChild, const GridItemInfo* aGridItemInfo, nsSize aContainerSize,
8053 const Maybe<nscoord>& aStretchBSize, const Fragmentainer* aFragmentainer,
8054 const GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8055 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus) {
8056 nsPresContext* pc = PresContext();
8057 ComputedStyle* containerSC = Style();
8058 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
8059 const bool isGridItem = !!aGridItemInfo;
8060 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", 8060)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "isGridItem == !aChild->IsPlaceholderFrame()"
")"); do { MOZ_CrashSequence(__null, 8060); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8061 LogicalRect cb(wm);
8062 WritingMode childWM = aChild->GetWritingMode();
8063 bool isConstrainedBSize = false;
8064 nscoord toFragmentainerEnd;
8065 // The part of the child's grid area that's in previous container fragments.
8066 nscoord consumedGridAreaBSize = 0;
8067 if (MOZ_LIKELY(isGridItem)(__builtin_expect(!!(isGridItem), 1))) {
8068 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"
, 8068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridItemInfo->mFrame == aChild"
")"); do { MOZ_CrashSequence(__null, 8068); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8069 const GridArea& area = aGridItemInfo->mArea;
8070 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", 8070)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "area.IsDefinite()"
")"); do { MOZ_CrashSequence(__null, 8070); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8071 cb = aGridRI.ContainingBlockFor(area);
8072 if (aFragmentainer && !wm.IsOrthogonalTo(childWM)) {
8073 // |gridAreaBOffset| is the offset of the child's grid area in this
8074 // container fragment (if negative, that distance is the child CB size
8075 // consumed in previous container fragments). Note that cb.BStart
8076 // (initially) and aState.mFragBStart are in "global" grid coordinates
8077 // (like all track positions).
8078 nscoord gridAreaBOffset = cb.BStart(wm) - aGridRI.mFragBStart;
8079 consumedGridAreaBSize = std::max(0, -gridAreaBOffset);
8080 cb.BStart(wm) = std::max(0, gridAreaBOffset);
8081 if (aFragmentainer->mToFragmentainerEnd != NS_UNCONSTRAINEDSIZE) {
8082 toFragmentainerEnd = aFragmentainer->mToFragmentainerEnd -
8083 aGridRI.mFragBStart - cb.BStart(wm);
8084 toFragmentainerEnd = std::max(toFragmentainerEnd, 0);
8085 isConstrainedBSize = true;
8086 }
8087 }
8088 cb += aContentArea.Origin(wm);
8089 aGridRI.mRows.AlignBaselineSubtree(*aGridItemInfo);
8090 aGridRI.mCols.AlignBaselineSubtree(*aGridItemInfo);
8091 // Setup [align|justify]-content:[last ]baseline related frame properties.
8092 // These are added to the padding in SizeComputationInput::InitOffsets.
8093 // (a negative value signals the value is for 'last baseline' and should be
8094 // added to the (logical) end padding)
8095 typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
8096 auto SetProp = [aGridItemInfo, aChild](LogicalAxis aGridAxis, Prop aProp) {
8097 auto state = aGridItemInfo->mState[aGridAxis];
8098 auto baselineAdjust = (state & ItemState::eContentBaseline)
8099 ? aGridItemInfo->mBaselineOffset[aGridAxis]
8100 : nscoord(0);
8101 if (baselineAdjust < nscoord(0)) {
8102 // This happens when the subtree overflows its track.
8103 // XXX spec issue? it's unclear how to handle this.
8104 baselineAdjust = nscoord(0);
8105 } else if (state & ItemState::eLastBaseline) {
8106 // FIXME: We're not setting the ItemState::eEndSideBaseline flag any
8107 // more as the new baseline sharing group calculation handles most of
8108 // the cases we need. For non-masonry grids this flag was always set
8109 // for LAST_BASELINE items, so we're just mimicking that behavior here.
8110 // That said, masonry grids might not work 100% any more..
8111 baselineAdjust = -baselineAdjust;
8112 }
8113 if (baselineAdjust != nscoord(0)) {
8114 aChild->SetProperty(aProp, baselineAdjust);
8115 } else {
8116 aChild->RemoveProperty(aProp);
8117 }
8118 };
8119 const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
8120 SetProp(LogicalAxis::Block,
8121 isOrthogonal ? IBaselinePadProperty() : BBaselinePadProperty());
8122 SetProp(LogicalAxis::Inline,
8123 isOrthogonal ? BBaselinePadProperty() : IBaselinePadProperty());
8124 } else {
8125 // By convention, for frames that perform CSS Box Alignment, we position
8126 // placeholder children at the start corner of their alignment container,
8127 // and in this case that's usually the grid's content-box.
8128 // ("Usually" - the exception is when the grid *also* forms the
8129 // abs.pos. containing block. In that case, the alignment container isn't
8130 // the content-box -- it's some grid area instead. But that case doesn't
8131 // require any special handling here, because we handle it later using a
8132 // special flag (ReflowInput::InitFlag::StaticPosIsCBOrigin) which will make
8133 // us ignore the placeholder's position entirely.)
8134 cb = aContentArea;
8135 aChild->AddStateBits(PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN);
8136 }
8137
8138 LogicalSize reflowSize(cb.Size(wm));
8139 if (isConstrainedBSize) {
8140 reflowSize.BSize(wm) = toFragmentainerEnd;
8141 }
8142 LogicalSize childCBSize = reflowSize.ConvertTo(childWM, wm);
8143
8144 // Setup the ClampMarginBoxMinSize reflow flags and property, if needed.
8145 ComputeSizeFlags csFlags;
8146 if (aGridItemInfo) {
8147 const auto childIAxisInWM = childWM.ConvertAxisTo(LogicalAxis::Inline, wm);
8148 // Clamp during reflow if we're stretching in that axis.
8149 if (GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
8150 if (aGridItemInfo->mState[childIAxisInWM] &
8151 ItemState::eClampMarginBoxMinSize) {
8152 csFlags += ComputeSizeFlag::IClampMarginBoxMinSize;
8153 }
8154 } else {
8155 csFlags += ComputeSizeFlag::ShrinkWrap;
8156 }
8157
8158 const auto childBAxisInWM = GetOrthogonalAxis(childIAxisInWM);
8159 if (GridItemShouldStretch(aChild, LogicalAxis::Block) &&
8160 aGridItemInfo->mState[childBAxisInWM] &
8161 ItemState::eClampMarginBoxMinSize) {
8162 csFlags += ComputeSizeFlag::BClampMarginBoxMinSize;
8163 aChild->SetProperty(BClampMarginBoxMinSizeProperty(),
8164 childCBSize.BSize(childWM));
8165 } else {
8166 aChild->RemoveProperty(BClampMarginBoxMinSizeProperty());
8167 }
8168
8169 if ((aGridItemInfo->mState[childIAxisInWM] &
8170 ItemState::eContentBasedAutoMinSize)) {
8171 csFlags += ComputeSizeFlag::IApplyAutoMinSize;
8172 }
8173 }
8174
8175 if (!isConstrainedBSize) {
8176 childCBSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
8177 }
8178 LogicalSize percentBasis(cb.Size(wm).ConvertTo(childWM, wm));
8179 ReflowInput childRI(pc, *aGridRI.mReflowInput, aChild, childCBSize,
8180 Some(percentBasis), {}, {}, csFlags);
8181 childRI.mFlags.mIsTopOfPage =
8182 aFragmentainer ? aFragmentainer->mIsTopOfPage : false;
8183
8184 // FIXME (perf): It would be faster to do this only if the previous reflow of
8185 // the child was a measuring reflow, and only if the child does some of the
8186 // things that are affected by ComputeSizeFlag::IsGridMeasuringReflow.
8187 childRI.SetBResize(true);
8188 childRI.SetBResizeForPercentages(true);
8189
8190 // If the child is stretching in its block axis, and we might be fragmenting
8191 // it in that axis, then setup a frame property to tell
8192 // nsBlockFrame::ComputeFinalSize the size.
8193 if (isConstrainedBSize && !wm.IsOrthogonalTo(childWM)) {
8194 const bool stretch =
8195 childRI.mStylePosition
8196 ->BSize(childWM, AnchorPosResolutionParams::From(&childRI))
8197 ->IsAuto() &&
8198 GridItemShouldStretch(aChild, LogicalAxis::Block);
8199 if (stretch) {
8200 aChild->SetProperty(FragStretchBSizeProperty(), *aStretchBSize);
8201 } else {
8202 aChild->RemoveProperty(FragStretchBSizeProperty());
8203 }
8204 }
8205
8206 // We need the width of the child before we can correctly convert
8207 // the writing-mode of its origin, so we reflow at (0, 0) using a dummy
8208 // aContainerSize, and then pass the correct position to FinishReflowChild.
8209 ReflowOutput childSize(childRI);
8210 const nsSize dummyContainerSize;
8211
8212 ReflowChild(aChild, pc, childSize, childRI, childWM, LogicalPoint(childWM),
8213 dummyContainerSize, ReflowChildFlags::Default, aStatus);
8214
8215 // childPos here initially represents the position that the child would have
8216 // (expressed as an istart,bstart corner *in its own writing-mode*) if it
8217 // were placed at the cb origin:
8218 LogicalPoint childPos = cb.Origin(wm).ConvertRectOriginTo(
8219 childWM, wm, childSize.PhysicalSize(), aContainerSize);
8220
8221 // Apply align/justify-self and reflow again if that affects the size.
8222 if (MOZ_LIKELY(isGridItem)(__builtin_expect(!!(isGridItem), 1))) {
8223 LogicalSize size = childSize.Size(childWM); // from the ReflowChild()
8224 auto applyItemSelfAlignment = [&](LogicalAxis aAxis, nscoord aCBSize) {
8225 auto align =
8226 childRI.mStylePosition->UsedSelfAlignment(aAxis, containerSC);
8227 auto state = aGridItemInfo->mState[aAxis];
8228 AlignJustifyFlags flags;
8229 if (IsMasonry(aAxis)) {
8230 // In a masonry axis, we inhibit applying 'stretch' and auto-margins
8231 // here since AlignJustifyTracksInMasonryAxis deals with that.
8232 // The only other {align,justify}-{self,content} values that have an
8233 // effect are '[last] baseline', the rest behave as 'start'.
8234 if (MOZ_LIKELY(!(state & ItemState::eSelfBaseline))(__builtin_expect(!!(!(state & ItemState::eSelfBaseline))
, 1))
) {
8235 align = {StyleAlignFlags::START};
8236 } else {
8237 auto group = (state & ItemState::eFirstBaseline)
8238 ? BaselineSharingGroup::First
8239 : BaselineSharingGroup::Last;
8240 auto itemStart = aGridItemInfo->mArea.LineRangeForAxis(aAxis).mStart;
8241 aCBSize = aGridRI.TracksFor(aAxis)
8242 .mSizes[itemStart]
8243 .mBaselineSubtreeSize[group];
8244 }
8245 flags += AlignJustifyFlag::IgnoreAutoMargins;
8246 } else if (state & ItemState::eContentBaseline) {
8247 align = {(state & ItemState::eFirstBaseline)
8248 ? StyleAlignFlags::SELF_START
8249 : StyleAlignFlags::SELF_END};
8250 }
8251 if (aAxis == LogicalAxis::Block) {
8252 AlignSelf(*aGridItemInfo, align, aCBSize, wm, childRI, size, flags,
8253 &childPos);
8254 } else {
8255 JustifySelf(*aGridItemInfo, align, aCBSize, wm, childRI, size, flags,
8256 &childPos);
8257 }
8258 };
8259 if (aStatus.IsComplete()) {
8260 applyItemSelfAlignment(LogicalAxis::Block,
8261 cb.BSize(wm) - consumedGridAreaBSize);
8262 }
8263 applyItemSelfAlignment(LogicalAxis::Inline, cb.ISize(wm));
8264 } // else, AbsoluteContainingBlock.cpp will handle align/justify-self.
8265
8266 FinishReflowChild(aChild, pc, childSize, &childRI, childWM, childPos,
8267 aContainerSize, ReflowChildFlags::ApplyRelativePositioning);
8268 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, aChild);
8269}
8270
8271nscoord nsGridContainerFrame::ReflowInFragmentainer(
8272 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8273 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
8274 Fragmentainer& aFragmentainer, const nsSize& aContainerSize) {
8275 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", 8275)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 8275); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8276 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", 8276)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mReflowInput"
")"); do { MOZ_CrashSequence(__null, 8276); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8277
8278 // Collect our grid items and sort them in row order. Collect placeholders
8279 // and put them in a separate array.
8280 nsTArray<const GridItemInfo*> sortedItems(aGridRI.mGridItems.Length());
8281 nsTArray<nsIFrame*> placeholders(aGridRI.mAbsPosItems.Length());
8282 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
8283 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
8284 nsIFrame* child = *aGridRI.mIter;
8285 if (!child->IsPlaceholderFrame()) {
8286 const GridItemInfo* info = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
8287 sortedItems.AppendElement(info);
8288 } else {
8289 placeholders.AppendElement(child);
8290 }
8291 }
8292 // NOTE: We don't need stable_sort here, except in Masonry layout. There are
8293 // no dependencies on having content order between items on the same row in
8294 // the code below in the non-Masonry case.
8295 if (IsMasonry()) {
8296 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8297 GridItemInfo::IsStartRowLessThan);
8298 } else {
8299 std::sort(sortedItems.begin(), sortedItems.end(),
8300 GridItemInfo::IsStartRowLessThan);
8301 }
8302
8303 // Reflow our placeholder children; they must all be complete.
8304 for (auto child : placeholders) {
8305 nsReflowStatus childStatus;
8306 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(),
8307 &aFragmentainer, aGridRI, aContentArea, aDesiredSize,
8308 childStatus);
8309 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", 8310
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "nsPlaceholderFrame should never need to be fragmented"
")"); do { MOZ_CrashSequence(__null, 8310); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8310 "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", 8310
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "nsPlaceholderFrame should never need to be fragmented"
")"); do { MOZ_CrashSequence(__null, 8310); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8311 }
8312
8313 // The available size for children - we'll set this to the edge of the last
8314 // row in most cases below, but for now use the full size.
8315 nscoord childAvailableSize = aFragmentainer.mToFragmentainerEnd;
8316 const uint32_t startRow = aGridRI.mStartRow;
8317 const uint32_t numRows = aGridRI.mRows.mSizes.Length();
8318 bool isBDBClone = aGridRI.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
8319 StyleBoxDecorationBreak::Clone;
8320 nscoord bpBEnd = aGridRI.mBorderPadding.BEnd(aGridRI.mWM);
8321
8322 // Set |endRow| to the first row that doesn't fit.
8323 uint32_t endRow = numRows;
8324 if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8325 for (uint32_t row = startRow; row < numRows; ++row) {
8326 auto& sz = aGridRI.mRows.mSizes[row];
8327 const nscoord bEnd = sz.mPosition + sz.mBase;
8328 nscoord remainingAvailableSize = childAvailableSize - bEnd;
8329 if (remainingAvailableSize < 0 ||
8330 (isBDBClone && remainingAvailableSize < bpBEnd)) {
8331 endRow = row;
8332 break;
8333 }
8334 }
8335 }
8336
8337 // Check for forced breaks on the items if available block-size for children
8338 // is constrained. That is, ignore forced breaks if available block-size for
8339 // children is unconstrained since our parent expected us to be fully
8340 // complete.
8341 bool isForcedBreak = false;
8342 const bool avoidBreakInside = ShouldAvoidBreakInside(*aGridRI.mReflowInput);
8343 if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8344 const bool isTopOfPage = aFragmentainer.mIsTopOfPage;
8345 for (const GridItemInfo* info : sortedItems) {
8346 uint32_t itemStartRow = info->mArea.mRows.mStart;
8347 if (itemStartRow == endRow) {
8348 break;
8349 }
8350 const auto* disp = info->mFrame->StyleDisplay();
8351 if (disp->BreakBefore()) {
8352 // Propagate break-before on the first row to the container unless we're
8353 // already at top-of-page.
8354 if ((itemStartRow == 0 && !isTopOfPage) || avoidBreakInside) {
8355 aStatus.SetInlineLineBreakBeforeAndReset();
8356 return aGridRI.mFragBStart;
8357 }
8358 if ((itemStartRow > startRow ||
8359 (itemStartRow == startRow && !isTopOfPage)) &&
8360 itemStartRow < endRow) {
8361 endRow = itemStartRow;
8362 isForcedBreak = true;
8363 // reset any BREAK_AFTER we found on an earlier item
8364 aStatus.Reset();
8365 break; // we're done since the items are sorted in row order
8366 }
8367 }
8368 uint32_t itemEndRow = info->mArea.mRows.mEnd;
8369 if (disp->BreakAfter()) {
8370 if (itemEndRow != numRows) {
8371 if (itemEndRow > startRow && itemEndRow < endRow) {
8372 endRow = itemEndRow;
8373 isForcedBreak = true;
8374 // No "break;" here since later items with break-after may have
8375 // a shorter span.
8376 }
8377 } else {
8378 // Propagate break-after on the last row to the container, we may
8379 // still find a break-before on this row though (and reset aStatus).
8380 aStatus.SetInlineLineBreakAfter(); // tentative
8381 }
8382 }
8383 }
8384
8385 // Consume at least one row in each fragment until we have consumed them
8386 // all. Except for the first row if there's a break opportunity before it.
8387 if (startRow == endRow && startRow != numRows &&
8388 (startRow != 0 || !aFragmentainer.mCanBreakAtStart)) {
8389 ++endRow;
8390 }
8391
8392 // Honor break-inside:avoid if we can't fit all rows.
8393 if (avoidBreakInside && endRow < numRows) {
8394 aStatus.SetInlineLineBreakBeforeAndReset();
8395 return aGridRI.mFragBStart;
8396 }
8397 }
8398
8399 // Calculate the block-size including this fragment.
8400 nscoord bEndRow =
8401 aGridRI.mRows.GridLineEdge(endRow, GridLineSide::BeforeGridGap);
8402 nscoord bSize;
8403 if (aFragmentainer.mIsAutoBSize) {
8404 // We only apply min-bsize once all rows are complete (when bsize is auto).
8405 if (endRow < numRows) {
8406 bSize = bEndRow;
8407 auto clampedBSize = ClampToCSSMaxBSize(bSize, aGridRI.mReflowInput);
8408 if (MOZ_UNLIKELY(clampedBSize != bSize)(__builtin_expect(!!(clampedBSize != bSize), 0))) {
8409 // We apply max-bsize in all fragments though.
8410 bSize = clampedBSize;
8411 } else if (!isBDBClone) {
8412 // The max-bsize won't make this fragment COMPLETE, so the block-end
8413 // border will be in a later fragment.
8414 bpBEnd = 0;
8415 }
8416 } else {
8417 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(bEndRow);
8418 }
8419 } else {
8420 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(
8421 aGridRI.mReflowInput->ComputedBSize());
8422 }
8423
8424 // Check for overflow and set aStatus INCOMPLETE if so. Note that we should
8425 // not overflow an unconstrained available block-size.
8426 const bool overflow = childAvailableSize != NS_UNCONSTRAINEDSIZE &&
8427 bSize + bpBEnd > childAvailableSize;
8428 if (overflow) {
8429 if (avoidBreakInside) {
8430 aStatus.SetInlineLineBreakBeforeAndReset();
8431 return aGridRI.mFragBStart;
8432 }
8433 bool breakAfterLastRow = endRow == numRows && aFragmentainer.mCanBreakAtEnd;
8434 if (breakAfterLastRow) {
8435 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"
, 8435); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bEndRow < bSize"
") (" "bogus aFragmentainer.mCanBreakAtEnd" ")"); do { MOZ_CrashSequence
(__null, 8435); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8436 nscoord availableSize = childAvailableSize;
8437 if (isBDBClone) {
8438 availableSize -= bpBEnd;
8439 }
8440 // Pretend we have at least 1px available size, otherwise we'll never make
8441 // progress in consuming our bSize.
8442 availableSize =
8443 std::max(availableSize, aGridRI.mFragBStart + AppUnitsPerCSSPixel());
8444 // Fill the fragmentainer, but not more than our desired block-size and
8445 // at least to the size of the last row (even if that overflows).
8446 nscoord newBSize = std::min(bSize, availableSize);
8447 newBSize = std::max(newBSize, bEndRow);
8448 // If it's just the border+padding that is overflowing and we have
8449 // box-decoration-break:clone then we are technically COMPLETE. There's
8450 // no point in creating another zero-bsize fragment in this case.
8451 if (newBSize < bSize || !isBDBClone) {
8452 aStatus.SetIncomplete();
8453 }
8454 bSize = newBSize;
8455 } else if (bSize <= bEndRow && startRow + 1 < endRow) {
8456 if (endRow == numRows) {
8457 // We have more than one row in this fragment, so we can break before
8458 // the last row instead.
8459 --endRow;
8460 bEndRow =
8461 aGridRI.mRows.GridLineEdge(endRow, GridLineSide::BeforeGridGap);
8462 bSize = bEndRow;
8463 if (aFragmentainer.mIsAutoBSize) {
8464 bSize = ClampToCSSMaxBSize(bSize, aGridRI.mReflowInput);
8465 }
8466 }
8467 aStatus.SetIncomplete();
8468 } else if (endRow < numRows) {
8469 bSize = ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8470 } // else - no break opportunities.
8471 } else {
8472 // Even though our block-size fits we need to honor forced breaks, or if
8473 // a row doesn't fit in an auto-sized container (unless it's constrained
8474 // by a max-bsize which make us overflow-incomplete).
8475 if (endRow < numRows &&
8476 (isForcedBreak || (aFragmentainer.mIsAutoBSize && bEndRow == bSize))) {
8477 bSize = ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8478 }
8479 }
8480
8481 // If we can't fit all rows then we're at least overflow-incomplete.
8482 if (endRow < numRows) {
8483 childAvailableSize = bEndRow;
8484 if (aStatus.IsComplete()) {
8485 aStatus.SetOverflowIncomplete();
8486 aStatus.SetNextInFlowNeedsReflow();
8487 }
8488 } else if (childAvailableSize != NS_UNCONSTRAINEDSIZE) {
8489 // Children always have the full size of the rows in this fragment.
8490 childAvailableSize = std::max(childAvailableSize, bEndRow);
8491 }
8492
8493 return ReflowRowsInFragmentainer(aGridRI, aContentArea, aDesiredSize, aStatus,
8494 aFragmentainer, aContainerSize, sortedItems,
8495 startRow, endRow, bSize, childAvailableSize);
8496}
8497
8498nscoord nsGridContainerFrame::ReflowRowsInFragmentainer(
8499 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
8500 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
8501 Fragmentainer& aFragmentainer, const nsSize& aContainerSize,
8502 const nsTArray<const GridItemInfo*>& aSortedItems, uint32_t aStartRow,
8503 uint32_t aEndRow, nscoord aBSize, nscoord aAvailableSize) {
8504 FrameHashtable pushedItems;
8505 FrameHashtable incompleteItems;
8506 FrameHashtable overflowIncompleteItems;
8507 Maybe<nsTArray<nscoord>> masonryAxisPos;
8508 const auto rowCount = aGridRI.mRows.mSizes.Length();
8509 nscoord masonryAxisGap = 0;
8510 const auto wm = aGridRI.mWM;
8511 const bool isColMasonry = IsColMasonry();
8512 if (isColMasonry) {
8513 for (auto& sz : aGridRI.mCols.mSizes) {
8514 sz.mPosition = 0;
8515 }
8516 masonryAxisGap = nsLayoutUtils::ResolveGapToLength(
8517 aGridRI.mGridStyle->mColumnGap, aContentArea.ISize(wm));
8518 aGridRI.mCols.mGridGap = masonryAxisGap;
8519 masonryAxisPos.emplace(rowCount);
8520 masonryAxisPos->SetLength(rowCount);
8521 PodZero(masonryAxisPos->Elements(), rowCount);
8522 }
8523 bool isBDBClone = aGridRI.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
8524 StyleBoxDecorationBreak::Clone;
8525 bool didGrowRow = false;
8526 // As we walk across rows, we track whether the current row is at the top
8527 // of its grid-fragment, to help decide whether we can break before it. When
8528 // this function starts, our row is at the top of the current fragment if:
8529 // - we're starting with a nonzero row (i.e. we're a continuation)
8530 // OR:
8531 // - we're starting with the first row, & we're not allowed to break before
8532 // it (which makes it effectively at the top of its grid-fragment).
8533 bool isRowTopOfPage = aStartRow != 0 || !aFragmentainer.mCanBreakAtStart;
8534 const bool isStartRowTopOfPage = isRowTopOfPage;
8535 // Save our full available size for later.
8536 const nscoord gridAvailableSize = aFragmentainer.mToFragmentainerEnd;
8537 // Propagate the constrained size to our children.
8538 aFragmentainer.mToFragmentainerEnd = aAvailableSize;
8539 // Reflow the items in row order up to |aEndRow| and push items after that.
8540 uint32_t row = 0;
8541 // |i| is intentionally signed, so we can set it to -1 to restart the loop.
8542 for (int32_t i = 0, len = aSortedItems.Length(); i < len; ++i) {
8543 const GridItemInfo* const info = aSortedItems[i];
8544 nsIFrame* child = info->mFrame;
8545 row = info->mArea.mRows.mStart;
8546 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"
, 8547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
") (" "unexpected child start row" ")"); do { MOZ_CrashSequence
(__null, 8547); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8547 "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"
, 8547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow"
") (" "unexpected child start row" ")"); do { MOZ_CrashSequence
(__null, 8547); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8548 if (row >= aEndRow) {
8549 pushedItems.Insert(child);
8550 continue;
8551 }
8552
8553 bool rowCanGrow = false;
8554 nscoord maxRowSize = 0;
8555 if (row >= aStartRow) {
8556 if (row > aStartRow) {
8557 isRowTopOfPage = false;
8558 }
8559 // Can we grow this row? Only consider span=1 items per spec...
8560 rowCanGrow = !didGrowRow && info->mArea.mRows.Extent() == 1;
8561 if (rowCanGrow) {
8562 auto& sz = aGridRI.mRows.mSizes[row];
8563 // and only min-/max-content rows or flex rows in an auto-sized
8564 // container
8565 rowCanGrow = (sz.mState & TrackSize::eMinOrMaxContentMinSizing) ||
8566 ((sz.mState & TrackSize::eFlexMaxSizing) &&
8567 aFragmentainer.mIsAutoBSize);
8568 if (rowCanGrow) {
8569 if (isBDBClone) {
8570 maxRowSize = gridAvailableSize - aGridRI.mBorderPadding.BEnd(wm);
8571 } else {
8572 maxRowSize = gridAvailableSize;
8573 }
8574 maxRowSize -= sz.mPosition;
8575 // ...and only if there is space for it to grow.
8576 rowCanGrow = maxRowSize > sz.mBase;
8577 }
8578 }
8579 }
8580
8581 if (isColMasonry) {
8582 const auto& cols = info->mArea.mCols;
8583 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", 8583)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(cols.mStart == 0 || cols.mStart == 1) && cols.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 8583); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8584 aGridRI.mCols.mSizes[cols.mStart].mPosition = masonryAxisPos.ref()[row];
8585 }
8586
8587 // aFragmentainer.mIsTopOfPage is propagated to the child reflow input.
8588 // When it's false the child may request InlineBreak::Before. We set it
8589 // to false when the row is growable (as determined in the CSS Grid
8590 // Fragmentation spec) and there is a non-zero space between it and the
8591 // fragmentainer end (that can be used to grow it). If the child reports
8592 // a forced break in this case, we grow this row to fill the fragment and
8593 // restart the loop. We also restart the loop with |aEndRow = row|
8594 // (but without growing any row) for a InlineBreak::Before child if it spans
8595 // beyond the last row in this fragment. This is to avoid fragmenting it.
8596 // We only restart the loop once.
8597 aFragmentainer.mIsTopOfPage = isRowTopOfPage && !rowCanGrow;
8598 nsReflowStatus childStatus;
8599 // Pass along how much to stretch this fragment, in case it's needed.
8600 nscoord bSize =
8601 aGridRI.mRows.GridLineEdge(std::min(aEndRow, info->mArea.mRows.mEnd),
8602 GridLineSide::BeforeGridGap) -
8603 aGridRI.mRows.GridLineEdge(std::max(aStartRow, row),
8604 GridLineSide::AfterGridGap);
8605 ReflowInFlowChild(child, info, aContainerSize, Some(bSize), &aFragmentainer,
8606 aGridRI, aContentArea, aDesiredSize, childStatus);
8607 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"
, 8609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8609); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8608 !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"
, 8609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8609); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8609 "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"
, 8609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsInlineBreakBefore() || !childStatus.IsFullyComplete() || !child->GetNextInFlow()"
") (" "fully-complete reflow should destroy any NIFs" ")"); do
{ MOZ_CrashSequence(__null, 8609); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8610
8611 if (childStatus.IsInlineBreakBefore()) {
8612 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", 8614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8613 !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", 8614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8614 "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", 8614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never report InlineBreak::Before status"
")"); do { MOZ_CrashSequence(__null, 8614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8615 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", 8616
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFragmentainer.mIsTopOfPage"
") (" "got IsInlineBreakBefore() at top of page" ")"); do { MOZ_CrashSequence
(__null, 8616); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8616 "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", 8616
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFragmentainer.mIsTopOfPage"
") (" "got IsInlineBreakBefore() at top of page" ")"); do { MOZ_CrashSequence
(__null, 8616); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8617 if (!didGrowRow) {
8618 if (rowCanGrow) {
8619 // Grow this row and restart with the next row as |aEndRow|.
8620 aGridRI.mRows.ResizeRow(row, maxRowSize);
8621 if (aGridRI.mSharedGridData) {
8622 aGridRI.mSharedGridData->mRows.ResizeRow(row, maxRowSize);
8623 }
8624 didGrowRow = true;
8625 aEndRow = row + 1; // growing this row makes the next one not fit
8626 i = -1; // i == 0 after the next loop increment
8627 isRowTopOfPage = isStartRowTopOfPage;
8628 overflowIncompleteItems.Clear();
8629 incompleteItems.Clear();
8630 nscoord bEndRow =
8631 aGridRI.mRows.GridLineEdge(aEndRow, GridLineSide::BeforeGridGap);
8632 aFragmentainer.mToFragmentainerEnd = bEndRow;
8633 if (aFragmentainer.mIsAutoBSize) {
8634 aBSize =
8635 ClampToCSSMaxBSize(bEndRow, aGridRI.mReflowInput, &aStatus);
8636 } else if (aStatus.IsIncomplete()) {
8637 aBSize = aGridRI.mReflowInput->ApplyMinMaxBSize(
8638 aGridRI.mReflowInput->ComputedBSize());
8639 aBSize = std::min(bEndRow, aBSize);
8640 }
8641 continue;
8642 }
8643
8644 if (!isRowTopOfPage) {
8645 // We can break before this row - restart with it as the new end row.
8646 aEndRow = row;
8647 aBSize =
8648 aGridRI.mRows.GridLineEdge(aEndRow, GridLineSide::BeforeGridGap);
8649 i = -1; // i == 0 after the next loop increment
8650 isRowTopOfPage = isStartRowTopOfPage;
8651 overflowIncompleteItems.Clear();
8652 incompleteItems.Clear();
8653 aStatus.SetIncomplete();
8654 continue;
8655 }
8656 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"
, 8656); MOZ_PretendNoReturn(); } while (0)
;
8657 childStatus.Reset();
8658 } else {
8659 // We got InlineBreak::Before again after growing the row - this can
8660 // happen if the child isn't splittable, e.g. some form controls.
8661 childStatus.Reset();
8662 if (child->GetNextInFlow()) {
8663 // The child already has a fragment, so we know it's splittable.
8664 childStatus.SetIncomplete();
8665 } // else, report that it's complete
8666 }
8667 } else if (childStatus.IsInlineBreakAfter()) {
8668 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"
, 8668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected child reflow status" ")"
); do { MOZ_CrashSequence(__null, 8668); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8669 }
8670
8671 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", 8672
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childStatus.IsInlineBreakBefore()"
") (" "should've handled InlineBreak::Before above" ")"); do
{ MOZ_CrashSequence(__null, 8672); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8672 "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", 8672
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childStatus.IsInlineBreakBefore()"
") (" "should've handled InlineBreak::Before above" ")"); do
{ MOZ_CrashSequence(__null, 8672); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8673 if (childStatus.IsIncomplete()) {
8674 incompleteItems.Insert(child);
8675 } else if (!childStatus.IsFullyComplete()) {
8676 overflowIncompleteItems.Insert(child);
8677 }
8678 if (isColMasonry) {
8679 auto childWM = child->GetWritingMode();
8680 const auto childAxis = wm.ConvertAxisTo(LogicalAxis::Inline, childWM);
8681 auto normalPos = child->GetLogicalNormalPosition(wm, aContainerSize);
8682 auto sz =
8683 childAxis == LogicalAxis::Block ? child->BSize() : child->ISize();
8684 auto pos = normalPos.Pos(LogicalAxis::Inline, wm) + sz +
8685 child->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
8686 masonryAxisPos.ref()[row] =
8687 pos + masonryAxisGap - aContentArea.Start(LogicalAxis::Inline, wm);
8688 }
8689 }
8690
8691 // Record a break before |aEndRow|.
8692 aGridRI.mNextFragmentStartRow = aEndRow;
8693 if (aEndRow < rowCount) {
8694 aGridRI.mRows.BreakBeforeRow(aEndRow);
8695 if (aGridRI.mSharedGridData) {
8696 aGridRI.mSharedGridData->mRows.BreakBeforeRow(aEndRow);
8697 }
8698 }
8699
8700 const bool childrenMoved = PushIncompleteChildren(
8701 pushedItems, incompleteItems, overflowIncompleteItems);
8702 if (childrenMoved && aStatus.IsComplete()) {
8703 aStatus.SetOverflowIncomplete();
8704 aStatus.SetNextInFlowNeedsReflow();
8705 }
8706 if (!pushedItems.IsEmpty()) {
8707 AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
8708 // NOTE since we messed with our child list here, we intentionally
8709 // make aState.mIter invalid to avoid any use of it after this point.
8710 aGridRI.mIter.Invalidate();
8711 }
8712 if (!incompleteItems.IsEmpty()) {
8713 // NOTE since we messed with our child list here, we intentionally
8714 // make aState.mIter invalid to avoid any use of it after this point.
8715 aGridRI.mIter.Invalidate();
8716 }
8717
8718 if (isColMasonry) {
8719 nscoord maxSize = 0;
8720 for (auto pos : masonryAxisPos.ref()) {
8721 maxSize = std::max(maxSize, pos);
8722 }
8723 maxSize = std::max(nscoord(0), maxSize - masonryAxisGap);
8724 aGridRI.AlignJustifyContentInMasonryAxis(maxSize, aContentArea.ISize(wm));
8725 }
8726
8727 return aBSize;
8728}
8729
8730// Here's a brief overview of how Masonry layout is implemented:
8731// We setup two synthetic tracks in the Masonry axis so that the Reflow code
8732// can treat it the same as for normal grid layout. The first track is
8733// fixed (during item placement/layout) at the content box start and contains
8734// the start items for each grid-axis track. The second track contains
8735// all other items and is moved to the position where we want to position
8736// the currently laid out item (like a sliding window as we place items).
8737// Once item layout is done, the tracks are resized to be the size of
8738// the "masonry box", which is the offset from the content box start to
8739// the margin-box end of the item that is furthest away (this happens in
8740// AlignJustifyContentInMasonryAxis() called at the end of this method).
8741// This is to prepare for AlignJustifyTracksInMasonryAxis, which is called
8742// later by our caller.
8743// Both tracks store their first-/last-baseline group offsets as usual.
8744// The first-baseline of the start track, and the last-baseline of the last
8745// track (if they exist) are exported as the grid container's baselines, or
8746// we fall back to picking an item's baseline (all this is per normal grid
8747// layout). There's a slight difference in which items belongs to which
8748// group though - see InitializeItemBaselinesInMasonryAxis for details.
8749// This method returns the "masonry box" size (in the masonry axis).
8750nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aGridRI,
8751 const LogicalRect& aContentArea,
8752 SizingConstraint aConstraint,
8753 ReflowOutput& aDesiredSize,
8754 nsReflowStatus& aStatus,
8755 Fragmentainer* aFragmentainer,
8756 const nsSize& aContainerSize) {
8757 using BaselineAlignmentSet = Tracks::BaselineAlignmentSet;
8758
8759 auto recordAutoPlacement = [this, &aGridRI](GridItemInfo* aItem,
8760 LogicalAxis aGridAxis) {
8761 // When we're auto-placing an item in a continuation we need to record
8762 // the placement in mSharedGridData.
8763 if (MOZ_UNLIKELY(aGridRI.mSharedGridData && GetPrevInFlow())(__builtin_expect(!!(aGridRI.mSharedGridData && GetPrevInFlow
()), 0))
&&
8764 (aItem->mState[aGridAxis] & ItemState::eAutoPlacement)) {
8765 auto* child = aItem->mFrame;
8766 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"
, 8767); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never be auto-placed" ")"); do {
MOZ_CrashSequence(__null, 8767); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8767 "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"
, 8767); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!child->GetPrevInFlow()"
") (" "continuations should never be auto-placed" ")"); do {
MOZ_CrashSequence(__null, 8767); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8768 for (auto& sharedItem : aGridRI.mSharedGridData->mGridItems) {
8769 if (sharedItem.mFrame == child) {
8770 sharedItem.mArea.LineRangeForAxis(aGridAxis) =
8771 aItem->mArea.LineRangeForAxis(aGridAxis);
8772 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", 8772)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "sharedItem.mState[aGridAxis] & ItemState::eAutoPlacement"
")"); do { MOZ_CrashSequence(__null, 8772); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8773 sharedItem.mState[aGridAxis] &= ~ItemState::eAutoPlacement;
8774 break;
8775 }
8776 }
8777 }
8778 aItem->mState[aGridAxis] &= ~ItemState::eAutoPlacement;
8779 };
8780
8781 // Collect our grid items and sort them in grid order.
8782 nsTArray<GridItemInfo*> sortedItems(aGridRI.mGridItems.Length());
8783 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
8784 size_t absposIndex = 0;
8785 const LogicalAxis masonryAxis =
8786 IsMasonry(LogicalAxis::Block) ? LogicalAxis::Block : LogicalAxis::Inline;
8787 const auto wm = aGridRI.mWM;
8788 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
8789 nsIFrame* child = *aGridRI.mIter;
8790 if (MOZ_LIKELY(!child->IsPlaceholderFrame())(__builtin_expect(!!(!child->IsPlaceholderFrame()), 1))) {
8791 GridItemInfo* item = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
8792 sortedItems.AppendElement(item);
8793 } else if (aConstraint == SizingConstraint::NoConstraint) {
8794 // (we only collect placeholders in the NoConstraint case since they
8795 // don't affect intrinsic sizing in any way)
8796 GridItemInfo* item = nullptr;
8797 auto* ph = static_cast<nsPlaceholderFrame*>(child);
8798 auto* oof = ph->GetOutOfFlowFrame();
8799 if (oof && oof->GetParent() == this) {
8800 item = &aGridRI.mAbsPosItems[absposIndex++];
8801 MOZ_RELEASE_ASSERT(item->mFrame == oof)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item->mFrame == oof)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(item->mFrame == oof))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("item->mFrame == oof"
, "./../../../layout/generic/nsGridContainerFrame.cpp", 8801)
; AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "item->mFrame == oof"
")"); do { MOZ_CrashSequence(__null, 8801); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8802 auto masonryStart = item->mArea.LineRangeForAxis(masonryAxis).mStart;
8803 // If the item was placed by the author at line 1 (masonryStart == 0)
8804 // then include it to be placed at the masonry-box start. If it's
8805 // auto-placed and has an `auto` inset value in the masonry axis then
8806 // we include it to be placed after the last grid item with the same
8807 // grid-axis start track.
8808 // XXXmats this is all a bit experimental at this point, pending a spec
8809 const auto masonrySide = masonryAxis == LogicalAxis::Inline
8810 ? LogicalSide::IStart
8811 : LogicalSide::BStart;
8812 if (masonryStart == 0 ||
8813 (masonryStart == kAutoLine &&
8814 item->mFrame->StylePosition()
8815 ->GetAnchorResolvedInset(
8816 masonrySide, wm,
8817 AnchorPosOffsetResolutionParams::UseCBFrameSize(
8818 AnchorPosResolutionParams::From(item->mFrame)))
8819 ->IsAuto())) {
8820 sortedItems.AppendElement(item);
8821 } else {
8822 item = nullptr;
8823 }
8824 }
8825 if (!item) {
8826 // It wasn't included above - just reflow it and be done with it.
8827 nsReflowStatus childStatus;
8828 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(), nullptr,
8829 aGridRI, aContentArea, aDesiredSize, childStatus);
8830 }
8831 }
8832 }
8833 const auto masonryAutoFlow = aGridRI.mGridStyle->mMasonryAutoFlow;
8834 const bool definiteFirst =
8835 masonryAutoFlow.order == StyleMasonryItemOrder::DefiniteFirst;
8836 if (masonryAxis == LogicalAxis::Block) {
8837 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8838 definiteFirst ? GridItemInfo::RowMasonryDefiniteFirst
8839 : GridItemInfo::RowMasonryOrdered);
8840 } else {
8841 std::stable_sort(sortedItems.begin(), sortedItems.end(),
8842 definiteFirst ? GridItemInfo::ColMasonryDefiniteFirst
8843 : GridItemInfo::ColMasonryOrdered);
8844 }
8845
8846 FrameHashtable pushedItems;
8847 FrameHashtable incompleteItems;
8848 FrameHashtable overflowIncompleteItems;
8849 nscoord toFragmentainerEnd = nscoord_MAX;
8850 nscoord fragStartPos = aGridRI.mFragBStart;
8851 const bool avoidBreakInside =
8852 aFragmentainer && ShouldAvoidBreakInside(*aGridRI.mReflowInput);
8853 const bool isTopOfPageAtStart =
8854 aFragmentainer && aFragmentainer->mIsTopOfPage;
8855 if (aFragmentainer) {
8856 toFragmentainerEnd = std::max(0, aFragmentainer->mToFragmentainerEnd);
8857 }
8858 const LogicalAxis gridAxis = GetOrthogonalAxis(masonryAxis);
8859 const auto gridAxisTrackCount = aGridRI.TracksFor(gridAxis).mSizes.Length();
8860 auto& masonryTracks = aGridRI.TracksFor(masonryAxis);
8861 auto& masonrySizes = masonryTracks.mSizes;
8862 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", 8862)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonrySizes.Length() == 2"
")"); do { MOZ_CrashSequence(__null, 8862); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8863 for (auto& sz : masonrySizes) {
8864 sz.mPosition = fragStartPos;
8865 }
8866 // The current running position for each grid-axis track where the next item
8867 // should be positioned. When an item is placed we'll update the tracks it
8868 // spans to the end of its margin box + 'gap'.
8869 nsTArray<nscoord> currentPos(gridAxisTrackCount);
8870 currentPos.SetLength(gridAxisTrackCount);
8871 for (auto& sz : currentPos) {
8872 sz = fragStartPos;
8873 }
8874 nsTArray<nscoord> lastPos(currentPos.Clone());
8875 nsTArray<GridItemInfo*> lastItems(gridAxisTrackCount);
8876 lastItems.SetLength(gridAxisTrackCount);
8877 PodZero(lastItems.Elements(), gridAxisTrackCount);
8878 const nscoord gap = nsLayoutUtils::ResolveGapToLength(
8879 masonryAxis == LogicalAxis::Block ? aGridRI.mGridStyle->mRowGap
8880 : aGridRI.mGridStyle->mColumnGap,
8881 masonryTracks.mContentBoxSize);
8882 masonryTracks.mGridGap = gap;
8883 uint32_t cursor = 0;
8884 const auto containerToMasonryBoxOffset =
8885 fragStartPos - aContentArea.Start(masonryAxis, wm);
8886 const bool isPack = masonryAutoFlow.placement == StyleMasonryPlacement::Pack;
8887 bool didAlignStartAlignedFirstItems = false;
8888
8889 // Return true if any of the lastItems in aRange are baseline-aligned in
8890 // the masonry axis.
8891 auto lastItemHasBaselineAlignment = [&](const LineRange& aRange) {
8892 for (auto i : aRange.Range()) {
8893 if (auto* child = lastItems[i] ? lastItems[i]->mFrame : nullptr) {
8894 const auto& pos = child->StylePosition();
8895 auto selfAlignment = pos->UsedSelfAlignment(masonryAxis, this->Style());
8896 if (selfAlignment == StyleAlignFlags::BASELINE ||
8897 selfAlignment == StyleAlignFlags::LAST_BASELINE) {
8898 return true;
8899 }
8900 auto childAxis = masonryAxis;
8901 if (child->GetWritingMode().IsOrthogonalTo(wm)) {
8902 childAxis = gridAxis;
8903 }
8904 auto contentAlignment = pos->UsedContentAlignment(childAxis).primary;
8905 if (contentAlignment == StyleAlignFlags::BASELINE ||
8906 contentAlignment == StyleAlignFlags::LAST_BASELINE) {
8907 return true;
8908 }
8909 }
8910 }
8911 return false;
8912 };
8913
8914 // Resolve aItem's placement, unless it's definite already. Return its
8915 // masonry axis position with that placement.
8916 auto placeItem = [&](GridItemInfo* aItem) -> nscoord {
8917 auto& masonryAxisRange = aItem->mArea.LineRangeForAxis(masonryAxis);
8918 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", 8918
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "masonryAxisRange.mStart != 0"
") (" "item placement is already final" ")"); do { MOZ_CrashSequence
(__null, 8918); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8919 auto& gridAxisRange = aItem->mArea.LineRangeForAxis(gridAxis);
8920 bool isAutoPlaced = aItem->mState[gridAxis] & ItemState::eAutoPlacement;
8921 uint32_t start = isAutoPlaced ? 0 : gridAxisRange.mStart;
8922 if (isAutoPlaced && !isPack) {
8923 start = cursor;
8924 isAutoPlaced = false;
8925 }
8926 const uint32_t extent = gridAxisRange.Extent();
8927 if (start + extent > gridAxisTrackCount) {
8928 // Note that this will only happen to auto-placed items since the grid is
8929 // always wide enough to fit other items.
8930 start = 0;
8931 }
8932 // This keeps track of the smallest `maxPosForRange` value that
8933 // we discover in the loop below:
8934 nscoord minPos = nscoord_MAX;
8935 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"
, 8935); AnnotateMozCrashReason("MOZ_ASSERT" "(" "extent <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 8935); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8936 const uint32_t iEnd = gridAxisTrackCount + 1 - extent;
8937 for (uint32_t i = start; i < iEnd; ++i) {
8938 // Find the max `currentPos` value for the tracks that we would span
8939 // if we were to use `i` as our start track:
8940 nscoord maxPosForRange = 0;
8941 for (auto j = i, jEnd = j + extent; j < jEnd; ++j) {
8942 maxPosForRange = std::max(currentPos[j], maxPosForRange);
8943 }
8944 if (maxPosForRange < minPos) {
8945 minPos = maxPosForRange;
8946 start = i;
8947 }
8948 if (!isAutoPlaced) {
8949 break;
8950 }
8951 }
8952 gridAxisRange.mStart = start;
8953 gridAxisRange.mEnd = start + extent;
8954 bool isFirstItem = true;
8955 for (uint32_t i : gridAxisRange.Range()) {
8956 if (lastItems[i]) {
8957 isFirstItem = false;
8958 break;
8959 }
8960 }
8961 // If this is the first item in its spanned grid tracks, then place it in
8962 // the first masonry track. Otherwise, place it in the second masonry track.
8963 masonryAxisRange.mStart = isFirstItem ? 0 : 1;
8964 masonryAxisRange.mEnd = masonryAxisRange.mStart + 1;
8965 return minPos;
8966 };
8967
8968 // Handle the resulting reflow status after reflowing aItem.
8969 // This may set aStatus to BreakBefore which the caller is expected
8970 // to handle by returning from MasonryLayout.
8971 // @return true if this item should consume all remaining space
8972 auto handleChildStatus = [&](GridItemInfo* aItem,
8973 const nsReflowStatus& aChildStatus) {
8974 bool result = false;
8975 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
8976 auto* child = aItem->mFrame;
8977 if (!aChildStatus.IsComplete() || aChildStatus.IsInlineBreakBefore() ||
8978 aChildStatus.IsInlineBreakAfter() ||
8979 child->StyleDisplay()->BreakAfter()) {
8980 if (!isTopOfPageAtStart && avoidBreakInside) {
8981 aStatus.SetInlineLineBreakBeforeAndReset();
8982 return result;
8983 }
8984 result = true;
8985 }
8986 if (aChildStatus.IsInlineBreakBefore()) {
8987 aStatus.SetIncomplete();
8988 pushedItems.Insert(child);
8989 } else if (aChildStatus.IsIncomplete()) {
8990 recordAutoPlacement(aItem, gridAxis);
8991 aStatus.SetIncomplete();
8992 incompleteItems.Insert(child);
8993 } else if (!aChildStatus.IsFullyComplete()) {
8994 recordAutoPlacement(aItem, gridAxis);
8995 overflowIncompleteItems.Insert(child);
8996 }
8997 }
8998 return result;
8999 };
9000
9001 // @return the distance from the masonry-box start to the end of the margin-
9002 // box of aChild
9003 auto offsetToMarginBoxEnd = [&](nsIFrame* aChild) {
9004 auto childWM = aChild->GetWritingMode();
9005 auto childAxis = !childWM.IsOrthogonalTo(wm) ? masonryAxis : gridAxis;
9006 auto normalPos = aChild->GetLogicalNormalPosition(wm, aContainerSize);
9007 auto sz =
9008 childAxis == LogicalAxis::Block ? aChild->BSize() : aChild->ISize();
9009 return containerToMasonryBoxOffset + normalPos.Pos(masonryAxis, wm) + sz +
9010 aChild->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
9011 };
9012
9013 // Apply baseline alignment to items belonging to the given set.
9014 nsTArray<Tracks::ItemBaselineData> firstBaselineItems;
9015 nsTArray<Tracks::ItemBaselineData> lastBaselineItems;
9016 auto applyBaselineAlignment = [&](BaselineAlignmentSet aSet) {
9017 firstBaselineItems.ClearAndRetainStorage();
9018 lastBaselineItems.ClearAndRetainStorage();
9019 masonryTracks.InitializeItemBaselinesInMasonryAxis(
9020 aGridRI, aGridRI.mGridItems, aSet, aContainerSize, currentPos,
9021 firstBaselineItems, lastBaselineItems);
9022
9023 bool didBaselineAdjustment = false;
9024 nsTArray<Tracks::ItemBaselineData>* baselineItems[] = {&firstBaselineItems,
9025 &lastBaselineItems};
9026 for (const auto* items : baselineItems) {
9027 for (const auto& data : *items) {
9028 GridItemInfo* item = data.mGridItem;
9029 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", 9029)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item->mState[masonryAxis] & ItemState::eIsBaselineAligned)"
")"); do { MOZ_CrashSequence(__null, 9029); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9030 nscoord baselineOffset = item->mBaselineOffset[masonryAxis];
9031 if (baselineOffset == nscoord(0)) {
9032 continue; // no adjustment needed for this item
9033 }
9034 didBaselineAdjustment = true;
9035 auto* child = item->mFrame;
9036 auto masonryAxisStart =
9037 item->mArea.LineRangeForAxis(masonryAxis).mStart;
9038 auto gridAxisRange = item->mArea.LineRangeForAxis(gridAxis);
9039 masonrySizes[masonryAxisStart].mPosition =
9040 aSet.mItemSet == BaselineAlignmentSet::LastItems
9041 ? lastPos[gridAxisRange.mStart]
9042 : fragStartPos;
9043 bool consumeAllSpace = false;
9044 const auto state = item->mState[masonryAxis];
9045 if ((state & ItemState::eContentBaseline) ||
9046 MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9047 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9048 aFragmentainer->mIsTopOfPage =
9049 isTopOfPageAtStart &&
9050 masonrySizes[masonryAxisStart].mPosition == fragStartPos;
9051 }
9052 nsReflowStatus childStatus;
9053 ReflowInFlowChild(child, item, aContainerSize, Nothing(),
9054 aFragmentainer, aGridRI, aContentArea, aDesiredSize,
9055 childStatus);
9056 consumeAllSpace = handleChildStatus(item, childStatus);
9057 if (aStatus.IsInlineBreakBefore()) {
9058 return false;
9059 }
9060 } else if (!(state & ItemState::eEndSideBaseline)) {
9061 // `align/justify-self` baselines on the start side can be handled by
9062 // just moving the frame (except in a fragmentainer in which case we
9063 // reflow it above instead since it might make it INCOMPLETE).
9064 LogicalPoint logicalDelta(wm);
9065 logicalDelta.Pos(masonryAxis, wm) = baselineOffset;
9066 child->MovePositionBy(wm, logicalDelta);
9067 }
9068 if ((state & ItemState::eEndSideBaseline) && !consumeAllSpace) {
9069 // Account for an end-side baseline adjustment.
9070 for (uint32_t i : gridAxisRange.Range()) {
9071 currentPos[i] += baselineOffset;
9072 }
9073 } else {
9074 nscoord pos = consumeAllSpace ? toFragmentainerEnd
9075 : offsetToMarginBoxEnd(child);
9076 pos += gap;
9077 for (uint32_t i : gridAxisRange.Range()) {
9078 currentPos[i] = pos;
9079 }
9080 }
9081 }
9082 }
9083 return didBaselineAdjustment;
9084 };
9085
9086 // Place and reflow items. We'll use two fake tracks in the masonry axis.
9087 // The first contains items that were placed there by the regular grid
9088 // placement algo (PlaceGridItems) and we may add some items here if there
9089 // are still empty slots. The second track contains all other items.
9090 // Both tracks always have the size of the content box in the masonry axis.
9091 // The position of the first track is always at the start. The position
9092 // of the second track is updated as we go to a position where we want
9093 // the current item to be positioned.
9094 for (GridItemInfo* item : sortedItems) {
9095 auto* child = item->mFrame;
9096 auto& masonryRange = item->mArea.LineRangeForAxis(masonryAxis);
9097 auto& gridRange = item->mArea.LineRangeForAxis(gridAxis);
9098 nsReflowStatus childStatus;
9099 if (MOZ_UNLIKELY(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))(__builtin_expect(!!(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)), 0))
) {
9100 auto contentArea = aContentArea;
9101 nscoord pos = nscoord_MAX;
9102 // XXXmats take mEnd into consideration...
9103 if (gridRange.mStart == kAutoLine) {
9104 for (auto p : currentPos) {
9105 pos = std::min(p, pos);
9106 }
9107 } else if (gridRange.mStart < currentPos.Length()) {
9108 pos = currentPos[gridRange.mStart];
9109 } else if (currentPos.Length() > 0) {
9110 pos = currentPos.LastElement();
9111 }
9112 if (pos == nscoord_MAX) {
9113 pos = nscoord(0);
9114 }
9115 contentArea.Start(masonryAxis, wm) = pos;
9116 child = child->GetPlaceholderFrame();
9117 ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(), nullptr,
9118 aGridRI, contentArea, aDesiredSize, childStatus);
9119 } else {
9120 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", 9121)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 9121); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9121 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", 9121)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRange.Extent() > 0 && gridRange.Extent() <= gridAxisTrackCount"
")"); do { MOZ_CrashSequence(__null, 9121); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9122 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", 9123)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 9123); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9123 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", 9123)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "(masonryRange.mStart == 0 || masonryRange.mStart == 1) && masonryRange.Extent() == 1"
")"); do { MOZ_CrashSequence(__null, 9123); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9124 if (masonryRange.mStart != 0) {
9125 masonrySizes[1].mPosition = placeItem(item);
9126 }
9127
9128 // If this is the first item NOT in the first track and if any of
9129 // the grid-axis tracks we span has a baseline-aligned item then we
9130 // need to do that baseline alignment now since it may affect
9131 // the placement of this and later items.
9132 if (!didAlignStartAlignedFirstItems &&
9133 aConstraint == SizingConstraint::NoConstraint &&
9134 masonryRange.mStart != 0 && lastItemHasBaselineAlignment(gridRange)) {
9135 didAlignStartAlignedFirstItems = true;
9136 if (applyBaselineAlignment({BaselineAlignmentSet::FirstItems,
9137 BaselineAlignmentSet::StartStretch})) {
9138 // Baseline alignment resized some items - redo our placement.
9139 masonrySizes[1].mPosition = placeItem(item);
9140 }
9141 if (aStatus.IsInlineBreakBefore()) {
9142 return fragStartPos;
9143 }
9144 }
9145
9146 for (uint32_t i : gridRange.Range()) {
9147 lastItems[i] = item;
9148 }
9149 cursor = gridRange.mEnd;
9150 if (cursor >= gridAxisTrackCount) {
9151 cursor = 0;
9152 }
9153
9154 nscoord pos;
9155 if (aConstraint == SizingConstraint::NoConstraint) {
9156 const auto* disp = child->StyleDisplay();
9157 if (MOZ_UNLIKELY(aFragmentainer)(__builtin_expect(!!(aFragmentainer), 0))) {
9158 aFragmentainer->mIsTopOfPage =
9159 isTopOfPageAtStart &&
9160 masonrySizes[masonryRange.mStart].mPosition == fragStartPos;
9161 if (!aFragmentainer->mIsTopOfPage &&
9162 (disp->BreakBefore() ||
9163 masonrySizes[masonryRange.mStart].mPosition >=
9164 toFragmentainerEnd)) {
9165 childStatus.SetInlineLineBreakBeforeAndReset();
9166 }
9167 }
9168 if (!childStatus.IsInlineBreakBefore()) {
9169 ReflowInFlowChild(child, item, aContainerSize, Nothing(),
9170 aFragmentainer, aGridRI, aContentArea, aDesiredSize,
9171 childStatus);
9172 }
9173 bool consumeAllSpace = handleChildStatus(item, childStatus);
9174 if (aStatus.IsInlineBreakBefore()) {
9175 return fragStartPos;
9176 }
9177 pos =
9178 consumeAllSpace ? toFragmentainerEnd : offsetToMarginBoxEnd(child);
9179 } else {
9180 LogicalSize percentBasis(
9181 aGridRI.PercentageBasisFor(LogicalAxis::Inline, *item));
9182 IntrinsicISizeType type = aConstraint == SizingConstraint::MaxContent
9183 ? IntrinsicISizeType::PrefISize
9184 : IntrinsicISizeType::MinISize;
9185 auto sz = ::ContentContribution(*item, aGridRI, masonryAxis,
9186 percentBasis, type);
9187 pos = sz + masonrySizes[masonryRange.mStart].mPosition;
9188 }
9189 pos += gap;
9190 for (uint32_t i : gridRange.Range()) {
9191 lastPos[i] = currentPos[i];
9192 currentPos[i] = pos;
9193 }
9194 }
9195 }
9196
9197 // Do the remaining baseline alignment sets.
9198 if (aConstraint == SizingConstraint::NoConstraint) {
9199 for (auto*& item : lastItems) {
9200 if (item) {
9201 item->mState[masonryAxis] |= ItemState::eIsLastItemInMasonryTrack;
9202 }
9203 }
9204 BaselineAlignmentSet baselineSets[] = {
9205 {BaselineAlignmentSet::FirstItems, BaselineAlignmentSet::StartStretch},
9206 {BaselineAlignmentSet::FirstItems, BaselineAlignmentSet::EndStretch},
9207 {BaselineAlignmentSet::LastItems, BaselineAlignmentSet::StartStretch},
9208 {BaselineAlignmentSet::LastItems, BaselineAlignmentSet::EndStretch},
9209 };
9210 for (uint32_t i = 0; i < std::size(baselineSets); ++i) {
9211 if (i == 0 && didAlignStartAlignedFirstItems) {
9212 continue;
9213 }
9214 applyBaselineAlignment(baselineSets[i]);
9215 }
9216 }
9217
9218 const bool childrenMoved = PushIncompleteChildren(
9219 pushedItems, incompleteItems, overflowIncompleteItems);
9220 if (childrenMoved && aStatus.IsComplete()) {
9221 aStatus.SetOverflowIncomplete();
9222 aStatus.SetNextInFlowNeedsReflow();
9223 }
9224 if (!pushedItems.IsEmpty()) {
9225 AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
9226 // NOTE since we messed with our child list here, we intentionally
9227 // make aState.mIter invalid to avoid any use of it after this point.
9228 aGridRI.mIter.Invalidate();
9229 }
9230 if (!incompleteItems.IsEmpty()) {
9231 // NOTE since we messed with our child list here, we intentionally
9232 // make aState.mIter invalid to avoid any use of it after this point.
9233 aGridRI.mIter.Invalidate();
9234 }
9235
9236 nscoord masonryBoxSize = 0;
9237 for (auto pos : currentPos) {
9238 masonryBoxSize = std::max(masonryBoxSize, pos);
9239 }
9240 masonryBoxSize = std::max(nscoord(0), masonryBoxSize - gap);
9241 if (aConstraint == SizingConstraint::NoConstraint) {
9242 aGridRI.AlignJustifyContentInMasonryAxis(masonryBoxSize,
9243 masonryTracks.mContentBoxSize);
9244 }
9245 return masonryBoxSize;
9246}
9247
9248nsGridContainerFrame* nsGridContainerFrame::ParentGridContainerForSubgrid()
9249 const {
9250 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"
, 9250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9250); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9251 nsIFrame* p = GetParent();
9252 while (p->GetContent() == GetContent()) {
9253 p = p->GetParent();
9254 }
9255 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"
, 9255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p->IsGridContainerFrame()"
")"); do { MOZ_CrashSequence(__null, 9255); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9256 auto* parent = static_cast<nsGridContainerFrame*>(p);
9257 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"
, 9257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent->HasSubgridItems()"
")"); do { MOZ_CrashSequence(__null, 9257); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9258 return parent;
9259}
9260
9261nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aGridRI,
9262 const LogicalRect& aContentArea,
9263 const nsSize& aContainerSize,
9264 ReflowOutput& aDesiredSize,
9265 nsReflowStatus& aStatus) {
9266 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
9267 nscoord bSize = aContentArea.BSize(wm);
9268 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", 9268)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mReflowInput"
")"); do { MOZ_CrashSequence(__null, 9268); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9269 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"
, 9269); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
MOZ_CrashSequence(__null, 9269); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9270 if (HidesContentForLayout()) {
9271 return bSize;
9272 }
9273
9274 OverflowAreas ocBounds;
9275 nsReflowStatus ocStatus;
9276 if (GetPrevInFlow()) {
9277 ReflowOverflowContainerChildren(PresContext(), *aGridRI.mReflowInput,
9278 ocBounds, ReflowChildFlags::Default,
9279 ocStatus, MergeSortedFrameListsFor);
9280 }
9281
9282 Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aGridRI);
9283 // MasonryLayout() can only handle fragmentation in the masonry-axis,
9284 // so we let ReflowInFragmentainer() deal with grid-axis fragmentation
9285 // in the else-clause below.
9286 if (IsMasonry() && !(IsColMasonry() && fragmentainer.isSome())) {
9287 aGridRI.mInFragmentainer = fragmentainer.isSome();
9288 nscoord sz = MasonryLayout(
9289 aGridRI, aContentArea, SizingConstraint::NoConstraint, aDesiredSize,
9290 aStatus, fragmentainer.ptrOr(nullptr), aContainerSize);
9291 if (IsRowMasonry()) {
9292 bSize = aGridRI.mReflowInput->ComputedBSize();
9293 if (bSize == NS_UNCONSTRAINEDSIZE) {
9294 bSize = aGridRI.mReflowInput->ApplyMinMaxBSize(sz);
9295 }
9296 }
9297 } else if (MOZ_UNLIKELY(fragmentainer.isSome())(__builtin_expect(!!(fragmentainer.isSome()), 0))) {
9298 if (IsColMasonry() && !GetPrevInFlow()) {
9299 // First we do an unconstrained reflow to resolve the item placement
9300 // which is then kept as-is in the constrained reflow below.
9301 MasonryLayout(aGridRI, aContentArea, SizingConstraint::NoConstraint,
9302 aDesiredSize, aStatus, nullptr, aContainerSize);
9303 }
9304 aGridRI.mInFragmentainer = true;
9305 bSize = ReflowInFragmentainer(aGridRI, aContentArea, aDesiredSize, aStatus,
9306 *fragmentainer, aContainerSize);
9307 } else {
9308 aGridRI.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
9309 for (; !aGridRI.mIter.AtEnd(); aGridRI.mIter.Next()) {
9310 nsIFrame* child = *aGridRI.mIter;
9311 const GridItemInfo* info = nullptr;
9312 if (!child->IsPlaceholderFrame()) {
9313 info = &aGridRI.mGridItems[aGridRI.mIter.ItemIndex()];
9314 }
9315 nsReflowStatus childStatus;
9316 ReflowInFlowChild(child, info, aContainerSize, Nothing(), nullptr,
9317 aGridRI, aContentArea, aDesiredSize, childStatus);
9318 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", 9319);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "child should be complete in unconstrained reflow" ")"
); do { MOZ_CrashSequence(__null, 9319); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9319 "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", 9319);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "childStatus.IsComplete()"
") (" "child should be complete in unconstrained reflow" ")"
); do { MOZ_CrashSequence(__null, 9319); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9320 aStatus.MergeCompletionStatusFrom(childStatus);
9321 }
9322 }
9323
9324 // Merge overflow container bounds and status.
9325 aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
9326 aStatus.MergeCompletionStatusFrom(ocStatus);
9327
9328 return bSize;
9329}
9330
9331void nsGridContainerFrame::ReflowAbsoluteChildren(
9332 GridReflowInput& aGridRI, const LogicalRect& aContentArea,
9333 nscoord aContentBSize, ReflowOutput& aDesiredSize,
9334 nsReflowStatus& aStatus) {
9335 WritingMode wm = aGridRI.mReflowInput->GetWritingMode();
9336 auto* absoluteContainer = GetAbsoluteContainingBlock();
9337 // We have prepared the absolute frames in Grid::PlaceGridItems() or in
9338 // GridReflowInput::InitializeForContinuation().
9339 if (!absoluteContainer || !absoluteContainer->HasAbsoluteFrames()) {
9340 return;
9341 }
9342 // 'gridOrigin' is the origin of the grid (the start of the first track),
9343 // with respect to the grid container's padding-box (CB).
9344 LogicalMargin pad(aGridRI.mReflowInput->ComputedLogicalPadding(wm));
9345 const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
9346 const nscoord gridContentBSize =
9347 (aGridRI.mInFragmentainer && !aGridRI.mRows.mSizes.IsEmpty())
9348 ? aGridRI.mRows.GridLineEdge(aGridRI.mRows.mSizes.Length(),
9349 GridLineSide::BeforeGridGap)
9350 : aContentBSize;
9351 const LogicalRect gridCB(wm, 0, 0, aContentArea.ISize(wm) + pad.IStartEnd(wm),
9352 gridContentBSize + pad.BStartEnd(wm));
9353 const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
9354 size_t i = 0;
9355 for (nsIFrame* child : absoluteContainer->GetChildList()) {
9356 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"
, 9356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "i < aGridRI.mAbsPosItems.Length()"
")"); do { MOZ_CrashSequence(__null, 9356); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9357 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", 9357)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGridRI.mAbsPosItems[i].mFrame == child"
")"); do { MOZ_CrashSequence(__null, 9357); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9358 GridArea& area = aGridRI.mAbsPosItems[i].mArea;
9359 LogicalRect itemCB =
9360 aGridRI.ContainingBlockForAbsPos(area, gridOrigin, gridCB);
9361 // AbsoluteContainingBlock::Reflow uses physical coordinates.
9362 nsRect* cb =
9363 child->GetOrCreateDeletableProperty(GridItemContainingBlockRect());
9364 *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize);
9365 ++i;
9366 }
9367 const auto border = aGridRI.mReflowInput->ComputedPhysicalBorder();
9368 const nsPoint borderShift{border.left, border.top};
9369 const nsRect paddingRect(borderShift, gridCBPhysicalSize);
9370 // XXX: To optimize the performance, set the flags only when the CB width
9371 // or height actually changes.
9372 AbsPosReflowFlags flags{
9373 AbsPosReflowFlag::AllowFragmentation, AbsPosReflowFlag::CBWidthChanged,
9374 AbsPosReflowFlag::CBHeightChanged, AbsPosReflowFlag::IsGridContainerCB};
9375 nsReflowStatus absposStatus;
9376 absoluteContainer->Reflow(this, PresContext(), *aGridRI.mReflowInput,
9377 absposStatus, paddingRect, flags,
9378 &aDesiredSize.mOverflowAreas);
9379 aStatus.MergeCompletionStatusFrom(absposStatus);
9380}
9381
9382nscoord nsGridContainerFrame::ComputeBSizeForResolvingRowSizes(
9383 GridReflowInput& aGridRI, nscoord aComputedBSize,
9384 const Maybe<nscoord>& aContainIntrinsicBSize) const {
9385 if (aComputedBSize != NS_UNCONSTRAINEDSIZE) {
9386 // We don't need to apply the min/max constraints to the computed block-size
9387 // because ReflowInput (specifically when computing the block-size in
9388 // nsIFrame::ComputeSize()) has already clamped the block-size.
9389 return aComputedBSize;
9390 }
9391
9392 if (aContainIntrinsicBSize) {
9393 // We have an unconstrained block-size, but we also have a specified
9394 // 'contain-intrinsic-block-size'. We apply the min/max constraints to the
9395 // value, and use that for track sizing.
9396 return aGridRI.mReflowInput->ApplyMinMaxBSize(*aContainIntrinsicBSize);
9397 }
9398
9399 return NS_UNCONSTRAINEDSIZE;
9400}
9401
9402nscoord nsGridContainerFrame::ComputeIntrinsicContentBSize(
9403 const GridReflowInput& aGridRI, nscoord aComputedBSize,
9404 nscoord aBSizeForResolvingRowSizes,
9405 const Maybe<nscoord>& aContainIntrinsicBSize) const {
9406 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", 9409
); 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, 9409); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9407 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", 9409
); 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, 9409); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9408 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", 9409
); 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, 9409); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9409 "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", 9409
); 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, 9409); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9410
9411 if (aComputedBSize == NS_UNCONSTRAINEDSIZE) {
9412 // When we have an unconstrained block-size, the intrinsic content
9413 // block-size would have been determined after we resolved the row sizes the
9414 // first time. Just return that value.
9415 return aBSizeForResolvingRowSizes;
9416 }
9417
9418 if (aContainIntrinsicBSize) {
9419 // We have a specified 'contain-intrinsic-block-size' which we need to
9420 // honor.
9421 return *aContainIntrinsicBSize;
9422 }
9423
9424 if (IsRowMasonry()) {
9425 // There aren't any tracks to derive a block-size from, if we're doing
9426 // masonry rather than forming rows in the block direction.
9427 return aBSizeForResolvingRowSizes;
9428 }
9429
9430 return aGridRI.mRows.TotalTrackSizeWithoutAlignment(this);
9431}
9432
9433void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
9434 ReflowOutput& aDesiredSize,
9435 const ReflowInput& aReflowInput,
9436 nsReflowStatus& aStatus) {
9437 NormalizeChildLists();
9438
9439 if (IsHiddenByContentVisibilityOfInFlowParentForLayout()) {
9440 return;
9441 }
9442
9443 MarkInReflow();
9444 DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame")aPresContext->CountReflows(("nsGridContainerFrame"), (nsIFrame
*)this);
;
9445 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"
, 9445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
MOZ_CrashSequence(__null, 9445); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9446
9447 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);
;
9448
9449 if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
9450 return;
9451 }
9452
9453#ifdef DEBUG1
9454 mDidPushItemsBitMayLie = false;
9455 SanityCheckChildListsBeforeReflow();
9456#endif // DEBUG
9457
9458 for (auto& perAxisBaseline : mBaseline) {
9459 for (auto& baseline : perAxisBaseline) {
9460 baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
9461 }
9462 }
9463
9464 const nsStylePosition* stylePos = aReflowInput.mStylePosition;
9465 auto prevInFlow = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
9466 if (MOZ_LIKELY(!prevInFlow)(__builtin_expect(!!(!prevInFlow), 1))) {
9467 InitImplicitNamedAreas(stylePos);
9468 } else {
9469 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"
, 9471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9471); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9470 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"
, 9471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9471); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9471 "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"
, 9471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevInFlow->HasAnyStateBits(kIsSubgridBits) == HasAnyStateBits(kIsSubgridBits)"
") (" "continuations should have same kIsSubgridBits" ")"); do
{ MOZ_CrashSequence(__null, 9471); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9472 }
9473 GridReflowInput gridRI(this, aReflowInput);
9474 if (gridRI.mIter.ItemsAreAlreadyInOrder()) {
9475 AddStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
9476 } else {
9477 RemoveStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
9478 }
9479 if (gridRI.mIter.AtEnd() || aReflowInput.mStyleDisplay->IsContainLayout()) {
9480 // We have no grid items, or we're layout-contained. So, we have no
9481 // baseline, and our parent should synthesize a baseline if needed.
9482 AddStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
9483 } else {
9484 RemoveStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
9485 }
9486 const nscoord computedBSize = aReflowInput.ComputedBSize();
9487 const nscoord computedISize = aReflowInput.ComputedISize();
9488
9489 // XXX Technically incorrect: 'contain-intrinsic-block-size: none' is
9490 // treated as 0, ignoring our row sizes, when really we should use them but
9491 // *they* should be computed as if we had no children. To be fixed in bug
9492 // 1488878.
9493 const Maybe<nscoord> containIntrinsicBSize =
9494 aReflowInput.mFrame->ContainIntrinsicBSize();
9495 const WritingMode& wm = gridRI.mWM;
9496
9497 nscoord consumedBSize = 0;
9498 nscoord contentBSize = 0;
9499 if (MOZ_LIKELY(!prevInFlow)(__builtin_expect(!!(!prevInFlow), 1))) {
9500 Grid grid;
9501 if (MOZ_LIKELY(!IsSubgrid())(__builtin_expect(!!(!IsSubgrid()), 1))) {
9502 RepeatTrackSizingInput repeatSizing(aReflowInput.ComputedMinSize(),
9503 aReflowInput.ComputedSize(),
9504 aReflowInput.ComputedMaxSize());
9505 grid.PlaceGridItems(gridRI, repeatSizing);
9506 } else {
9507 auto* subgrid = GetProperty(Subgrid::Prop());
9508 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", 9508
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "subgrid" ") (" "an ancestor forgot to call PlaceGridItems?"
")"); do { MOZ_CrashSequence(__null, 9508); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9509 gridRI.mGridItems = subgrid->mGridItems.Clone();
9510 gridRI.mAbsPosItems = subgrid->mAbsPosItems.Clone();
9511 grid.mGridColEnd = subgrid->mGridColEnd;
9512 grid.mGridRowEnd = subgrid->mGridRowEnd;
9513 }
9514
9515 // Resolve the column sizes with the grid container's inline size.
9516 // 12.1.1: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9517 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid, computedISize,
9518 SizingConstraint::NoConstraint);
9519
9520 nscoord bSizeForResolvingRowSizes = ComputeBSizeForResolvingRowSizes(
9521 gridRI, computedBSize, containIntrinsicBSize);
9522
9523 // Resolve the row sizes with the determined bSizeForResolvingRowSizes.
9524 // 12.1.2: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9525 //
9526 // If bSizeForResolvingRowSizes is unconstrained, that's fine. It forces
9527 // percent-valued row sizes to be treated as 'auto', yielding an intrinsic
9528 // content block-size needed later to *actually* resolve percent-valued row
9529 // gaps and row sizes.
9530 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid,
9531 bSizeForResolvingRowSizes,
9532 SizingConstraint::NoConstraint);
9533
9534 // Invalidate the column sizes before re-resolving them.
9535 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Inline);
9536
9537 // Re-resolve the column sizes.
9538 // 12.1.3: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9539 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid, computedISize,
9540 SizingConstraint::NoConstraint);
9541
9542 // If our bSizeForResolvingRowSizes is still indefinite, replace it with
9543 // the sum of the row sizes we just resolved, then re-resolve the row
9544 // sizes against that value. We skip this for masonry, which doesn't need
9545 // two-pass row sizes resolution.
9546 if (bSizeForResolvingRowSizes == NS_UNCONSTRAINEDSIZE && !IsRowMasonry()) {
9547 bSizeForResolvingRowSizes =
9548 std::max(gridRI.mRows.TotalTrackSizeWithoutAlignment(this),
9549 gridRI.mReflowInput->ComputedMinBSize());
9550
9551 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", 9553)
; MOZ_PretendNoReturn(); } } while (0)
9552 "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", 9553)
; MOZ_PretendNoReturn(); } } while (0)
9553 "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", 9553)
; MOZ_PretendNoReturn(); } } while (0)
;
9554
9555 // Invalidate the row sizes before re-resolving them.
9556 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Block);
9557
9558 // Re-resolve the row sizes.
9559 // 12.1.4: https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
9560 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid,
9561 bSizeForResolvingRowSizes,
9562 SizingConstraint::NoConstraint);
9563 }
9564
9565 if (computedBSize == NS_UNCONSTRAINEDSIZE ||
9566 aReflowInput.ShouldApplyAutomaticMinimumOnBlockAxis()) {
9567 // We either have an unconstrained block-size, or we have a definite
9568 // block-size derived from the inline-size (transferred via aspect-ratio)
9569 // and need to apply the automatic content-based minimum sizes on the
9570 // block-axis. In both case, we need to compute the intrinsic
9571 // content block-size.
9572 contentBSize = ComputeIntrinsicContentBSize(gridRI, computedBSize,
9573 bSizeForResolvingRowSizes,
9574 containIntrinsicBSize);
9575 }
9576 } else {
9577 consumedBSize = CalcAndCacheConsumedBSize();
9578 gridRI.InitializeForContinuation(this, consumedBSize);
9579 if (containIntrinsicBSize) {
9580 contentBSize = *containIntrinsicBSize;
9581 } else {
9582 const uint32_t numRows = gridRI.mRows.mSizes.Length();
9583 contentBSize =
9584 gridRI.mRows.GridLineEdge(numRows, GridLineSide::AfterGridGap);
9585 }
9586 }
9587 if (computedBSize == NS_UNCONSTRAINEDSIZE) {
9588 contentBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
9589 } else if (aReflowInput.ShouldApplyAutomaticMinimumOnBlockAxis()) {
9590 contentBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
9591 contentBSize = std::max(contentBSize, computedBSize);
9592 } else {
9593 contentBSize = computedBSize;
9594 }
9595 if (contentBSize != NS_UNCONSTRAINEDSIZE) {
9596 contentBSize = std::max(contentBSize - consumedBSize, 0);
9597 }
9598 auto& bp = gridRI.mBorderPadding;
9599 LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm), computedISize,
9600 contentBSize);
9601
9602 if (!prevInFlow) {
9603 const auto& rowSizes = gridRI.mRows.mSizes;
9604 if (!IsRowSubgrid()) {
9605 if (!gridRI.mRows.mIsMasonry) {
9606 // Apply 'align-content' to the grid.
9607 auto alignment = stylePos->mAlignContent;
9608 gridRI.mRows.AlignJustifyContent(stylePos, alignment, wm, contentBSize,
9609 false);
9610 }
9611 } else {
9612 if (computedBSize == NS_UNCONSTRAINEDSIZE) {
9613 contentBSize = gridRI.mRows.GridLineEdge(rowSizes.Length(),
9614 GridLineSide::BeforeGridGap);
9615 contentArea.BSize(wm) = std::max(contentBSize, nscoord(0));
9616 }
9617 }
9618 // Save the final row sizes for use by subgrids, if needed.
9619 if (HasSubgridItems() || IsSubgrid()) {
9620 StoreUsedTrackSizes(LogicalAxis::Block, rowSizes);
9621 }
9622 }
9623
9624 nsSize containerSize = contentArea.Size(wm).GetPhysicalSize(wm);
9625 bool repositionChildren = false;
9626 if (containerSize.width == NS_UNCONSTRAINEDSIZE && wm.IsVerticalRL()) {
9627 // Note that writing-mode:vertical-rl is the only case where the block
9628 // logical direction progresses in a negative physical direction, and
9629 // therefore block-dir coordinate conversion depends on knowing the width
9630 // of the coordinate space in order to translate between the logical and
9631 // physical origins.
9632 //
9633 // A masonry axis size may be unconstrained, otherwise in a regular grid
9634 // our intrinsic size is always known by now. We'll re-position
9635 // the children below once our size is known.
9636 repositionChildren = true;
9637 containerSize.width = 0;
9638 }
9639 containerSize.width += bp.LeftRight(wm);
9640 containerSize.height += bp.TopBottom(wm);
9641
9642 contentBSize =
9643 ReflowChildren(gridRI, contentArea, containerSize, aDesiredSize, aStatus);
9644 if (Style()->GetPseudoType() == PseudoStyleType::MozScrolledContent) {
9645 // Per spec, the grid area is included in a grid container's scrollable
9646 // overflow region [1], as well as the padding on the end-edge sides that
9647 // would satisfy the requirements of 'place-content: end' alignment [2].
9648 //
9649 // Note that we include the padding from all sides of the grid area, not
9650 // just the end sides; this is fine because the grid area is relative to our
9651 // content-box origin. The inflated bounds won't go beyond our padding-box
9652 // edges on the start sides.
9653 //
9654 // The margin areas of grid item boxes are also included in the scrollable
9655 // overflow region [2].
9656 //
9657 // [1] https://drafts.csswg.org/css-grid-2/#overflow
9658 // [2] https://drafts.csswg.org/css-overflow-3/#scrollable
9659
9660 // Synthesize a grid area covering all columns and rows, and compute its
9661 // rect relative to our border-box.
9662 //
9663 // Note: the grid columns and rows exist only if there is an explicit grid;
9664 // or when an implicit grid is needed to place any grid items. See
9665 // nsGridContainerFrame::Grid::PlaceGridItems().
9666 const auto numCols = static_cast<int32_t>(gridRI.mCols.mSizes.Length());
9667 const auto numRows = static_cast<int32_t>(gridRI.mRows.mSizes.Length());
9668 if (numCols > 0 && numRows > 0) {
9669 const GridArea gridArea(LineRange(0, numCols), LineRange(0, numRows));
9670 const LogicalRect gridAreaRect =
9671 gridRI.ContainingBlockFor(gridArea) +
9672 LogicalPoint(wm, bp.IStart(wm), bp.BStart(wm));
9673
9674 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", 9675)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "bp == aReflowInput.ComputedLogicalPadding(wm)"
") (" "A scrolled inner frame shouldn't have any border!" ")"
); do { MOZ_CrashSequence(__null, 9675); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9675 "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", 9675)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "bp == aReflowInput.ComputedLogicalPadding(wm)"
") (" "A scrolled inner frame shouldn't have any border!" ")"
); do { MOZ_CrashSequence(__null, 9675); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9676 const LogicalMargin& padding = bp;
9677 nsRect physicalGridAreaRectWithPadding =
9678 gridAreaRect.GetPhysicalRect(wm, containerSize);
9679 physicalGridAreaRectWithPadding.Inflate(padding.GetPhysicalMargin(wm));
9680 aDesiredSize.mOverflowAreas.UnionAllWith(physicalGridAreaRectWithPadding);
9681 }
9682
9683 nsRect gridItemMarginBoxBounds;
9684 for (const auto& item : gridRI.mGridItems) {
9685 gridItemMarginBoxBounds =
9686 gridItemMarginBoxBounds.Union(item.mFrame->GetMarginRect());
9687 }
9688 aDesiredSize.mOverflowAreas.UnionAllWith(gridItemMarginBoxBounds);
9689 }
9690 ReflowAbsoluteChildren(gridRI, contentArea, contentBSize, aDesiredSize,
9691 aStatus);
9692 contentBSize = std::max(contentBSize - consumedBSize, 0);
9693
9694 // Skip our block-end border if we're INCOMPLETE.
9695 if (!aStatus.IsComplete() && !gridRI.mSkipSides.BEnd() &&
9696 StyleBorder()->mBoxDecorationBreak != StyleBoxDecorationBreak::Clone) {
9697 bp.BEnd(wm) = nscoord(0);
9698 }
9699
9700 LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
9701 contentBSize + bp.BStartEnd(wm));
9702 aDesiredSize.SetSize(wm, desiredSize);
9703 nsRect frameRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
9704 aDesiredSize.mOverflowAreas.UnionAllWith(frameRect);
9705
9706 if (repositionChildren) {
9707 nsPoint physicalDelta(aDesiredSize.Width() - bp.LeftRight(wm), 0);
9708 for (const auto& item : gridRI.mGridItems) {
9709 auto* child = item.mFrame;
9710 child->MovePositionBy(physicalDelta);
9711 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
9712 }
9713 }
9714
9715 // TODO: fix align-tracks alignment in fragments
9716 if ((IsRowMasonry() && !prevInFlow) || IsColMasonry()) {
9717 gridRI.AlignJustifyTracksInMasonryAxis(contentArea.Size(wm),
9718 aDesiredSize.PhysicalSize());
9719 }
9720
9721 // Convert INCOMPLETE -> OVERFLOW_INCOMPLETE and zero bsize if we're an OC.
9722 if (HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER)) {
9723 if (!aStatus.IsComplete()) {
9724 aStatus.SetOverflowIncomplete();
9725 aStatus.SetNextInFlowNeedsReflow();
9726 }
9727 contentBSize = 0;
9728 desiredSize.BSize(wm) = contentBSize + bp.BStartEnd(wm);
9729 aDesiredSize.SetSize(wm, desiredSize);
9730 }
9731
9732 if (!gridRI.mInFragmentainer) {
9733 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", 9733)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gridRI.mIter.IsValid()"
")"); do { MOZ_CrashSequence(__null, 9733); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9734 auto sz = frameRect.Size();
9735 CalculateBaselines(BaselineSet::eBoth, &gridRI.mIter, &gridRI.mGridItems,
9736 gridRI.mCols, 0, gridRI.mCols.mSizes.Length(), wm, sz,
9737 bp.IStart(wm), bp.IEnd(wm), desiredSize.ISize(wm));
9738 CalculateBaselines(BaselineSet::eBoth, &gridRI.mIter, &gridRI.mGridItems,
9739 gridRI.mRows, 0, gridRI.mRows.mSizes.Length(), wm, sz,
9740 bp.BStart(wm), bp.BEnd(wm), desiredSize.BSize(wm));
9741 } else {
9742 // Only compute 'first baseline' if this fragment contains the first track.
9743 // XXXmats maybe remove this condition? bug 1306499
9744 BaselineSet baselines = BaselineSet::eNone;
9745 if (gridRI.mStartRow == 0 &&
9746 gridRI.mStartRow != gridRI.mNextFragmentStartRow) {
9747 baselines = BaselineSet::eFirst;
9748 }
9749 // Only compute 'last baseline' if this fragment contains the last track.
9750 // XXXmats maybe remove this condition? bug 1306499
9751 uint32_t len = gridRI.mRows.mSizes.Length();
9752 if (gridRI.mStartRow != len && gridRI.mNextFragmentStartRow == len) {
9753 baselines = BaselineSet(baselines | BaselineSet::eLast);
9754 }
9755 Maybe<CSSOrderAwareFrameIterator> iter;
9756 Maybe<nsTArray<GridItemInfo>> gridItems;
9757 if (baselines != BaselineSet::eNone) {
9758 // We need to create a new iterator and GridItemInfo array because we
9759 // might have pushed some children at this point.
9760 // Even if gridRI.mIter is invalid, we can reuse its
9761 // state about order to optimize initialization of the new iterator.
9762 // An ordered child list can't become unordered by pushing frames.
9763 // An unordered list can become ordered in a number of cases, but we
9764 // ignore that here and guess that the child list is still unordered.
9765 // XXX this is O(n^2) in the number of items in this fragment: bug 1306705
9766 using Filter = CSSOrderAwareFrameIterator::ChildFilter;
9767 using Order = CSSOrderAwareFrameIterator::OrderState;
9768 bool ordered = gridRI.mIter.ItemsAreAlreadyInOrder();
9769 auto orderState = ordered ? Order::Ordered : Order::Unordered;
9770 iter.emplace(this, FrameChildListID::Principal, Filter::SkipPlaceholders,
9771 orderState);
9772 gridItems.emplace();
9773 for (; !iter->AtEnd(); iter->Next()) {
9774 auto child = **iter;
9775 for (const auto& info : gridRI.mGridItems) {
9776 if (info.mFrame == child) {
9777 gridItems->AppendElement(info);
9778 }
9779 }
9780 }
9781 }
9782 auto sz = frameRect.Size();
9783 CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
9784 gridRI.mCols, 0, gridRI.mCols.mSizes.Length(), wm, sz,
9785 bp.IStart(wm), bp.IEnd(wm), desiredSize.ISize(wm));
9786 CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
9787 gridRI.mRows, gridRI.mStartRow,
9788 gridRI.mNextFragmentStartRow, wm, sz, bp.BStart(wm),
9789 bp.BEnd(wm), desiredSize.BSize(wm));
9790 }
9791
9792 if (HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO)) {
9793 // This state bit will never be cleared, since reflow can be called
9794 // multiple times in fragmented grids, and it's challenging to scope
9795 // the bit to only that sequence of calls. This is relatively harmless
9796 // since this bit is only set by accessing a ChromeOnly property, and
9797 // therefore can't unduly slow down normal web browsing.
9798
9799 // Clear our GridFragmentInfo property, which might be holding a stale
9800 // dom::Grid object built from previously-computed info. This will
9801 // ensure that the next call to GetGridFragments will create a new one.
9802 if (mozilla::dom::Grid* grid = TakeProperty(GridFragmentInfo())) {
9803 grid->ForgetFrame();
9804 }
9805
9806 // Now that we know column and row sizes and positions, set
9807 // the ComputedGridTrackInfo and related properties
9808
9809 const auto* subgrid = GetProperty(Subgrid::Prop());
9810 const auto* subgridColRange =
9811 subgrid && IsColSubgrid() ? &subgrid->SubgridCols() : nullptr;
9812
9813 LineNameMap colLineNameMap(gridRI.mGridStyle, GetImplicitNamedAreas(),
9814 gridRI.mColFunctions, nullptr, subgridColRange);
9815 uint32_t colTrackCount = gridRI.mCols.mSizes.Length();
9816 nsTArray<nscoord> colTrackPositions(colTrackCount);
9817 nsTArray<nscoord> colTrackSizes(colTrackCount);
9818 nsTArray<uint32_t> colTrackStates(colTrackCount);
9819 nsTArray<bool> colRemovedRepeatTracks(
9820 gridRI.mColFunctions.mRemovedRepeatTracks.Clone());
9821 uint32_t col = 0;
9822 for (const TrackSize& sz : gridRI.mCols.mSizes) {
9823 colTrackPositions.AppendElement(sz.mPosition);
9824 colTrackSizes.AppendElement(sz.mBase);
9825 bool isRepeat = ((col >= gridRI.mColFunctions.mRepeatAutoStart) &&
9826 (col < gridRI.mColFunctions.mRepeatAutoEnd));
9827 colTrackStates.AppendElement(
9828 isRepeat ? (uint32_t)mozilla::dom::GridTrackState::Repeat
9829 : (uint32_t)mozilla::dom::GridTrackState::Static);
9830
9831 col++;
9832 }
9833 // Get the number of explicit tracks first. The order of argument evaluation
9834 // is implementation-defined. We should be OK here because colTrackSizes is
9835 // taken by rvalue, but computing the size first prevents any changes in the
9836 // argument types of the constructor from breaking this.
9837 const uint32_t numColExplicitTracks =
9838 IsColSubgrid() ? colTrackSizes.Length()
9839 : gridRI.mColFunctions.NumExplicitTracks();
9840 ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
9841 gridRI.mColFunctions.mExplicitGridOffset, numColExplicitTracks, 0, col,
9842 std::move(colTrackPositions), std::move(colTrackSizes),
9843 std::move(colTrackStates), std::move(colRemovedRepeatTracks),
9844 gridRI.mColFunctions.mRepeatAutoStart,
9845 colLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
9846 IsColSubgrid(), IsColMasonry());
9847 SetProperty(GridColTrackInfo(), colInfo);
9848
9849 const auto* subgridRowRange =
9850 subgrid && IsRowSubgrid() ? &subgrid->SubgridRows() : nullptr;
9851 LineNameMap rowLineNameMap(gridRI.mGridStyle, GetImplicitNamedAreas(),
9852 gridRI.mRowFunctions, nullptr, subgridRowRange);
9853 uint32_t rowTrackCount = gridRI.mRows.mSizes.Length();
9854 nsTArray<nscoord> rowTrackPositions(rowTrackCount);
9855 nsTArray<nscoord> rowTrackSizes(rowTrackCount);
9856 nsTArray<uint32_t> rowTrackStates(rowTrackCount);
9857 nsTArray<bool> rowRemovedRepeatTracks(
9858 gridRI.mRowFunctions.mRemovedRepeatTracks.Clone());
9859 uint32_t row = 0;
9860 for (const TrackSize& sz : gridRI.mRows.mSizes) {
9861 rowTrackPositions.AppendElement(sz.mPosition);
9862 rowTrackSizes.AppendElement(sz.mBase);
9863 bool isRepeat = ((row >= gridRI.mRowFunctions.mRepeatAutoStart) &&
9864 (row < gridRI.mRowFunctions.mRepeatAutoEnd));
9865 rowTrackStates.AppendElement(
9866 isRepeat ? (uint32_t)mozilla::dom::GridTrackState::Repeat
9867 : (uint32_t)mozilla::dom::GridTrackState::Static);
9868
9869 row++;
9870 }
9871 // Get the number of explicit tracks first. The order of argument evaluation
9872 // is implementation-defined. We should be OK here because colTrackSizes is
9873 // taken by rvalue, but computing the size first prevents any changes in the
9874 // argument types of the constructor from breaking this.
9875 const uint32_t numRowExplicitTracks =
9876 IsRowSubgrid() ? rowTrackSizes.Length()
9877 : gridRI.mRowFunctions.NumExplicitTracks();
9878 // Row info has to accommodate fragmentation of the grid, which may happen
9879 // in later calls to Reflow. For now, presume that no more fragmentation
9880 // will occur.
9881 ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
9882 gridRI.mRowFunctions.mExplicitGridOffset, numRowExplicitTracks,
9883 gridRI.mStartRow, row, std::move(rowTrackPositions),
9884 std::move(rowTrackSizes), std::move(rowTrackStates),
9885 std::move(rowRemovedRepeatTracks),
9886 gridRI.mRowFunctions.mRepeatAutoStart,
9887 rowLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
9888 IsRowSubgrid(), IsRowMasonry());
9889 SetProperty(GridRowTrackInfo(), rowInfo);
9890
9891 if (prevInFlow) {
9892 // This frame is fragmenting rows from a previous frame, so patch up
9893 // the prior GridRowTrackInfo with a new end row.
9894
9895 // FIXME: This can be streamlined and/or removed when bug 1151204 lands.
9896
9897 ComputedGridTrackInfo* priorRowInfo =
9898 prevInFlow->GetProperty(GridRowTrackInfo());
9899
9900 // Adjust track positions based on the first track in this fragment.
9901 if (priorRowInfo->mPositions.Length() >
9902 priorRowInfo->mStartFragmentTrack) {
9903 nscoord delta =
9904 priorRowInfo->mPositions[priorRowInfo->mStartFragmentTrack];
9905 for (nscoord& pos : priorRowInfo->mPositions) {
9906 pos -= delta;
9907 }
9908 }
9909
9910 ComputedGridTrackInfo* revisedPriorRowInfo = new ComputedGridTrackInfo(
9911 priorRowInfo->mNumLeadingImplicitTracks,
9912 priorRowInfo->mNumExplicitTracks, priorRowInfo->mStartFragmentTrack,
9913 gridRI.mStartRow, std::move(priorRowInfo->mPositions),
9914 std::move(priorRowInfo->mSizes), std::move(priorRowInfo->mStates),
9915 std::move(priorRowInfo->mRemovedRepeatTracks),
9916 priorRowInfo->mRepeatFirstTrack,
9917 std::move(priorRowInfo->mResolvedLineNames), priorRowInfo->mIsSubgrid,
9918 priorRowInfo->mIsMasonry);
9919 prevInFlow->SetProperty(GridRowTrackInfo(), revisedPriorRowInfo);
9920 }
9921
9922 // Generate the line info properties. We need to provide the number of
9923 // repeat tracks produced in the reflow. Only explicit names are assigned
9924 // to lines here; the mozilla::dom::GridLines class will later extract
9925 // implicit names from grid areas and assign them to the appropriate lines.
9926
9927 auto& colFunctions = gridRI.mColFunctions;
9928
9929 // Generate column lines first.
9930 uint32_t capacity = gridRI.mCols.mSizes.Length();
9931 nsTArray<nsTArray<RefPtr<nsAtom>>> columnLineNames(capacity);
9932 for (col = 0; col <= gridRI.mCols.mSizes.Length(); col++) {
9933 // Offset col by the explicit grid offset, to get the original names.
9934 nsTArray<RefPtr<nsAtom>> explicitNames =
9935 colLineNameMap.GetExplicitLineNamesAtIndex(
9936 col - colFunctions.mExplicitGridOffset);
9937
9938 columnLineNames.EmplaceBack(std::move(explicitNames));
9939 }
9940 // Get the explicit names that follow a repeat auto declaration.
9941 nsTArray<RefPtr<nsAtom>> colNamesFollowingRepeat;
9942 nsTArray<RefPtr<nsAtom>> colBeforeRepeatAuto;
9943 nsTArray<RefPtr<nsAtom>> colAfterRepeatAuto;
9944 // Note: the following is only used for a non-subgridded axis.
9945 if (colLineNameMap.HasRepeatAuto()) {
9946 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"
, 9946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!colFunctions.mTemplate.IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9946); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9947 // The line name list after the repeatAutoIndex holds the line names
9948 // for the first explicit line after the repeat auto declaration.
9949 uint32_t repeatAutoEnd = colLineNameMap.RepeatAutoStart() + 1;
9950 for (auto* list : colLineNameMap.ExpandedLineNames()[repeatAutoEnd]) {
9951 for (auto& name : list->AsSpan()) {
9952 colNamesFollowingRepeat.AppendElement(name.AsAtom());
9953 }
9954 }
9955 auto names = colLineNameMap.TrackAutoRepeatLineNames();
9956 for (auto& name : names[0].AsSpan()) {
9957 colBeforeRepeatAuto.AppendElement(name.AsAtom());
9958 }
9959 for (auto& name : names[1].AsSpan()) {
9960 colAfterRepeatAuto.AppendElement(name.AsAtom());
9961 }
9962 }
9963
9964 ComputedGridLineInfo* columnLineInfo = new ComputedGridLineInfo{
9965 std::move(columnLineNames), std::move(colBeforeRepeatAuto),
9966 std::move(colAfterRepeatAuto), std::move(colNamesFollowingRepeat)};
9967 SetProperty(GridColumnLineInfo(), columnLineInfo);
9968
9969 // Generate row lines next.
9970 auto& rowFunctions = gridRI.mRowFunctions;
9971 capacity = gridRI.mRows.mSizes.Length();
9972 nsTArray<nsTArray<RefPtr<nsAtom>>> rowLineNames(capacity);
9973 for (row = 0; row <= gridRI.mRows.mSizes.Length(); row++) {
9974 // Offset row by the explicit grid offset, to get the original names.
9975 nsTArray<RefPtr<nsAtom>> explicitNames =
9976 rowLineNameMap.GetExplicitLineNamesAtIndex(
9977 row - rowFunctions.mExplicitGridOffset);
9978 rowLineNames.EmplaceBack(std::move(explicitNames));
9979 }
9980 // Get the explicit names that follow a repeat auto declaration.
9981 nsTArray<RefPtr<nsAtom>> rowNamesFollowingRepeat;
9982 nsTArray<RefPtr<nsAtom>> rowBeforeRepeatAuto;
9983 nsTArray<RefPtr<nsAtom>> rowAfterRepeatAuto;
9984 // Note: the following is only used for a non-subgridded axis.
9985 if (rowLineNameMap.HasRepeatAuto()) {
9986 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"
, 9986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rowFunctions.mTemplate.IsSubgrid()"
")"); do { MOZ_CrashSequence(__null, 9986); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9987 // The line name list after the repeatAutoIndex holds the line names
9988 // for the first explicit line after the repeat auto declaration.
9989 uint32_t repeatAutoEnd = rowLineNameMap.RepeatAutoStart() + 1;
9990 for (auto* list : rowLineNameMap.ExpandedLineNames()[repeatAutoEnd]) {
9991 for (auto& name : list->AsSpan()) {
9992 rowNamesFollowingRepeat.AppendElement(name.AsAtom());
9993 }
9994 }
9995 auto names = rowLineNameMap.TrackAutoRepeatLineNames();
9996 for (auto& name : names[0].AsSpan()) {
9997 rowBeforeRepeatAuto.AppendElement(name.AsAtom());
9998 }
9999 for (auto& name : names[1].AsSpan()) {
10000 rowAfterRepeatAuto.AppendElement(name.AsAtom());
10001 }
10002 }
10003
10004 ComputedGridLineInfo* rowLineInfo = new ComputedGridLineInfo{
10005 std::move(rowLineNames), std::move(rowBeforeRepeatAuto),
10006 std::move(rowAfterRepeatAuto), std::move(rowNamesFollowingRepeat)};
10007 SetProperty(GridRowLineInfo(), rowLineInfo);
10008
10009 // Generate area info for explicit areas. Implicit areas are handled
10010 // elsewhere.
10011 if (!gridRI.mGridStyle->mGridTemplateAreas.IsNone()) {
10012 auto* areas = new StyleOwnedSlice<NamedArea>(
10013 gridRI.mGridStyle->mGridTemplateAreas.AsAreas()->areas);
10014 SetProperty(ExplicitNamedAreasProperty(), areas);
10015 } else {
10016 RemoveProperty(ExplicitNamedAreasProperty());
10017 }
10018 }
10019
10020 if (!prevInFlow) {
10021 if (!aStatus.IsFullyComplete()) {
10022 SharedGridData* sharedGridData =
10023 GetOrCreateDeletableProperty(SharedGridData::Prop());
10024 sharedGridData->mCols.mSizes = std::move(gridRI.mCols.mSizes);
10025 sharedGridData->mCols.mContentBoxSize = gridRI.mCols.mContentBoxSize;
10026 sharedGridData->mCols.mBaselineSubtreeAlign =
10027 gridRI.mCols.mBaselineSubtreeAlign;
10028 sharedGridData->mCols.mIsMasonry = gridRI.mCols.mIsMasonry;
10029 sharedGridData->mRows.mSizes = std::move(gridRI.mRows.mSizes);
10030 // Save the original row grid sizes and gaps so we can restore them later
10031 // in GridReflowInput::Initialize for the continuations.
10032 auto& origRowData = sharedGridData->mOriginalRowData;
10033 origRowData.ClearAndRetainStorage();
10034 origRowData.SetCapacity(sharedGridData->mRows.mSizes.Length());
10035 nscoord prevTrackEnd = 0;
10036 for (auto& sz : sharedGridData->mRows.mSizes) {
10037 SharedGridData::RowData data = {sz.mBase, sz.mPosition - prevTrackEnd};
10038 origRowData.AppendElement(data);
10039 prevTrackEnd = sz.mPosition + sz.mBase;
10040 }
10041 sharedGridData->mRows.mContentBoxSize = gridRI.mRows.mContentBoxSize;
10042 sharedGridData->mRows.mBaselineSubtreeAlign =
10043 gridRI.mRows.mBaselineSubtreeAlign;
10044 sharedGridData->mRows.mIsMasonry = gridRI.mRows.mIsMasonry;
10045 sharedGridData->mGridItems = std::move(gridRI.mGridItems);
10046 sharedGridData->mAbsPosItems = std::move(gridRI.mAbsPosItems);
10047
10048 sharedGridData->mGenerateComputedGridInfo =
10049 HasAnyStateBits(NS_STATE_GRID_COMPUTED_INFO);
10050 } else if (!GetNextInFlow()) {
10051 RemoveProperty(SharedGridData::Prop());
10052 }
10053 }
10054
10055 FinishAndStoreOverflow(&aDesiredSize);
10056}
10057
10058void nsGridContainerFrame::UpdateSubgridFrameState() {
10059 nsFrameState oldBits = GetStateBits() & kIsSubgridBits;
10060 nsFrameState newBits = ComputeSelfSubgridMasonryBits() & kIsSubgridBits;
10061 if (newBits != oldBits) {
10062 RemoveStateBits(kIsSubgridBits);
10063 if (!newBits) {
10064 RemoveProperty(Subgrid::Prop());
10065 } else {
10066 AddStateBits(newBits);
10067 }
10068 }
10069}
10070
10071nsFrameState nsGridContainerFrame::ComputeSelfSubgridMasonryBits() const {
10072 nsFrameState bits = NS_FRAME_STATE_NONE;
10073 const auto* pos = StylePosition();
10074
10075 // We can only have masonry layout in one axis.
10076 if (pos->mGridTemplateRows.IsMasonry()) {
10077 bits |= NS_STATE_GRID_IS_ROW_MASONRY;
10078 } else if (pos->mGridTemplateColumns.IsMasonry()) {
10079 bits |= NS_STATE_GRID_IS_COL_MASONRY;
10080 }
10081
10082 // NOTE: The rest of this function is only relevant if we're a subgrid;
10083 // hence, we return early as soon as we rule out that possibility.
10084
10085 // 'contain:layout/paint' makes us an "independent formatting context",
10086 // which prevents us from being a subgrid in this case (but not always).
10087 // We will also need to check our containing scroll frame for this property.
10088 // https://drafts.csswg.org/css-display-3/#establish-an-independent-formatting-context
10089 if (ShouldInhibitSubgridDueToIFC(this)) {
10090 return bits;
10091 }
10092
10093 // Skip over our scroll frame and such if we have it, to find our "parent
10094 // grid", if we have one.
10095
10096 // After this loop, 'parent' will represent the parent of the outermost frame
10097 // that shares our content node. (Normally this is just our parent frame, but
10098 // if we're e.g. a scrolled frame, then this will be the parent of our
10099 // wrapper-scrollable-frame.) If 'parent' turns out to be a grid container,
10100 // then it's our "parent grid", and we could potentially be a subgrid of it.
10101 auto* parent = GetParent();
10102 while (parent && parent->GetContent() == GetContent()) {
10103 // If we find our containing frame (e.g. our scroll frame) can't be a
10104 // subgrid, then we can't be a subgrid, for the same reasons as above. This
10105 // can happen when this frame is itself a grid item with "overflow:scroll"
10106 // or similar.
10107 if (ShouldInhibitSubgridDueToIFC(parent)) {
10108 return bits;
10109 }
10110 parent = parent->GetParent();
10111 }
10112 const nsGridContainerFrame* parentGrid = do_QueryFrame(parent);
10113 if (parentGrid) {
10114 bool isOrthogonal =
10115 GetWritingMode().IsOrthogonalTo(parent->GetWritingMode());
10116 bool isColSubgrid = pos->mGridTemplateColumns.IsSubgrid();
10117 // Subgridding a parent masonry axis makes us use masonry layout too,
10118 // unless our other axis is a masonry axis.
10119 if (isColSubgrid &&
10120 parent->HasAnyStateBits(isOrthogonal ? NS_STATE_GRID_IS_ROW_MASONRY
10121 : NS_STATE_GRID_IS_COL_MASONRY)) {
10122 isColSubgrid = false;
10123 if (!HasAnyStateBits(NS_STATE_GRID_IS_ROW_MASONRY)) {
10124 bits |= NS_STATE_GRID_IS_COL_MASONRY;
10125 }
10126 }
10127 if (isColSubgrid) {
10128 bits |= NS_STATE_GRID_IS_COL_SUBGRID;
10129 }
10130
10131 bool isRowSubgrid = pos->mGridTemplateRows.IsSubgrid();
10132 if (isRowSubgrid &&
10133 parent->HasAnyStateBits(isOrthogonal ? NS_STATE_GRID_IS_COL_MASONRY
10134 : NS_STATE_GRID_IS_ROW_MASONRY)) {
10135 isRowSubgrid = false;
10136 if (!HasAnyStateBits(NS_STATE_GRID_IS_COL_MASONRY)) {
10137 bits |= NS_STATE_GRID_IS_ROW_MASONRY;
10138 }
10139 }
10140 if (isRowSubgrid) {
10141 bits |= NS_STATE_GRID_IS_ROW_SUBGRID;
10142 }
10143 }
10144 return bits;
10145}
10146
10147void nsGridContainerFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
10148 nsIFrame* aPrevInFlow) {
10149 nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
10150
10151 if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)) {
10152 AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
10153 }
10154
10155 nsFrameState bits = NS_FRAME_STATE_NONE;
10156 if (MOZ_LIKELY(!aPrevInFlow)(__builtin_expect(!!(!aPrevInFlow), 1))) {
10157 bits = ComputeSelfSubgridMasonryBits();
10158 } else {
10159 bits = aPrevInFlow->GetStateBits() &
10160 (NS_STATE_GRID_IS_ROW_MASONRY | NS_STATE_GRID_IS_COL_MASONRY |
10161 kIsSubgridBits | NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
10162 NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
10163 }
10164 AddStateBits(bits);
10165}
10166
10167void nsGridContainerFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
10168 nsContainerFrame::DidSetComputedStyle(aOldStyle);
10169
10170 if (!aOldStyle) {
10171 return; // Init() already initialized the bits.
10172 }
10173 UpdateSubgridFrameState();
10174}
10175
10176nscoord nsGridContainerFrame::ComputeIntrinsicISize(
10177 const IntrinsicSizeInput& aInput, IntrinsicISizeType aType) {
10178 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);
10179 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);
;
10180
10181 if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
10182 return *containISize;
10183 }
10184
10185 // Calculate the sum of column sizes under intrinsic sizing.
10186 // https://drafts.csswg.org/css-grid-2/#intrinsic-sizes
10187 NormalizeChildLists();
10188 GridReflowInput gridRI(this, *aInput.mContext);
10189 // Ensure we do not measure flex tracks against unconstrained bounds.
10190 gridRI.mIsGridIntrinsicSizing = true;
10191 InitImplicitNamedAreas(gridRI.mGridStyle); // XXX optimize
10192
10193 // The min/sz/max sizes are the input to the "repeat-to-fill" algorithm:
10194 // https://drafts.csswg.org/css-grid-2/#auto-repeat
10195 // They're only used for auto-repeat so we skip computing them otherwise.
10196 RepeatTrackSizingInput repeatSizing(gridRI.mWM);
10197 if (!IsColSubgrid() && gridRI.mColFunctions.mHasRepeatAuto) {
10198 repeatSizing.InitFromStyle(
10199 LogicalAxis::Inline, gridRI.mWM, gridRI.mFrame, gridRI.mFrame->Style(),
10200 gridRI.mFrame->GetAspectRatio(), aInput.mContainingBlockSize);
10201 }
10202 if ((!IsRowSubgrid() && gridRI.mRowFunctions.mHasRepeatAuto &&
10203 !(gridRI.mGridStyle->mGridAutoFlow & StyleGridAutoFlow::ROW)) ||
10204 IsColMasonry()) {
10205 // Only 'grid-auto-flow:column' can create new implicit columns, so that's
10206 // the only case where our block-size can affect the number of columns.
10207 // Masonry layout always depends on how many rows we have though.
10208 repeatSizing.InitFromStyle(
10209 LogicalAxis::Block, gridRI.mWM, gridRI.mFrame, gridRI.mFrame->Style(),
10210 gridRI.mFrame->GetAspectRatio(), aInput.mContainingBlockSize);
10211 }
10212
10213 Grid grid;
10214 if (MOZ_LIKELY(!IsSubgrid())(__builtin_expect(!!(!IsSubgrid()), 1))) {
10215 grid.PlaceGridItems(gridRI, repeatSizing); // XXX optimize
10216 } else {
10217 auto* subgrid = GetProperty(Subgrid::Prop());
10218 gridRI.mGridItems = subgrid->mGridItems.Clone();
10219 gridRI.mAbsPosItems = subgrid->mAbsPosItems.Clone();
10220 grid.mGridColEnd = subgrid->mGridColEnd;
10221 grid.mGridRowEnd = subgrid->mGridRowEnd;
10222 }
10223
10224 auto constraint = aType == IntrinsicISizeType::MinISize
10225 ? SizingConstraint::MinContent
10226 : SizingConstraint::MaxContent;
10227 if (IsColMasonry()) {
10228 ReflowOutput desiredSize(gridRI.mWM);
10229 nsSize containerSize;
10230 LogicalRect contentArea(gridRI.mWM);
10231 nsReflowStatus status;
10232 gridRI.mRows.mSizes.SetLength(grid.mGridRowEnd);
10233 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10234 NS_UNCONSTRAINEDSIZE, constraint);
10235 return MasonryLayout(gridRI, contentArea, constraint, desiredSize, status,
10236 nullptr, containerSize);
10237 }
10238
10239 if (grid.mGridColEnd == 0) {
10240 return nscoord(0);
10241 }
10242
10243 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10244 NS_UNCONSTRAINEDSIZE, constraint);
10245
10246 const nscoord contentBoxBSize =
10247 aInput.mPercentageBasisForChildren
10248 ? aInput.mPercentageBasisForChildren->BSize(gridRI.mWM)
10249 : NS_UNCONSTRAINEDSIZE;
10250
10251 // Resolve row sizes so that when we re-resolve the column sizes, grid items
10252 // with percent-valued block-sizes (and aspect ratios) have definite row
10253 // sizes as the percentage basis. Their resolved block-size can then
10254 // transfer to the inline-axis, contributing correctly to the grid
10255 // container's intrinsic inline-size.
10256 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Block, grid, contentBoxBSize,
10257 SizingConstraint::NoConstraint);
10258
10259 // Invalidate the column sizes before re-resolving them.
10260 gridRI.InvalidateTrackSizesForAxis(LogicalAxis::Inline);
10261
10262 // Re-resolve the column sizes, using the resolved row sizes established
10263 // above. See 12.1.3 of the Grid Sizing Algorithm for more scenarios where
10264 // re-resolving the column sizes is necessary:
10265 // https://drafts.csswg.org/css-grid-2/#algo-grid-sizing
10266 gridRI.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
10267 NS_UNCONSTRAINEDSIZE, constraint);
10268
10269 return gridRI.mCols.TotalTrackSizeWithoutAlignment(this);
10270}
10271
10272nscoord nsGridContainerFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
10273 IntrinsicISizeType aType) {
10274 auto* firstCont = static_cast<nsGridContainerFrame*>(FirstContinuation());
10275 if (firstCont != this) {
10276 return firstCont->IntrinsicISize(aInput, aType);
10277 }
10278 return mCachedIntrinsicSizes.GetOrSet(*this, aType, aInput, [&] {
10279 return ComputeIntrinsicISize(aInput, aType);
10280 });
10281}
10282
10283void nsGridContainerFrame::MarkIntrinsicISizesDirty() {
10284 mCachedIntrinsicSizes.Clear();
10285 for (auto& perAxisBaseline : mBaseline) {
10286 for (auto& baseline : perAxisBaseline) {
10287 baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
10288 }
10289 }
10290 nsContainerFrame::MarkIntrinsicISizesDirty();
10291}
10292
10293void nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
10294 const nsDisplayListSet& aLists) {
10295 DisplayBorderBackgroundOutline(aBuilder, aLists);
10296 if (HidesContent()) {
10297 return;
10298 }
10299
10300 if (GetPrevInFlow()) {
10301 DisplayOverflowContainers(aBuilder, aLists);
10302 }
10303
10304 // Our children are all grid-level boxes, which behave the same as
10305 // inline-blocks in painting, so their borders/backgrounds all go on
10306 // the BlockBorderBackgrounds list.
10307 typedef CSSOrderAwareFrameIterator::OrderState OrderState;
10308 OrderState order =
10309 HasAnyStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
10310 ? OrderState::Ordered
10311 : OrderState::Unordered;
10312 CSSOrderAwareFrameIterator iter(
10313 this, FrameChildListID::Principal,
10314 CSSOrderAwareFrameIterator::ChildFilter::IncludeAll, order);
10315 const auto flags = DisplayFlagsForFlexOrGridItem();
10316 for (; !iter.AtEnd(); iter.Next()) {
10317 nsIFrame* child = *iter;
10318 BuildDisplayListForChild(aBuilder, child, aLists, flags);
10319 }
10320
10321 if (GetPrevInFlow() || GetNextInFlow()) {
10322 DisplayAbsoluteFramesNotBuiltByPlaceholder(aBuilder, aLists);
10323 }
10324}
10325
10326bool nsGridContainerFrame::DrainSelfOverflowList() {
10327 return DrainAndMergeSelfOverflowList();
10328}
10329
10330void nsGridContainerFrame::AppendFrames(ChildListID aListID,
10331 nsFrameList&& aFrameList) {
10332 NoteNewChildren(aListID, aFrameList);
10333 nsContainerFrame::AppendFrames(aListID, std::move(aFrameList));
10334}
10335
10336void nsGridContainerFrame::InsertFrames(
10337 ChildListID aListID, nsIFrame* aPrevFrame,
10338 const nsLineList::iterator* aPrevFrameLine, nsFrameList&& aFrameList) {
10339 NoteNewChildren(aListID, aFrameList);
10340 nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
10341 std::move(aFrameList));
10342}
10343
10344void nsGridContainerFrame::RemoveFrame(DestroyContext& aContext,
10345 ChildListID aListID,
10346 nsIFrame* aOldFrame) {
10347 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"
, 10347); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aListID == FrameChildListID::Principal"
") (" "unexpected child list" ")"); do { MOZ_CrashSequence(__null
, 10347); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10348
10349#ifdef DEBUG1
10350 SetDidPushItemsBitIfNeeded(aListID, aOldFrame);
10351#endif
10352
10353 nsContainerFrame::RemoveFrame(aContext, aListID, aOldFrame);
10354}
10355
10356nscoord nsGridContainerFrame::SynthesizeBaseline(
10357 const FindItemInGridOrderResult& aGridOrderItem, LogicalAxis aAxis,
10358 BaselineSharingGroup aGroup, const nsSize& aCBPhysicalSize, nscoord aCBSize,
10359 WritingMode aCBWM) {
10360 if (MOZ_UNLIKELY(!aGridOrderItem.mItem)(__builtin_expect(!!(!aGridOrderItem.mItem), 0))) {
10361 // No item in this fragment - synthesize a baseline from our border-box.
10362 return ::SynthesizeBaselineFromBorderBox(aGroup, aCBWM, aAxis, aCBSize);
10363 }
10364
10365 nsIFrame* child = aGridOrderItem.mItem->mFrame;
10366 nsGridContainerFrame* grid = do_QueryFrame(child);
10367 auto childWM = child->GetWritingMode();
10368 bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
10369 const LogicalAxis childAxis = aCBWM.ConvertAxisTo(aAxis, childWM);
10370 nscoord baseline;
10371 nscoord start;
10372 nscoord size;
10373
10374 if (aAxis == LogicalAxis::Block) {
10375 start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).B(aCBWM);
10376 size = child->BSize(aCBWM);
10377 if (grid && aGridOrderItem.mIsInEdgeTrack) {
10378 baseline = isOrthogonal ? grid->GetIBaseline(aGroup)
10379 : grid->GetBBaseline(aGroup);
10380 } else if (!isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
10381 // This assertion is mostly for documentation purposes; it must hold,
10382 // given the checks in our 'if' statements. (We know aAxis is
10383 // LogicalAxis::Block, and isOrthogonal is false, which means childAxis
10384 // must be LogicalAxis::Block). If instead we got here with a childAxis of
10385 // LogicalAxis::Inline, then our call to
10386 // Baseline::SynthesizeBaselineFromBorderBox might incorrectly think
10387 // it makes sense to use a central baseline, in an axis where that
10388 // doesn't make sense.
10389 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", 10389
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "childAxis == LogicalAxis::Block"
") (" "unexpected childAxis" ")"); do { MOZ_CrashSequence(__null
, 10389); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10390 baseline = child
10391 ->GetNaturalBaselineBOffset(childWM, aGroup,
10392 BaselineExportContext::Other)
10393 .valueOrFrom([aGroup, child, childWM]() {
10394 return Baseline::SynthesizeBOffsetFromBorderBox(
10395 child, childWM, aGroup);
10396 });
10397 } else {
10398 baseline =
10399 ::SynthesizeBaselineFromBorderBox(aGroup, childWM, childAxis, size);
10400 }
10401 } else {
10402 start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).I(aCBWM);
10403 size = child->ISize(aCBWM);
10404 if (grid && aGridOrderItem.mIsInEdgeTrack) {
10405 baseline = isOrthogonal ? grid->GetBBaseline(aGroup)
10406 : grid->GetIBaseline(aGroup);
10407 } else if (isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
10408 baseline = child
10409 ->GetNaturalBaselineBOffset(childWM, aGroup,
10410 BaselineExportContext::Other)
10411 .valueOrFrom([aGroup, childWM, childAxis, size]() {
10412 return ::SynthesizeBaselineFromBorderBox(
10413 aGroup, childWM, childAxis, size);
10414 });
10415 } else {
10416 baseline =
10417 ::SynthesizeBaselineFromBorderBox(aGroup, childWM, childAxis, size);
10418 }
10419 }
10420 return aGroup == BaselineSharingGroup::First
10421 ? start + baseline
10422 : aCBSize - start - size + baseline;
10423}
10424
10425void nsGridContainerFrame::CalculateBaselines(
10426 BaselineSet aBaselineSet, CSSOrderAwareFrameIterator* aIter,
10427 const nsTArray<GridItemInfo>* aGridItems, const Tracks& aTracks,
10428 uint32_t aFragmentStartTrack, uint32_t aFirstExcludedTrack, WritingMode aWM,
10429 const nsSize& aCBPhysicalSize, nscoord aCBBorderPaddingStart,
10430 nscoord aCBBorderPaddingEnd, nscoord aCBSize) {
10431 const auto axis = aTracks.mAxis;
10432
10433 auto firstBaseline = aTracks.GetBaseline(0, BaselineSharingGroup::First);
10434 if (!(aBaselineSet & BaselineSet::eFirst)) {
10435 mBaseline[axis][BaselineSharingGroup::First] =
10436 ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::First, aWM,
10437 axis, aCBSize);
10438 } else if (firstBaseline.isNothing()) {
10439 FindItemInGridOrderResult gridOrderFirstItem = FindFirstItemInGridOrder(
10440 *aIter, *aGridItems,
10441 axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
10442 axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
10443 aFragmentStartTrack);
10444 mBaseline[axis][BaselineSharingGroup::First] = SynthesizeBaseline(
10445 gridOrderFirstItem, axis, BaselineSharingGroup::First, aCBPhysicalSize,
10446 aCBSize, aWM);
10447 } else {
10448 // We have a 'first baseline' group in the start track in this fragment.
10449 // Convert it from track to grid container border-box coordinates.
10450 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", 10450
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aGridItems->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 10450); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10451 nscoord gapBeforeStartTrack =
10452 aFragmentStartTrack == 0
10453 ? aTracks.GridLineEdge(aFragmentStartTrack,
10454 GridLineSide::AfterGridGap)
10455 : nscoord(0); // no content gap at start of fragment
10456 mBaseline[axis][BaselineSharingGroup::First] =
10457 aCBBorderPaddingStart + gapBeforeStartTrack + *firstBaseline;
10458 }
10459
10460 auto lastBaseline = aTracks.GetBaseline(aTracks.mBaselines.Length() - 1,
10461 BaselineSharingGroup::Last);
10462 if (!(aBaselineSet & BaselineSet::eLast)) {
10463 mBaseline[axis][BaselineSharingGroup::Last] =
10464 ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::Last, aWM, axis,
10465 aCBSize);
10466 } else if (lastBaseline.isNothing()) {
10467 // For finding items for the 'last baseline' we need to create a reverse
10468 // iterator ('aIter' is the forward iterator from the GridReflowInput).
10469 using Iter = ReverseCSSOrderAwareFrameIterator;
10470 auto orderState = aIter->ItemsAreAlreadyInOrder()
10471 ? Iter::OrderState::Ordered
10472 : Iter::OrderState::Unordered;
10473 Iter iter(this, FrameChildListID::Principal,
10474 Iter::ChildFilter::SkipPlaceholders, orderState);
10475 iter.SetItemCount(aGridItems->Length());
10476 FindItemInGridOrderResult gridOrderLastItem = FindLastItemInGridOrder(
10477 iter, *aGridItems,
10478 axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
10479 axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
10480 aFragmentStartTrack, aFirstExcludedTrack);
10481 mBaseline[axis][BaselineSharingGroup::Last] =
10482 SynthesizeBaseline(gridOrderLastItem, axis, BaselineSharingGroup::Last,
10483 aCBPhysicalSize, aCBSize, aWM);
10484 } else {
10485 // We have a 'last baseline' group in the end track in this fragment.
10486 // Convert it from track to grid container border-box coordinates.
10487 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", 10487
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aGridItems->IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 10487); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10488 auto borderBoxStartToEndOfEndTrack =
10489 aCBBorderPaddingStart +
10490 aTracks.GridLineEdge(aFirstExcludedTrack, GridLineSide::BeforeGridGap) -
10491 aTracks.GridLineEdge(aFragmentStartTrack, GridLineSide::BeforeGridGap);
10492 mBaseline[axis][BaselineSharingGroup::Last] =
10493 (aCBSize - borderBoxStartToEndOfEndTrack) + *lastBaseline;
10494 }
10495}
10496
10497#ifdef DEBUG_FRAME_DUMP1
10498nsresult nsGridContainerFrame::GetFrameName(nsAString& aResult) const {
10499 return MakeFrameName(u"GridContainer"_ns, aResult);
10500}
10501
10502void nsGridContainerFrame::ExtraContainerFrameInfo(
10503 nsACString& aTo, bool aListOnlyDeterministic) const {
10504 if (const void* const subgrid = GetProperty(Subgrid::Prop())) {
10505 aTo += "[subgrid";
10506 ListPtr(aTo, aListOnlyDeterministic, subgrid);
10507 aTo += "]";
10508 }
10509}
10510
10511#endif
10512
10513/* static */ nsGridContainerFrame::FindItemInGridOrderResult
10514nsGridContainerFrame::FindFirstItemInGridOrder(
10515 CSSOrderAwareFrameIterator& aIter, const nsTArray<GridItemInfo>& aGridItems,
10516 LineRange GridArea::* aMajor, LineRange GridArea::* aMinor,
10517 uint32_t aFragmentStartTrack) {
10518 FindItemInGridOrderResult result = {nullptr, false};
10519 uint32_t minMajor = kTranslatedMaxLine + 1;
10520 uint32_t minMinor = kTranslatedMaxLine + 1;
10521 aIter.Reset();
10522 for (; !aIter.AtEnd(); aIter.Next()) {
10523 const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
10524 if ((item.mArea.*aMajor).mEnd <= aFragmentStartTrack) {
10525 continue; // item doesn't span any track in this fragment
10526 }
10527 uint32_t major = (item.mArea.*aMajor).mStart;
10528 uint32_t minor = (item.mArea.*aMinor).mStart;
10529 if (major < minMajor || (major == minMajor && minor < minMinor)) {
10530 minMajor = major;
10531 minMinor = minor;
10532 result.mItem = &item;
10533 result.mIsInEdgeTrack = major == 0U;
10534 }
10535 }
10536 return result;
10537}
10538
10539/* static */ nsGridContainerFrame::FindItemInGridOrderResult
10540nsGridContainerFrame::FindLastItemInGridOrder(
10541 ReverseCSSOrderAwareFrameIterator& aIter,
10542 const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::* aMajor,
10543 LineRange GridArea::* aMinor, uint32_t aFragmentStartTrack,
10544 uint32_t aFirstExcludedTrack) {
10545 FindItemInGridOrderResult result = {nullptr, false};
10546 int32_t maxMajor = -1;
10547 int32_t maxMinor = -1;
10548 aIter.Reset();
10549 int32_t lastMajorTrack = int32_t(aFirstExcludedTrack) - 1;
10550 for (; !aIter.AtEnd(); aIter.Next()) {
10551 const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
10552 // Subtract 1 from the end line to get the item's last track index.
10553 int32_t major = (item.mArea.*aMajor).mEnd - 1;
10554 // Currently, this method is only called with aFirstExcludedTrack ==
10555 // the first track in the next fragment, so we take the opportunity
10556 // to assert this item really belongs to this fragment.
10557 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", 10558
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item.mArea.*aMajor).mStart < aFirstExcludedTrack"
") (" "found an item that belongs to some later fragment" ")"
); do { MOZ_CrashSequence(__null, 10558); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10558 "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", 10558
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(item.mArea.*aMajor).mStart < aFirstExcludedTrack"
") (" "found an item that belongs to some later fragment" ")"
); do { MOZ_CrashSequence(__null, 10558); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10559 if (major < int32_t(aFragmentStartTrack)) {
10560 continue; // item doesn't span any track in this fragment
10561 }
10562 int32_t minor = (item.mArea.*aMinor).mEnd - 1;
10563 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"
, 10563); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minor >= 0 && major >= 0"
") (" "grid item must have span >= 1" ")"); do { MOZ_CrashSequence
(__null, 10563); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10564 if (major > maxMajor || (major == maxMajor && minor > maxMinor)) {
10565 maxMajor = major;
10566 maxMinor = minor;
10567 result.mItem = &item;
10568 result.mIsInEdgeTrack = major == lastMajorTrack;
10569 }
10570 }
10571 return result;
10572}
10573
10574nsGridContainerFrame::UsedTrackSizes* nsGridContainerFrame::GetUsedTrackSizes()
10575 const {
10576 return GetProperty(UsedTrackSizes::Prop());
10577}
10578
10579void nsGridContainerFrame::StoreUsedTrackSizes(LogicalAxis aAxis,
10580 const TrackPlan& aSizes) {
10581 auto* uts = GetOrCreateDeletableProperty(UsedTrackSizes::Prop());
10582 uts->mTrackPlans[aAxis].Assign(aSizes);
10583 uts->mCanResolveLineRangeSize[aAxis] = true;
10584 // XXX is resetting these bits necessary?
10585 for (auto& sz : uts->mTrackPlans[aAxis]) {
10586 sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited |
10587 TrackSize::eInfinitelyGrowable);
10588 }
10589}
10590
10591#ifdef DEBUG1
10592void nsGridContainerFrame::SetInitialChildList(ChildListID aListID,
10593 nsFrameList&& aChildList) {
10594 ChildListIDs supportedLists = {FrameChildListID::Principal};
10595 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", 10595
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "supportedLists.contains(aListID)"
") (" "unexpected child list" ")"); do { MOZ_CrashSequence(__null
, 10595); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10596 return nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
10597}
10598
10599void nsGridContainerFrame::TrackSize::DumpStateBits(StateBits aState) {
10600 printf("min:");
10601 if (aState & eAutoMinSizing) {
10602 printf("auto ");
10603 } else if (aState & eMinContentMinSizing) {
10604 printf("min-content ");
10605 } else if (aState & eMaxContentMinSizing) {
10606 printf("max-content ");
10607 }
10608 printf(" max:");
10609 if (aState & eAutoMaxSizing) {
10610 printf("auto ");
10611 } else if (aState & eMinContentMaxSizing) {
10612 printf("min-content ");
10613 } else if (aState & eMaxContentMaxSizing) {
10614 printf("max-content ");
10615 } else if (aState & eFlexMaxSizing) {
10616 printf("flex ");
10617 }
10618 if (aState & eFrozen) {
10619 printf("frozen ");
10620 }
10621 if (aState & eModified) {
10622 printf("modified ");
10623 }
10624 if (aState & eBreakBefore) {
10625 printf("break-before ");
10626 }
10627}
10628
10629void nsGridContainerFrame::TrackSize::Dump() const {
10630 printf("mPosition=%d mBase=%d mLimit=%d ", mPosition, mBase, mLimit);
10631 DumpStateBits(mState);
10632}
10633
10634#endif // DEBUG
10635
10636bool nsGridContainerFrame::IsMasonry(LogicalAxis aAxis) const {
10637 return HasAnyStateBits(aAxis == mozilla::LogicalAxis::Block
10638 ? NS_STATE_GRID_IS_ROW_MASONRY
10639 : NS_STATE_GRID_IS_COL_MASONRY);
10640}
10641
10642bool nsGridContainerFrame::GridItemShouldStretch(const nsIFrame* aChild,
10643 LogicalAxis aAxis) const {
10644 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", 10644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->IsGridItem()"
")"); do { MOZ_CrashSequence(__null, 10644); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10645
10646 if (aChild->IsGridContainerFrame()) {
10647 // The subgrid is always stretched in its subgridded dimensions.
10648 // https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment
10649 const auto* gridContainer =
10650 static_cast<const nsGridContainerFrame*>(aChild);
10651 if (gridContainer->IsSubgrid(aAxis)) {
10652 return true;
10653 }
10654 }
10655
10656 const auto wm = aChild->GetWritingMode();
10657 if (aChild->StyleMargin()->HasAuto(aAxis, wm,
10658 AnchorPosResolutionParams::From(aChild))) {
10659 // Per https://drafts.csswg.org/css-grid-2/#auto-margins, any 'auto' margin
10660 // in an axis disables the alignment property in that axis.
10661 return false;
10662 }
10663
10664 const auto cbwm = GetWritingMode();
10665 if (IsMasonry(wm, aAxis)) {
10666 // The child is in the container's masonry-axis.
10667 // AlignJustifyTracksInMasonryAxis will stretch it, so we don't report that
10668 // here.
10669 return false;
10670 }
10671
10672 const auto alignment =
10673 aChild->StylePosition()->UsedSelfAlignment(wm, aAxis, cbwm, Style());
10674 // An item with 'normal' alignment that is a replaced frame should use its
10675 // natural size, and not fill the grid area.
10676 // https://drafts.csswg.org/css-grid-2/#grid-item-sizing
10677 if (MOZ_LIKELY(alignment == StyleAlignFlags::NORMAL)(__builtin_expect(!!(alignment == StyleAlignFlags::NORMAL), 1
))
) {
10678 return !aChild->HasReplacedSizing();
10679 }
10680 return alignment == StyleAlignFlags::STRETCH;
10681}
10682
10683bool nsGridContainerFrame::ShouldInhibitSubgridDueToIFC(
10684 const nsIFrame* aFrame) {
10685 // Just checking for things that make us establish an independent formatting
10686 // context (IFC) and hence prevent us from being a subgrid:
10687 // * Out-of-flow (e.g. abspos) frames also establish an IFC. Note, our
10688 // NS_FRAME_OUT_OF_FLOW bit potentially isn't set yet, so we check our style.
10689 // * contain:layout and contain:paint each make us establish an IFC.
10690 const auto* display = aFrame->StyleDisplay();
10691 return display->IsContainLayout() || display->IsContainPaint() ||
10692 display->mContainerType &
10693 (StyleContainerType::SIZE | StyleContainerType::INLINE_SIZE) ||
10694 display->IsAbsolutelyPositionedStyle();
10695}
10696
10697nsGridContainerFrame* nsGridContainerFrame::GetGridContainerFrame(
10698 nsIFrame* aFrame) {
10699 nsGridContainerFrame* gridFrame = nullptr;
10700
10701 if (aFrame) {
10702 nsIFrame* inner = aFrame;
10703 if (MOZ_UNLIKELY(aFrame->IsFieldSetFrame())(__builtin_expect(!!(aFrame->IsFieldSetFrame()), 0))) {
10704 inner = static_cast<nsFieldSetFrame*>(aFrame)->GetInner();
10705 }
10706 // Since "Get" methods like GetInner and GetContentInsertionFrame can
10707 // return null, we check the return values before dereferencing. Our
10708 // calling pattern makes this unlikely, but we're being careful.
10709 nsIFrame* insertionFrame =
10710 inner ? inner->GetContentInsertionFrame() : nullptr;
10711 nsIFrame* possibleGridFrame = insertionFrame ? insertionFrame : aFrame;
10712 gridFrame = possibleGridFrame->IsGridContainerFrame()
10713 ? static_cast<nsGridContainerFrame*>(possibleGridFrame)
10714 : nullptr;
10715 }
10716 return gridFrame;
10717}
10718
10719nsGridContainerFrame* nsGridContainerFrame::GetGridFrameWithComputedInfo(
10720 nsIFrame* aFrame) {
10721 nsGridContainerFrame* gridFrame = GetGridContainerFrame(aFrame);
10722 if (!gridFrame) {
10723 return nullptr;
10724 }
10725
10726 auto HasComputedInfo = [](const nsGridContainerFrame& aFrame) -> bool {
10727 return aFrame.HasProperty(GridColTrackInfo()) &&
10728 aFrame.HasProperty(GridRowTrackInfo()) &&
10729 aFrame.HasProperty(GridColumnLineInfo()) &&
10730 aFrame.HasProperty(GridRowLineInfo());
10731 };
10732
10733 if (HasComputedInfo(*gridFrame)) {
10734 return gridFrame;
10735 }
10736
10737 // Trigger a reflow that generates additional grid property data.
10738 // Hold onto aFrame while we do this, in case reflow destroys it.
10739 AutoWeakFrame weakFrameRef(gridFrame);
10740
10741 RefPtr<mozilla::PresShell> presShell = gridFrame->PresShell();
10742 gridFrame->AddStateBits(NS_STATE_GRID_COMPUTED_INFO);
10743 presShell->FrameNeedsReflow(gridFrame, IntrinsicDirty::None,
10744 NS_FRAME_IS_DIRTY);
10745 presShell->FlushPendingNotifications(FlushType::Layout);
10746
10747 // If the weakFrameRef is no longer valid, then we must bail out.
10748 if (!weakFrameRef.IsAlive()) {
10749 return nullptr;
10750 }
10751
10752 // This can happen if for some reason we ended up not reflowing, like in print
10753 // preview under some circumstances.
10754 if (MOZ_UNLIKELY(!HasComputedInfo(*gridFrame))(__builtin_expect(!!(!HasComputedInfo(*gridFrame)), 0))) {
10755 return nullptr;
10756 }
10757
10758 return gridFrame;
10759}
10760
10761void nsGridContainerFrame::MarkCachedGridMeasurementsDirty(
10762 nsIFrame* aItemFrame) {
10763 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", 10763
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItemFrame->IsGridItem()"
")"); do { MOZ_CrashSequence(__null, 10763); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10764 aItemFrame->RemoveProperty(CachedBAxisMeasurement::Prop());
10765}
10766
10767// TODO: This is a rather dumb implementation of nsILineIterator, but it's
10768// better than our pre-existing behavior. Ideally, we should probably use the
10769// grid information to return a meaningful number of lines etc.
10770bool nsGridContainerFrame::IsLineIteratorFlowRTL() { return false; }
10771
10772int32_t nsGridContainerFrame::GetNumLines() const {
10773 return mFrames.GetLength();
10774}
10775
10776Result<nsILineIterator::LineInfo, nsresult> nsGridContainerFrame::GetLine(
10777 int32_t aLineNumber) {
10778 if (aLineNumber < 0 || aLineNumber >= GetNumLines()) {
10779 return Err(NS_ERROR_FAILURE);
10780 }
10781 LineInfo rv;
10782 nsIFrame* f = mFrames.FrameAt(aLineNumber);
10783 rv.mLineBounds = f->GetRect();
10784 rv.mFirstFrameOnLine = f;
10785 rv.mNumFramesOnLine = 1;
10786 return rv;
10787}
10788
10789int32_t nsGridContainerFrame::FindLineContaining(const nsIFrame* aFrame,
10790 int32_t aStartLine) {
10791 const int32_t index = mFrames.IndexOf(aFrame);
10792 if (index < 0) {
10793 return -1;
10794 }
10795 if (index < aStartLine) {
10796 return -1;
10797 }
10798 return index;
10799}
10800
10801NS_IMETHODIMPnsresult
10802nsGridContainerFrame::CheckLineOrder(int32_t aLine, bool* aIsReordered,
10803 nsIFrame** aFirstVisual,
10804 nsIFrame** aLastVisual) {
10805 *aIsReordered = false;
10806 *aFirstVisual = nullptr;
10807 *aLastVisual = nullptr;
10808 return NS_OK;
10809}
10810
10811NS_IMETHODIMPnsresult
10812nsGridContainerFrame::FindFrameAt(int32_t aLineNumber, nsPoint aPos,
10813 nsIFrame** aFrameFound,
10814 bool* aPosIsBeforeFirstFrame,
10815 bool* aPosIsAfterLastFrame) {
10816 const auto wm = GetWritingMode();
10817 const LogicalPoint pos(wm, aPos, GetSize());
10818
10819 *aFrameFound = nullptr;
10820 *aPosIsBeforeFirstFrame = true;
10821 *aPosIsAfterLastFrame = false;
10822
10823 nsIFrame* f = mFrames.FrameAt(aLineNumber);
10824 if (!f) {
10825 return NS_OK;
10826 }
10827
10828 auto rect = f->GetLogicalRect(wm, GetSize());
10829 *aFrameFound = f;
10830 *aPosIsBeforeFirstFrame = pos.I(wm) < rect.IStart(wm);
10831 *aPosIsAfterLastFrame = pos.I(wm) > rect.IEnd(wm);
10832 return NS_OK;
10833}
10834
10835void nsGridContainerFrame::TrackPlan::Initialize(TrackSizingPhase aPhase,
10836 const Tracks& aTracks) {
10837 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", 10837
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTrackSizes.Length() == aTracks.mSizes.Length()"
")"); do { MOZ_CrashSequence(__null, 10837); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10838 auto plan = mTrackSizes.begin();
10839 auto sz = aTracks.mSizes.begin();
10840 for (; plan != mTrackSizes.end() && sz != aTracks.mSizes.end();
10841 plan++, sz++) {
10842 plan->mBase = Tracks::StartSizeInDistribution(aPhase, *sz);
10843 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"
, 10845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10845); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
10844 !(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"
, 10845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10845); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
10845 "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"
, 10845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPhase == TrackSizingPhase::MaxContentMaximums || !(sz->mState & TrackSize::eInfinitelyGrowable)"
") (" "forgot to reset the eInfinitelyGrowable bit?" ")"); do
{ MOZ_CrashSequence(__null, 10845); __attribute__((nomerge))
::abort(); } while (false); } } while (false)
;
10846 plan->mState = sz->mState;
10847 }
10848}
10849
10850// Distribute space to all flex tracks this item spans.
10851// https://drafts.csswg.org/css-grid-2/#algo-spanning-flex-items
10852nscoord nsGridContainerFrame::TrackPlan::DistributeToFlexTrackSizes(
10853 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
10854 const TrackSizingFunctions& aFunctions,
10855 const nsGridContainerFrame::Tracks& aTracks) {
10856 nscoord space = aAvailableSpace;
10857 // Measure used fraction.
10858 double totalFr = 0.0;
10859 // TODO alaskanemily: we should be subtracting definite-sized tracks from
10860 // the available space below.
10861 for (uint32_t track : aGrowableTracks) {
10862 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", 10863
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
") (" "Only flex-sized tracks should be growable during step 4"
")"); do { MOZ_CrashSequence(__null, 10863); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10863 "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", 10863
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTracks.mSizes[track].mState & TrackSize::eFlexMaxSizing"
") (" "Only flex-sized tracks should be growable during step 4"
")"); do { MOZ_CrashSequence(__null, 10863); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10864 totalFr += aFunctions.MaxSizingFor(track).AsFlex()._0;
10865 }
10866 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"
, 10866); AnnotateMozCrashReason("MOZ_ASSERT" "(" "totalFr >= 0.0"
") (" "flex fractions must be non-negative." ")"); do { MOZ_CrashSequence
(__null, 10866); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10867
10868 double frSize = aAvailableSpace;
10869 if (totalFr > 1.0) {
10870 frSize /= totalFr;
10871 }
10872 // Distribute the space to the tracks proportionally to the fractional
10873 // sizes.
10874 for (uint32_t track : aGrowableTracks) {
10875 TrackSize& sz = mTrackSizes[track];
10876 if (sz.IsFrozen()) {
10877 continue;
10878 }
10879 const double trackFr = aFunctions.MaxSizingFor(track).AsFlex()._0;
10880 nscoord size = NSToCoordRoundWithClamp(frSize * trackFr);
10881 // This shouldn't happen in theory, but it could happen due to a
10882 // combination of floating-point error during the multiplication above
10883 // and loss of precision in the cast.
10884 if (MOZ_UNLIKELY(size > space)(__builtin_expect(!!(size > space), 0))) {
10885 size = space;
10886 space = 0;
10887 } else {
10888 space -= size;
10889 }
10890 sz.mBase = std::max(sz.mBase, size);
10891 }
10892 return space;
10893}
10894
10895void nsGridContainerFrame::ItemPlan::Initialize(
10896 TrackSizingPhase aPhase, const nsTArray<uint32_t>& aGrowableTracks,
10897 const nsGridContainerFrame::Tracks& aTracks) {
10898 for (uint32_t track : aGrowableTracks) {
10899 auto& plan = mTrackSizes[track];
10900 const TrackSize& sz = aTracks.mSizes[track];
10901 plan.mBase = Tracks::StartSizeInDistribution(aPhase, sz);
10902 bool unlimited = sz.mState & TrackSize::eInfinitelyGrowable;
10903 plan.mLimit = unlimited ? NS_UNCONSTRAINEDSIZE : sz.mLimit;
10904 plan.mState = sz.mState;
10905 }
10906}
10907
10908nscoord nsGridContainerFrame::ItemPlan::GrowTracksToLimit(
10909 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
10910 const FitContentClamper& aFitContentClamper) {
10911 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", 10911
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0"
")"); do { MOZ_CrashSequence(__null, 10911); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10912 nscoord space = aAvailableSpace;
10913 uint32_t numGrowable = aGrowableTracks.Length();
10914 while (true) {
10915 nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
10916 for (uint32_t track : aGrowableTracks) {
10917 TrackSize& sz = mTrackSizes[track];
10918 if (sz.IsFrozen()) {
10919 continue;
10920 }
10921 nscoord newBase = sz.mBase + spacePerTrack;
10922 nscoord limit = sz.mLimit;
10923 if (MOZ_UNLIKELY((sz.mState & TrackSize::eApplyFitContentClamping) &&(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
10924 aFitContentClamper)(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
) {
10925 // Clamp the limit to the fit-content() size, for §12.5.2 step 5/6.
10926 aFitContentClamper(track, sz.mBase, &limit);
10927 }
10928 if (newBase > limit) {
10929 nscoord consumed = limit - sz.mBase;
10930 if (consumed > 0) {
10931 space -= consumed;
10932 sz.mBase = limit;
10933 }
10934 sz.mState |= TrackSize::eFrozen;
10935 if (--numGrowable == 0) {
10936 return space;
10937 }
10938 } else {
10939 sz.mBase = newBase;
10940 space -= spacePerTrack;
10941 }
10942 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", 10942)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "space >= 0" ")"
); do { MOZ_CrashSequence(__null, 10942); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10943 if (space == 0) {
10944 return 0;
10945 }
10946 }
10947 }
10948 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"
, 10948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "we don't exit the loop above except by return"
")"); do { MOZ_CrashSequence(__null, 10948); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10949 return 0;
10950}
10951
10952uint32_t nsGridContainerFrame::ItemPlan::MarkExcludedTracks(
10953 TrackSizingPhase aPhase, const nsTArray<uint32_t>& aGrowableTracks,
10954 SizingConstraint aConstraint) {
10955 uint32_t numGrowable = aGrowableTracks.Length();
10956 if (aPhase == TrackSizingPhase::IntrinsicMaximums ||
10957 aPhase == TrackSizingPhase::MaxContentMaximums) {
10958 // "when handling any intrinsic growth limit: all affected tracks"
10959 return numGrowable;
10960 }
10961
10962 TrackSize::StateBits selector = Tracks::SelectorForPhase(aPhase, aConstraint);
10963 numGrowable = MarkExcludedTracks(
10964 numGrowable, aGrowableTracks, TrackSize::eMaxContentMinSizing,
10965 TrackSize::eMaxContentMaxSizing, TrackSize::eSkipGrowUnlimited1);
10966 // Note that eMaxContentMinSizing is always included. We do those first:
10967 if ((selector &= ~TrackSize::eMaxContentMinSizing)) {
10968 numGrowable = MarkExcludedTracks(numGrowable, aGrowableTracks, selector,
10969 TrackSize::eIntrinsicMaxSizing,
10970 TrackSize::eSkipGrowUnlimited2);
10971 }
10972 return numGrowable;
10973}
10974
10975uint32_t nsGridContainerFrame::ItemPlan::MarkExcludedTracks(
10976 uint32_t aNumGrowable, const nsTArray<uint32_t>& aGrowableTracks,
10977 TrackSize::StateBits aMinSizingSelector,
10978 TrackSize::StateBits aMaxSizingSelector, TrackSize::StateBits aSkipFlag) {
10979 bool foundOneSelected = false;
10980 bool foundOneGrowable = false;
10981 uint32_t numGrowable = aNumGrowable;
10982 for (uint32_t track : aGrowableTracks) {
10983 TrackSize& sz = mTrackSizes[track];
10984 const auto state = sz.mState;
10985 if (state & aMinSizingSelector) {
10986 foundOneSelected = true;
10987 if (state & aMaxSizingSelector) {
10988 foundOneGrowable = true;
10989 continue;
10990 }
10991 sz.mState |= aSkipFlag;
10992 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", 10992
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numGrowable != 0"
")"); do { MOZ_CrashSequence(__null, 10992); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10993 --numGrowable;
10994 }
10995 }
10996 // 12.5 "if there are no such tracks, then all affected tracks"
10997 if (foundOneSelected && !foundOneGrowable) {
10998 for (uint32_t track : aGrowableTracks) {
10999 mTrackSizes[track].mState &= ~aSkipFlag;
11000 }
11001 numGrowable = aNumGrowable;
11002 }
11003 return numGrowable;
11004}
11005
11006void nsGridContainerFrame::ItemPlan::GrowSelectedTracksUnlimited(
11007 nscoord aAvailableSpace, const nsTArray<uint32_t>& aGrowableTracks,
11008 uint32_t aNumGrowable, const FitContentClamper& aFitContentClamper) {
11009 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", 11010
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 11010); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11010 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", 11010
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAvailableSpace > 0 && aGrowableTracks.Length() > 0 && aNumGrowable <= aGrowableTracks.Length()"
")"); do { MOZ_CrashSequence(__null, 11010); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11011 nscoord space = aAvailableSpace;
11012 DebugOnly<bool> didClamp = false;
11013 while (aNumGrowable) {
11014 nscoord spacePerTrack = std::max<nscoord>(space / aNumGrowable, 1);
11015 for (uint32_t track : aGrowableTracks) {
11016 TrackSize& sz = mTrackSizes[track];
11017 if (sz.mState & TrackSize::eSkipGrowUnlimited) {
11018 continue; // an excluded track
11019 }
11020 nscoord delta = spacePerTrack;
11021 nscoord newBase = sz.mBase + delta;
11022 if (MOZ_UNLIKELY((sz.mState & TrackSize::eApplyFitContentClamping) &&(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
11023 aFitContentClamper)(__builtin_expect(!!((sz.mState & TrackSize::eApplyFitContentClamping
) && aFitContentClamper), 0))
) {
11024 // Clamp newBase to the fit-content() size, for §12.5.2 step 5/6.
11025 if (aFitContentClamper(track, sz.mBase, &newBase)) {
11026 didClamp = true;
11027 delta = newBase - sz.mBase;
11028 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"
, 11028); AnnotateMozCrashReason("MOZ_ASSERT" "(" "delta >= 0"
") (" "track size shouldn't shrink" ")"); do { MOZ_CrashSequence
(__null, 11028); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11029 sz.mState |= TrackSize::eSkipGrowUnlimited1;
11030 --aNumGrowable;
11031 }
11032 }
11033 sz.mBase = newBase;
11034 space -= delta;
11035 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", 11035)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "space >= 0" ")"
); do { MOZ_CrashSequence(__null, 11035); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11036 if (space == 0) {
11037 return;
11038 }
11039 }
11040 }
11041 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"
, 11043); 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, 11043); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11042 "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"
, 11043); 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, 11043); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
11043 "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"
, 11043); 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, 11043); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11044}