Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/base/./../../../layout/base/nsCSSFrameConstructor.cpp
Warning:line 6896, column 5
Value stored to 'parentType' 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_base1.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/base -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/base -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/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/layout/forms -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/mathml -I /root/firefox-clang/layout/painting -I /root/firefox-clang/layout/printing -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/tables -I /root/firefox-clang/layout/xul -I /root/firefox-clang/layout/xul/tree -I /root/firefox-clang/docshell/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/html -I /root/firefox-clang/dom/svg -I /root/firefox-clang/dom/xul -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 -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-11-12-001017-1011516-1 -x c++ Unified_cpp_layout_base1.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/*
6 * construction of a frame tree that is nearly isomorphic to the content
7 * tree and updating of that tree in response to dynamic changes
8 */
9
10#include "nsCSSFrameConstructor.h"
11
12#include "ActiveLayerTracker.h"
13#include "ChildIterator.h"
14#include "PseudoStyleType.h"
15#include "RetainedDisplayListBuilder.h"
16#include "RubyUtils.h"
17#include "StickyScrollContainer.h"
18#include "mozilla/AbsoluteContainingBlock.h"
19#include "mozilla/Assertions.h"
20#include "mozilla/AutoRestore.h"
21#include "mozilla/ComputedStyleInlines.h"
22#include "mozilla/DebugOnly.h"
23#include "mozilla/ErrorResult.h"
24#include "mozilla/Likely.h"
25#include "mozilla/ManualNAC.h"
26#include "mozilla/PresShell.h"
27#include "mozilla/PresShellInlines.h"
28#include "mozilla/PrintedSheetFrame.h"
29#include "mozilla/ProfilerLabels.h"
30#include "mozilla/ProfilerMarkers.h"
31#include "mozilla/RestyleManager.h"
32#include "mozilla/SVGGradientFrame.h"
33#include "mozilla/ScopeExit.h"
34#include "mozilla/ScrollContainerFrame.h"
35#include "mozilla/ServoBindings.h"
36#include "mozilla/ServoStyleSetInlines.h"
37#include "mozilla/StaticPrefs_browser.h"
38#include "mozilla/StaticPrefs_layout.h"
39#include "mozilla/StaticPrefs_mathml.h"
40#include "mozilla/dom/BindContext.h"
41#include "mozilla/dom/BrowsingContext.h"
42#include "mozilla/dom/CharacterData.h"
43#include "mozilla/dom/CharacterDataBuffer.h"
44#include "mozilla/dom/Document.h"
45#include "mozilla/dom/DocumentInlines.h"
46#include "mozilla/dom/Element.h"
47#include "mozilla/dom/ElementInlines.h"
48#include "mozilla/dom/GeneratedImageContent.h"
49#include "mozilla/dom/HTMLInputElement.h"
50#include "mozilla/dom/HTMLLabelElement.h"
51#include "mozilla/dom/HTMLSelectElement.h"
52#include "mozilla/dom/HTMLSharedListElement.h"
53#include "mozilla/dom/HTMLSummaryElement.h"
54#include "mozilla/dom/ShadowRoot.h"
55#include "mozilla/intl/LocaleService.h"
56#include "nsAtom.h"
57#include "nsAutoLayoutPhase.h"
58#include "nsBlockFrame.h"
59#include "nsCRT.h"
60#include "nsCanvasFrame.h"
61#include "nsCheckboxRadioFrame.h"
62#include "nsComboboxControlFrame.h"
63#include "nsContainerFrame.h"
64#include "nsContentUtils.h"
65#include "nsError.h"
66#include "nsFieldSetFrame.h"
67#include "nsFirstLetterFrame.h"
68#include "nsFlexContainerFrame.h"
69#include "nsGkAtoms.h"
70#include "nsGridContainerFrame.h"
71#include "nsHTMLParts.h"
72#include "nsIAnonymousContentCreator.h"
73#include "nsIFormControl.h"
74#include "nsIFrameInlines.h"
75#include "nsIObjectLoadingContent.h"
76#include "nsIPopupContainer.h"
77#include "nsIScriptError.h"
78#include "nsImageFrame.h"
79#include "nsInlineFrame.h"
80#include "nsLayoutUtils.h"
81#include "nsListControlFrame.h"
82#include "nsMathMLParts.h"
83#include "nsNameSpaceManager.h"
84#include "nsPageContentFrame.h"
85#include "nsPageFrame.h"
86#include "nsPageSequenceFrame.h"
87#include "nsPlaceholderFrame.h"
88#include "nsPresContext.h"
89#include "nsRefreshDriver.h"
90#include "nsRubyBaseContainerFrame.h"
91#include "nsRubyBaseFrame.h"
92#include "nsRubyFrame.h"
93#include "nsRubyTextContainerFrame.h"
94#include "nsRubyTextFrame.h"
95#include "nsStyleConsts.h"
96#include "nsStyleStructInlines.h"
97#include "nsTArray.h"
98#include "nsTableCellFrame.h"
99#include "nsTableColFrame.h"
100#include "nsTableFrame.h"
101#include "nsTableRowFrame.h"
102#include "nsTableRowGroupFrame.h"
103#include "nsTableWrapperFrame.h"
104#include "nsTextControlFrame.h"
105#include "nsTextNode.h"
106#include "nsTransitionManager.h"
107#include "nsUnicharUtils.h"
108#include "nsXULElement.h"
109
110#ifdef XP_MACOSX
111# include "nsIDocShell.h"
112#endif
113
114#ifdef ACCESSIBILITY1
115# include "nsAccessibilityService.h"
116#endif
117
118#undef NOISY_FIRST_LETTER
119
120using namespace mozilla;
121using namespace mozilla::dom;
122
123nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell, ComputedStyle* aStyle);
124
125nsIFrame* NS_NewHTMLVideoFrame(PresShell* aPresShell, ComputedStyle* aStyle);
126nsIFrame* NS_NewHTMLAudioFrame(PresShell* aPresShell, ComputedStyle* aStyle);
127
128nsContainerFrame* NS_NewSVGOuterSVGFrame(PresShell* aPresShell,
129 ComputedStyle* aStyle);
130nsContainerFrame* NS_NewSVGOuterSVGAnonChildFrame(PresShell* aPresShell,
131 ComputedStyle* aStyle);
132nsIFrame* NS_NewSVGInnerSVGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
133nsIFrame* NS_NewSVGGeometryFrame(PresShell* aPresShell, ComputedStyle* aStyle);
134nsIFrame* NS_NewSVGGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
135nsContainerFrame* NS_NewSVGForeignObjectFrame(PresShell* aPresShell,
136 ComputedStyle* aStyle);
137nsIFrame* NS_NewSVGAFrame(PresShell* aPresShell, ComputedStyle* aStyle);
138nsIFrame* NS_NewSVGSwitchFrame(PresShell* aPresShell, ComputedStyle* aStyle);
139nsIFrame* NS_NewSVGSymbolFrame(PresShell* aPresShell, ComputedStyle* aStyle);
140nsIFrame* NS_NewSVGTextFrame(PresShell* aPresShell, ComputedStyle* aStyle);
141nsIFrame* NS_NewSVGContainerFrame(PresShell* aPresShell, ComputedStyle* aStyle);
142nsIFrame* NS_NewSVGUseFrame(PresShell* aPresShell, ComputedStyle* aStyle);
143nsIFrame* NS_NewSVGViewFrame(PresShell* aPresShell, ComputedStyle* aStyle);
144extern nsIFrame* NS_NewSVGLinearGradientFrame(PresShell* aPresShell,
145 ComputedStyle* aStyle);
146extern nsIFrame* NS_NewSVGRadialGradientFrame(PresShell* aPresShell,
147 ComputedStyle* aStyle);
148extern nsIFrame* NS_NewSVGStopFrame(PresShell* aPresShell,
149 ComputedStyle* aStyle);
150nsContainerFrame* NS_NewSVGMarkerFrame(PresShell* aPresShell,
151 ComputedStyle* aStyle);
152nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(PresShell* aPresShell,
153 ComputedStyle* aStyle);
154extern nsIFrame* NS_NewSVGImageFrame(PresShell* aPresShell,
155 ComputedStyle* aStyle);
156nsIFrame* NS_NewSVGClipPathFrame(PresShell* aPresShell, ComputedStyle* aStyle);
157nsIFrame* NS_NewSVGFilterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
158nsIFrame* NS_NewSVGPatternFrame(PresShell* aPresShell, ComputedStyle* aStyle);
159nsIFrame* NS_NewSVGMaskFrame(PresShell* aPresShell, ComputedStyle* aStyle);
160nsIFrame* NS_NewSVGFEContainerFrame(PresShell* aPresShell,
161 ComputedStyle* aStyle);
162nsIFrame* NS_NewSVGFELeafFrame(PresShell* aPresShell, ComputedStyle* aStyle);
163nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
164nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
165 ComputedStyle* aStyle);
166nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
167nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
168nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);
169nsIFrame* NS_NewInputButtonControlFrame(PresShell*, ComputedStyle*);
170
171#include "mozilla/dom/NodeInfo.h"
172#include "nsContentCreatorFunctions.h"
173#include "nsNodeInfoManager.h"
174#include "prenv.h"
175
176#ifdef DEBUG1
177// Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
178// more of the following flags (comma separated) for handy debug
179// output.
180static bool gNoisyContentUpdates = false;
181static bool gReallyNoisyContentUpdates = false;
182static bool gNoisyInlineConstruction = false;
183
184struct FrameCtorDebugFlags {
185 const char* name;
186 bool* on;
187};
188
189static FrameCtorDebugFlags gFrameCtorDebugFlags[] = {
190 {"content-updates", &gNoisyContentUpdates},
191 {"really-noisy-content-updates", &gReallyNoisyContentUpdates},
192 {"noisy-inline", &gNoisyInlineConstruction}};
193
194# define NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags)) (std::size(gFrameCtorDebugFlags))
195#endif
196
197//------------------------------------------------------------------
198
199nsIFrame* NS_NewLeafBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
200
201nsIFrame* NS_NewRangeFrame(PresShell* aPresShell, ComputedStyle* aStyle);
202
203nsIFrame* NS_NewTextBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
204
205nsIFrame* NS_NewSplitterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
206
207nsIFrame* NS_NewMenuPopupFrame(PresShell* aPresShell, ComputedStyle* aStyle);
208
209nsIFrame* NS_NewTreeBodyFrame(PresShell* aPresShell, ComputedStyle* aStyle);
210
211nsIFrame* NS_NewSliderFrame(PresShell* aPresShell, ComputedStyle* aStyle);
212
213nsIFrame* NS_NewScrollbarFrame(PresShell* aPresShell, ComputedStyle* aStyle);
214
215nsIFrame* NS_NewScrollbarButtonFrame(PresShell*, ComputedStyle*);
216nsIFrame* NS_NewSimpleXULLeafFrame(PresShell*, ComputedStyle*);
217
218nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
219nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
220nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
221nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
222nsIFrame* NS_NewImageFrameForViewTransition(PresShell*, ComputedStyle*);
223
224// Returns true if aFrame is an anonymous flex/grid item.
225static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
226 return aFrame->Style()->GetPseudoType() == PseudoStyleType::MozAnonymousItem;
227}
228
229// Returns true IFF the given nsIFrame is a nsFlexContainerFrame and represents
230// a -webkit-{inline-}box container.
231static inline bool IsFlexContainerForLegacyWebKitBox(const nsIFrame* aFrame) {
232 return aFrame->IsFlexContainerFrame() && aFrame->IsLegacyWebkitBox();
233}
234
235static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
236 const nsIFrame* aChild, const nsIFrame* aParent) {
237 MOZ_ASSERT(IsAnonymousItem(aChild), "expected an anonymous item child frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsAnonymousItem(aChild))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsAnonymousItem(aChild)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsAnonymousItem(aChild)"
" (" "expected an anonymous item child frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsAnonymousItem(aChild)"
") (" "expected an anonymous item child frame" ")"); do { MOZ_CrashSequence
(__null, 237); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
238 MOZ_ASSERT(aParent, "expected a parent frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aParent" " (" "expected a parent frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 238
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ") (" "expected a parent frame"
")"); do { MOZ_CrashSequence(__null, 238); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
239 MOZ_ASSERT(aParent->IsFlexOrGridContainer(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->IsFlexOrGridContainer())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->IsFlexOrGridContainer
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->IsFlexOrGridContainer()" " (" "anonymous items should only exist as children of flex/grid "
"container frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 241)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
240 "anonymous items should only exist as children of flex/grid "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->IsFlexOrGridContainer())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->IsFlexOrGridContainer
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->IsFlexOrGridContainer()" " (" "anonymous items should only exist as children of flex/grid "
"container frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 241)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
241 "container frames")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->IsFlexOrGridContainer())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->IsFlexOrGridContainer
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->IsFlexOrGridContainer()" " (" "anonymous items should only exist as children of flex/grid "
"container frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 241)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
242}
243
244static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
245 const nsIFrame* aChild) {
246 AssertAnonymousFlexOrGridItemParent(aChild, aChild->GetParent());
247}
248
249#define ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
\
250 [](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { \
251 return _func(aPs, aStyle); \
252 }
253
254/**
255 * True if aFrame is an actual inline frame in the sense of non-replaced
256 * display:inline CSS boxes. In other words, it can be affected by {ib}
257 * splitting and can contain first-letter frames. Basically, this is either an
258 * inline frame (positioned or otherwise) or an line frame (this last because
259 * it can contain first-letter and because inserting blocks in the middle of it
260 * needs to terminate it).
261 */
262static bool IsInlineFrame(const nsIFrame* aFrame) {
263 return aFrame->IsLineParticipant();
264}
265
266/**
267 * True for display: contents elements.
268 */
269static inline bool IsDisplayContents(const Element* aElement) {
270 return aElement->IsDisplayContents();
271}
272
273static inline bool IsDisplayContents(const nsIContent* aContent) {
274 return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
275}
276
277/**
278 * True if aFrame is an instance of an SVG frame class or is an inline/block
279 * frame being used for SVG text.
280 */
281static bool IsFrameForSVG(const nsIFrame* aFrame) {
282 return aFrame->IsSVGFrame() || aFrame->IsInSVGTextSubtree();
283}
284
285static bool IsLastContinuationForColumnContent(const nsIFrame* aFrame) {
286 MOZ_ASSERT(aFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 286); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ")")
; do { MOZ_CrashSequence(__null, 286); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
287 return aFrame->Style()->GetPseudoType() ==
288 PseudoStyleType::MozColumnContent &&
289 !aFrame->GetNextContinuation();
290}
291
292/**
293 * Returns true iff aFrame explicitly prevents its descendants from floating
294 * (at least, down to the level of descendants which themselves are
295 * float-containing blocks -- those will manage the floating status of any
296 * lower-level descendents inside them, of course).
297 */
298static bool ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) {
299 return aFrame->IsFlexOrGridContainer() || aFrame->IsMathMLFrame();
300}
301
302// Return true if column-span descendants should be suppressed under aFrame's
303// subtree (until a multi-column container re-establishing a block formatting
304// context). Basically, this is testing whether aFrame establishes a new block
305// formatting context or not.
306static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
307 if (aFrame->Style()->GetPseudoType() == PseudoStyleType::MozColumnContent) {
308 // Never suppress column-span under ::-moz-column-content frames.
309 return false;
310 }
311
312 if (aFrame->IsInlineFrame()) {
313 // Allow inline frames to have column-span block children.
314 return false;
315 }
316
317 if (!aFrame->IsBlockFrameOrSubclass() ||
318 aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) ||
319 aFrame->IsFixedPosContainingBlock()) {
320 // Need to suppress column-span if we:
321 // - Are a different block formatting context,
322 // - Are an out-of-flow frame, OR
323 // - Establish a containing block for fixed-position descendants
324 //
325 // For example, the children of a column-span never need to be further
326 // processed even if there is a nested column-span child. Because a
327 // column-span always creates its own block formatting context, a nested
328 // column-span child won't be in the same block formatting context with the
329 // nearest multi-column ancestor. This is the same case as if the
330 // column-span is outside of a multi-column hierarchy.
331 return true;
332 }
333
334 return false;
335}
336
337// Reparent a frame into a wrapper frame that is a child of its old parent.
338static void ReparentFrame(RestyleManager* aRestyleManager,
339 nsContainerFrame* aNewParentFrame, nsIFrame* aFrame,
340 bool aForceStyleReparent) {
341 aFrame->SetParent(aNewParentFrame);
342 // We reparent frames for two reasons: to put them inside ::first-line, and to
343 // put them inside some wrapper anonymous boxes.
344 if (aForceStyleReparent) {
345 aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
346 }
347}
348
349static void ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
350 nsContainerFrame* aNewParentFrame,
351 const nsFrameList& aFrameList,
352 bool aForceStyleReparent) {
353 RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
354 for (nsIFrame* f : aFrameList) {
355 ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
356 }
357}
358
359//----------------------------------------------------------------------
360//
361// When inline frames get weird and have block frames in them, we
362// annotate them to help us respond to incremental content changes
363// more easily.
364
365static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) {
366 bool result = aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT);
367 MOZ_ASSERT(!result || aFrame->IsBlockFrameOrSubclass() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!result || aFrame->IsBlockFrameOrSubclass() || aFrame
->IsInlineFrameOrSubclass())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!result || aFrame->IsBlockFrameOrSubclass
() || aFrame->IsInlineFrameOrSubclass()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
" (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 369
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 369); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
368 aFrame->IsInlineFrameOrSubclass(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!result || aFrame->IsBlockFrameOrSubclass() || aFrame
->IsInlineFrameOrSubclass())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!result || aFrame->IsBlockFrameOrSubclass
() || aFrame->IsInlineFrameOrSubclass()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
" (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 369
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 369); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
369 "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!result || aFrame->IsBlockFrameOrSubclass() || aFrame
->IsInlineFrameOrSubclass())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!result || aFrame->IsBlockFrameOrSubclass
() || aFrame->IsInlineFrameOrSubclass()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
" (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 369
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 369); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
370 return result;
371}
372
373static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) {
374 MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFramePartOfIBSplit(aFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFramePartOfIBSplit(aFrame)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"IsFramePartOfIBSplit(aFrame)" " (" "Shouldn't call this" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 374); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 374); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
375
376 // We only store the "ib-split sibling" annotation with the first
377 // frame in the continuation chain. Walk back to find that frame now.
378 return aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
379}
380
381static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) {
382 MOZ_ASSERT(IsFramePartOfIBSplit(aFrame), "Shouldn't call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFramePartOfIBSplit(aFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFramePartOfIBSplit(aFrame)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"IsFramePartOfIBSplit(aFrame)" " (" "Shouldn't call this" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 382); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 382); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
383
384 // We only store the ib-split sibling annotation with the first
385 // frame in the continuation chain. Walk back to find that frame now.
386 return aFrame->FirstContinuation()->GetProperty(
387 nsIFrame::IBSplitPrevSibling());
388}
389
390static nsContainerFrame* GetLastIBSplitSibling(nsIFrame* aFrame) {
391 for (nsIFrame *frame = aFrame, *next;; frame = next) {
392 next = GetIBSplitSibling(frame);
393 if (!next) {
394 return static_cast<nsContainerFrame*>(frame);
395 }
396 }
397 MOZ_ASSERT_UNREACHABLE("unreachable code")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: "
"unreachable code" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 397); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unreachable code" ")"); do { MOZ_CrashSequence
(__null, 397); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
398 return nullptr;
399}
400
401static void SetFrameIsIBSplit(nsContainerFrame* aFrame,
402 nsContainerFrame* aIBSplitSibling) {
403 MOZ_ASSERT(aFrame, "bad args!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "bad args!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 403
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "bad args!"
")"); do { MOZ_CrashSequence(__null, 403); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
404
405 // We should be the only continuation
406 NS_ASSERTION(!aFrame->GetPrevContinuation(),do { if (!(!aFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "assigning ib-split sibling to other than first continuation!"
, "!aFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 407); MOZ_PretendNoReturn(); } } while (0)
407 "assigning ib-split sibling to other than first continuation!")do { if (!(!aFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "assigning ib-split sibling to other than first continuation!"
, "!aFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 407); MOZ_PretendNoReturn(); } } while (0)
;
408 NS_ASSERTION(!aFrame->GetNextContinuation() ||do { if (!(!aFrame->GetNextContinuation() || IsFramePartOfIBSplit
(aFrame->GetNextContinuation()))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have no non-ib-split continuations here", "!aFrame->GetNextContinuation() || IsFramePartOfIBSplit(aFrame->GetNextContinuation())"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 410); MOZ_PretendNoReturn
(); } } while (0)
409 IsFramePartOfIBSplit(aFrame->GetNextContinuation()),do { if (!(!aFrame->GetNextContinuation() || IsFramePartOfIBSplit
(aFrame->GetNextContinuation()))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have no non-ib-split continuations here", "!aFrame->GetNextContinuation() || IsFramePartOfIBSplit(aFrame->GetNextContinuation())"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 410); MOZ_PretendNoReturn
(); } } while (0)
410 "should have no non-ib-split continuations here")do { if (!(!aFrame->GetNextContinuation() || IsFramePartOfIBSplit
(aFrame->GetNextContinuation()))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have no non-ib-split continuations here", "!aFrame->GetNextContinuation() || IsFramePartOfIBSplit(aFrame->GetNextContinuation())"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 410); MOZ_PretendNoReturn
(); } } while (0)
;
411
412 // Mark the frame as ib-split.
413 aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
414
415 if (aIBSplitSibling) {
416 NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(),do { if (!(!aIBSplitSibling->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "assigning something other than the first continuation as the "
"ib-split sibling", "!aIBSplitSibling->GetPrevContinuation()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 418); MOZ_PretendNoReturn
(); } } while (0)
417 "assigning something other than the first continuation as the "do { if (!(!aIBSplitSibling->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "assigning something other than the first continuation as the "
"ib-split sibling", "!aIBSplitSibling->GetPrevContinuation()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 418); MOZ_PretendNoReturn
(); } } while (0)
418 "ib-split sibling")do { if (!(!aIBSplitSibling->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "assigning something other than the first continuation as the "
"ib-split sibling", "!aIBSplitSibling->GetPrevContinuation()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 418); MOZ_PretendNoReturn
(); } } while (0)
;
419
420 // Store the ib-split sibling (if we were given one) with the
421 // first frame in the flow.
422 aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
423 aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
424 }
425}
426
427static nsIFrame* GetIBContainingBlockFor(nsIFrame* aFrame) {
428 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFramePartOfIBSplit(aFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFramePartOfIBSplit(aFrame)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"IsFramePartOfIBSplit(aFrame)" " (" "GetIBContainingBlockFor() should only be called on known IB frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 430
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 430); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
429 IsFramePartOfIBSplit(aFrame),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFramePartOfIBSplit(aFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFramePartOfIBSplit(aFrame)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"IsFramePartOfIBSplit(aFrame)" " (" "GetIBContainingBlockFor() should only be called on known IB frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 430
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 430); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
430 "GetIBContainingBlockFor() should only be called on known IB frames")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFramePartOfIBSplit(aFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFramePartOfIBSplit(aFrame)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"IsFramePartOfIBSplit(aFrame)" " (" "GetIBContainingBlockFor() should only be called on known IB frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 430
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 430); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
431
432 // Get the first "normal" ancestor of the target frame.
433 nsIFrame* parentFrame;
434 do {
435 parentFrame = aFrame->GetParent();
436
437 if (!parentFrame) {
438 NS_ERROR("no unsplit block frame in IB hierarchy")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "no unsplit block frame in IB hierarchy"
, "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 438); MOZ_PretendNoReturn(); } while (0)
;
439 return aFrame;
440 }
441
442 // Note that we ignore non-ib-split frames which have a pseudo on their
443 // ComputedStyle -- they're not the frames we're looking for! In
444 // particular, they may be hiding a real parent that _is_ in an ib-split.
445 if (!IsFramePartOfIBSplit(parentFrame) &&
446 !parentFrame->Style()->IsPseudoOrAnonBox()) {
447 break;
448 }
449
450 aFrame = parentFrame;
451 } while (true);
452
453 // post-conditions
454 NS_ASSERTION(parentFrame,do { if (!(parentFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "no normal ancestor found for ib-split frame "
"in GetIBContainingBlockFor", "parentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 456); MOZ_PretendNoReturn(); } } while (0)
455 "no normal ancestor found for ib-split frame "do { if (!(parentFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "no normal ancestor found for ib-split frame "
"in GetIBContainingBlockFor", "parentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 456); MOZ_PretendNoReturn(); } } while (0)
456 "in GetIBContainingBlockFor")do { if (!(parentFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "no normal ancestor found for ib-split frame "
"in GetIBContainingBlockFor", "parentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 456); MOZ_PretendNoReturn(); } } while (0)
;
457 NS_ASSERTION(parentFrame != aFrame,do { if (!(parentFrame != aFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "parentFrame is actually the child frame - bogus reslt", "parentFrame != aFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 458); MOZ_PretendNoReturn
(); } } while (0)
458 "parentFrame is actually the child frame - bogus reslt")do { if (!(parentFrame != aFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "parentFrame is actually the child frame - bogus reslt", "parentFrame != aFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 458); MOZ_PretendNoReturn
(); } } while (0)
;
459
460 return parentFrame;
461}
462
463// Find the multicol containing block suitable for reframing.
464//
465// Note: this function may not return a ColumnSetWrapperFrame. For example, if
466// the multicol containing block has "overflow:scroll" style,
467// ScrollContainerFrame is returned because ColumnSetWrapperFrame is the
468// scrolled frame which has the -moz-scrolled-content pseudo style. We may walk
469// up "too far", but in terms of correctness of reframing, it's OK.
470static nsContainerFrame* GetMultiColumnContainingBlockFor(nsIFrame* aFrame) {
471 MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Should only be called if the frame has a multi-column ancestor!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 472
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Should only be called if the frame has a multi-column ancestor!"
")"); do { MOZ_CrashSequence(__null, 472); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
472 "Should only be called if the frame has a multi-column ancestor!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Should only be called if the frame has a multi-column ancestor!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 472
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Should only be called if the frame has a multi-column ancestor!"
")"); do { MOZ_CrashSequence(__null, 472); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
473
474 nsContainerFrame* current = aFrame->GetParent();
475 while (current &&
476 (current->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
477 current->Style()->IsPseudoOrAnonBox())) {
478 current = current->GetParent();
479 }
480
481 MOZ_ASSERT(current,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(current)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(current))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("current" " (" "No multicol containing block in a valid column hierarchy?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 482
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 482); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
482 "No multicol containing block in a valid column hierarchy?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(current)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(current))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("current" " (" "No multicol containing block in a valid column hierarchy?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 482
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 482); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
483
484 return current;
485}
486
487static bool InsertSeparatorBeforeAccessKey() {
488 static bool sInitialized = false;
489 static bool sValue = false;
490 if (!sInitialized) {
491 sInitialized = true;
492 sValue =
493 intl::LocaleService::GetInstance()->InsertSeparatorBeforeAccesskeys();
494 }
495 return sValue;
496}
497
498static bool AlwaysAppendAccessKey() {
499 static bool sInitialized = false;
500 static bool sValue = false;
501 if (!sInitialized) {
502 sInitialized = true;
503 sValue = intl::LocaleService::GetInstance()->AlwaysAppendAccesskeys();
504 }
505 return sValue;
506}
507
508//----------------------------------------------------------------------
509
510// Block/inline frame construction logic. We maintain a few invariants here:
511//
512// 1. Block frames contain block and inline frames.
513//
514// 2. Inline frames only contain inline frames. If an inline parent has a block
515// child then the block child is migrated upward until it lands in a block
516// parent (the inline frames containing block is where it will end up).
517
518inline void SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame) {
519 MOZ_ASSERT(!aFrame->GetNextSibling(), "Should be using a frame list")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->GetNextSibling()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->GetNextSibling()" " (" "Should be using a frame list"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 519
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->GetNextSibling()"
") (" "Should be using a frame list" ")"); do { MOZ_CrashSequence
(__null, 519); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
520 aParent->SetInitialChildList(FrameChildListID::Principal,
521 nsFrameList(aFrame, aFrame));
522}
523
524// -----------------------------------------------------------
525
526// Structure used when constructing formatting object trees. Contains
527// state information needed for absolutely positioned elements
528namespace mozilla {
529struct AbsoluteFrameList final : public nsFrameList {
530 // Containing block for absolutely positioned elements.
531 nsContainerFrame* mContainingBlock;
532
533 explicit AbsoluteFrameList(nsContainerFrame* aContainingBlock = nullptr)
534 : mContainingBlock(aContainingBlock) {}
535
536 // Transfer frames in aOther to this list. aOther becomes empty after this
537 // operation.
538 AbsoluteFrameList(AbsoluteFrameList&& aOther) = default;
539 AbsoluteFrameList& operator=(AbsoluteFrameList&& aOther) = default;
540
541#ifdef DEBUG1
542 // XXXbz Does this need a debug-only assignment operator that nulls out the
543 // childList in the AbsoluteFrameList we're copying? Introducing a difference
544 // between debug and non-debug behavior seems bad, so I guess not...
545 ~AbsoluteFrameList() {
546 NS_ASSERTION(!FirstChild(),do { if (!(!FirstChild())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Dangling child list. Someone forgot to insert it?", "!FirstChild()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 547); MOZ_PretendNoReturn
(); } } while (0)
547 "Dangling child list. Someone forgot to insert it?")do { if (!(!FirstChild())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Dangling child list. Someone forgot to insert it?", "!FirstChild()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 547); MOZ_PretendNoReturn
(); } } while (0)
;
548 }
549#endif
550};
551} // namespace mozilla
552
553// -----------------------------------------------------------
554
555// Structure for saving the existing state when pushing/poping containing
556// blocks. The destructor restores the state to its previous state
557class MOZ_STACK_CLASS nsFrameConstructorSaveState {
558 public:
559 ~nsFrameConstructorSaveState();
560
561 private:
562 // Pointer to struct whose data we save/restore.
563 AbsoluteFrameList* mList = nullptr;
564
565 // The saved pointer to the fixed list.
566 AbsoluteFrameList* mSavedFixedList = nullptr;
567
568 // Copy of original frame list. This can be the original absolute list or a
569 // float list.
570 AbsoluteFrameList mSavedList;
571
572 // The name of the child list in which our frames would belong.
573 mozilla::FrameChildListID mChildListID = FrameChildListID::Principal;
574 nsFrameConstructorState* mState = nullptr;
575
576 friend class nsFrameConstructorState;
577};
578
579// Structure used for maintaining state information during the
580// frame construction process
581class MOZ_STACK_CLASS nsFrameConstructorState {
582 public:
583 nsPresContext* mPresContext;
584 PresShell* mPresShell;
585 nsCSSFrameConstructor* mFrameConstructor;
586
587 // Containing block information for out-of-flow frames.
588 //
589 // Floats are easy. Whatever is our float CB.
590 //
591 // Regular abspos elements are easy too. Its containing block can be the
592 // nearest abspos element, or the ICB (the canvas frame).
593 //
594 // Top layer abspos elements are always children of the ICB, but we can get
595 // away with having two different lists (mAbsoluteList and
596 // mTopLayerAbsoluteList), because because top layer frames cause
597 // non-top-layer frames to be contained inside (so any descendants of a top
598 // layer abspos can never share containing block with it, unless they're also
599 // in the top layer).
600 //
601 // Regular fixed elements however are trickier. Fixed elements can be
602 // contained in one of three lists:
603 //
604 // * mAbsoluteList, if our abspos cb is also a fixpos cb (e.g., is
605 // transformed or has a filter).
606 //
607 // * mAncestorFixedList, if the fixpos cb is an ancestor element other than
608 // the viewport frame, (so, a transformed / filtered
609 // ancestor).
610 //
611 // * mRealFixedList, which is also the fixed list used for the top layer
612 // fixed items, which is the fixed list of the viewport
613 // frame.
614 //
615 // It is important that mRealFixedList is shared between regular and top layer
616 // fixpos elements, since no-top-layer descendants of top layer fixed elements
617 // could share ICB and vice versa, so without that there would be no guarantee
618 // of layout ordering between them.
619 AbsoluteFrameList mFloatedList;
620 AbsoluteFrameList mAbsoluteList;
621 AbsoluteFrameList mTopLayerAbsoluteList;
622 AbsoluteFrameList mAncestorFixedList;
623 AbsoluteFrameList mRealFixedList;
624
625 // Never null, always pointing to one of the lists documented above.
626 AbsoluteFrameList* mFixedList;
627
628 // What `page: auto` resolves to. This is the used page-name of the parent
629 // frame. Updated by AutoFrameConstructionPageName.
630 const nsAtom* mAutoPageNameValue = nullptr;
631
632 nsCOMPtr<nsILayoutHistoryState> mFrameState;
633 // These bits will be added to the state bits of any frame we construct
634 // using this state.
635 nsFrameState mAdditionalStateBits = NS_FRAME_STATE_NONE;
636
637 // If false (which is the default) then call SetPrimaryFrame() as needed
638 // during frame construction. If true, don't make any SetPrimaryFrame()
639 // calls, except for generated content which doesn't have a primary frame
640 // yet. The mCreatingExtraFrames == true mode is meant to be used for
641 // construction of random "extra" frames for elements via normal frame
642 // construction APIs (e.g. replication of things across pages in paginated
643 // mode).
644 bool mCreatingExtraFrames;
645
646 // This keeps track of whether we have found a "rendered legend" for
647 // the current FieldSetFrame.
648 bool mHasRenderedLegend;
649
650 nsTArray<RefPtr<nsIContent>> mGeneratedContentWithInitializer;
651
652#ifdef DEBUG1
653 // Record the float containing block candidate passed into
654 // MaybePushFloatContainingBlock() to keep track that we've call the method to
655 // handle the float CB scope before processing the CB's children. It is reset
656 // in ConstructFramesFromItemList().
657 nsContainerFrame* mFloatCBCandidate = nullptr;
658#endif
659
660 // Constructor
661 nsFrameConstructorState(PresShell* aPresShell,
662 nsContainerFrame* aFixedContainingBlock,
663 nsContainerFrame* aAbsoluteContainingBlock,
664 nsContainerFrame* aFloatContainingBlock);
665
666 enum { ForRepeatingTableHeaders };
667 nsFrameConstructorState(PresShell* aPresShell,
668 decltype(ForRepeatingTableHeaders));
669
670 ~nsFrameConstructorState();
671
672 // Process the frame insertions for all the out-of-flow nsAbsoluteItems.
673 void ProcessFrameInsertionsForAllLists();
674
675 // Function to push the existing absolute containing block state and
676 // create a new scope. Code that uses this function should get matching
677 // logic in GetAbsoluteContainingBlock.
678 // Also makes aNewAbsoluteContainingBlock the containing block for
679 // fixed-pos elements if necessary.
680 // aPositionedFrame is the frame whose style actually makes
681 // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable
682 // element aPositionedFrame is the element's primary frame and
683 // aNewAbsoluteContainingBlock is the scrolled frame.
684 void PushAbsoluteContainingBlock(
685 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
686 nsFrameConstructorSaveState& aSaveState);
687
688 // Function to forbid floats descendants under aFloatCBCandidate, or open a
689 // new float containing block scope for aFloatCBCandidate. The current
690 // state is saved in aSaveState if a new scope is pushed.
691 void MaybePushFloatContainingBlock(nsContainerFrame* aFloatCBCandidate,
692 nsFrameConstructorSaveState& aSaveState);
693
694 // Helper function for MaybePushFloatContainingBlock().
695 void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
696 nsFrameConstructorSaveState& aSaveState);
697
698 // Function to return the proper geometric parent for a frame with display
699 // struct given by aStyleDisplay and parent's frame given by
700 // aContentParentFrame.
701 nsContainerFrame* GetGeometricParent(
702 const nsStyleDisplay& aStyleDisplay,
703 nsContainerFrame* aContentParentFrame) const;
704
705 // Collect absolute frames in mAbsoluteList which are proper descendants
706 // of aNewParent, and reparent them to aNewParent.
707 //
708 // Note: This function does something unusual that moves absolute items
709 // after their frames are constructed under a column hierarchy which has
710 // column-span elements. Do not use this if you're not dealing with
711 // columns.
712 void ReparentAbsoluteItems(nsContainerFrame* aNewParent);
713
714 // Collect floats in mFloatedList which are proper descendants of aNewParent,
715 // and reparent them to aNewParent.
716 //
717 // Note: This function does something unusual that moves floats after their
718 // frames are constructed under a column hierarchy which has column-span
719 // elements. Do not use this if you're not dealing with columns.
720 void ReparentFloats(nsContainerFrame* aNewParent);
721
722 /**
723 * Function to add a new frame to the right frame list. This MUST be called
724 * on frames before their children have been processed if the frames might
725 * conceivably be out-of-flow; otherwise cleanup in error cases won't work
726 * right. Also, this MUST be called on frames after they have been
727 * initialized.
728 * @param aNewFrame the frame to add
729 * @param aFrameList the list to add in-flow frames to
730 * @param aContent the content pointer for aNewFrame
731 * @param aParentFrame the parent frame for the content if it were in-flow
732 * @param aCanBePositioned pass false if the frame isn't allowed to be
733 * positioned
734 * @param aCanBeFloated pass false if the frame isn't allowed to be
735 * floated
736 */
737 void AddChild(nsIFrame* aNewFrame, nsFrameList& aFrameList,
738 nsIContent* aContent, nsContainerFrame* aParentFrame,
739 bool aCanBePositioned = true, bool aCanBeFloated = true,
740 bool aInsertAfter = false,
741 nsIFrame* aInsertAfterFrame = nullptr);
742
743 /**
744 * Function to return the fixed-pos element list. Normally this will just
745 * hand back the fixed-pos element list, but in case we're dealing with a
746 * transformed element that's acting as an abs-pos and fixed-pos container,
747 * we'll hand back the abs-pos list. Callers should use this function if they
748 * want to get the list acting as the fixed-pos item parent.
749 */
750 AbsoluteFrameList& GetFixedList() { return *mFixedList; }
751 const AbsoluteFrameList& GetFixedList() const { return *mFixedList; }
752
753 protected:
754 friend class nsFrameConstructorSaveState;
755
756 /**
757 * ProcessFrameInsertions takes the frames in aFrameList and adds them as
758 * kids to the aChildListID child list of |aFrameList.containingBlock|.
759 */
760 void ProcessFrameInsertions(AbsoluteFrameList& aFrameList,
761 mozilla::FrameChildListID aChildListID);
762
763 /**
764 * GetOutOfFlowFrameList selects the out-of-flow frame list the new
765 * frame should be added to. If the frame shouldn't be added to any
766 * out-of-flow list, it returns nullptr. The corresponding type of
767 * placeholder is also returned via the aPlaceholderType parameter
768 * if this method doesn't return nullptr. The caller should check
769 * whether the returned list really has a containing block.
770 */
771 AbsoluteFrameList* GetOutOfFlowFrameList(nsIFrame* aNewFrame,
772 bool aCanBePositioned,
773 bool aCanBeFloated,
774 nsFrameState* aPlaceholderType);
775
776 private:
777 enum class UseTopLayerList : bool { No, Yes };
778
779 nsFrameConstructorState(PresShell* aPresShell,
780 nsContainerFrame* aFixedContainingBlock,
781 nsContainerFrame* aAbsoluteContainingBlock,
782 nsContainerFrame* aFloatContainingBlock,
783 UseTopLayerList aUseTopLayerList);
784};
785
786nsFrameConstructorState::nsFrameConstructorState(
787 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
788 nsContainerFrame* aAbsoluteContainingBlock,
789 nsContainerFrame* aFloatContainingBlock)
790 : nsFrameConstructorState(aPresShell, aFixedContainingBlock,
791 aAbsoluteContainingBlock, aFloatContainingBlock,
792 UseTopLayerList::Yes) {}
793
794nsFrameConstructorState::nsFrameConstructorState(
795 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
796 nsContainerFrame* aAbsoluteContainingBlock,
797 nsContainerFrame* aFloatContainingBlock, UseTopLayerList aUseTopLayerList)
798 : mPresContext(aPresShell->GetPresContext()),
799 mPresShell(aPresShell),
800 mFrameConstructor(aPresShell->FrameConstructor()),
801 mFloatedList(aFloatContainingBlock),
802 mAbsoluteList(aAbsoluteContainingBlock),
803 mTopLayerAbsoluteList(aUseTopLayerList == UseTopLayerList::Yes
804 ? static_cast<nsContainerFrame*>(
805 mFrameConstructor->GetCanvasFrame())
806 : nullptr),
807 mAncestorFixedList(aFixedContainingBlock),
808 mRealFixedList(aUseTopLayerList == UseTopLayerList::Yes
809 ? static_cast<nsContainerFrame*>(
810 mFrameConstructor->GetRootFrame())
811 : nullptr),
812 // See PushAbsoluteContaningBlock below
813 mFrameState(aPresShell->GetDocument()->GetLayoutHistoryState()),
814 mCreatingExtraFrames(false),
815 mHasRenderedLegend(false) {
816 MOZ_COUNT_CTOR(nsFrameConstructorState)do { static_assert(std::is_class_v<nsFrameConstructorState
>, "Token '" "nsFrameConstructorState" "' is not a class type."
); static_assert(!std::is_base_of_v<nsISupports, nsFrameConstructorState
>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "nsFrameConstructorState"
, sizeof(*this)); } while (0)
;
817 mFixedList = [&] {
818 if (aFixedContainingBlock == aAbsoluteContainingBlock) {
819 return &mAbsoluteList;
820 }
821 if (aAbsoluteContainingBlock == mRealFixedList.mContainingBlock) {
822 return &mRealFixedList;
823 }
824 return &mAncestorFixedList;
825 }();
826}
827
828nsFrameConstructorState::nsFrameConstructorState(
829 PresShell* aPresShell, decltype(ForRepeatingTableHeaders))
830 : nsFrameConstructorState(aPresShell, nullptr, nullptr, nullptr,
831 UseTopLayerList::No) {}
832
833nsFrameConstructorState::~nsFrameConstructorState() {
834 MOZ_COUNT_DTOR(nsFrameConstructorState)do { static_assert(std::is_class_v<nsFrameConstructorState
>, "Token '" "nsFrameConstructorState" "' is not a class type."
); static_assert(!std::is_base_of_v<nsISupports, nsFrameConstructorState
>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "nsFrameConstructorState"
, sizeof(*this)); } while (0)
;
835 ProcessFrameInsertionsForAllLists();
836 for (auto& content : Reversed(mGeneratedContentWithInitializer)) {
837 content->RemoveProperty(nsGkAtoms::genConInitializerProperty);
838 }
839}
840
841void nsFrameConstructorState::ProcessFrameInsertionsForAllLists() {
842 ProcessFrameInsertions(mFloatedList, FrameChildListID::Float);
843 ProcessFrameInsertions(mAbsoluteList, FrameChildListID::Absolute);
844 ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
845 ProcessFrameInsertions(*mFixedList, FrameChildListID::Absolute);
846 ProcessFrameInsertions(mRealFixedList, FrameChildListID::Absolute);
847}
848
849void nsFrameConstructorState::PushAbsoluteContainingBlock(
850 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
851 nsFrameConstructorSaveState& aSaveState) {
852 MOZ_ASSERT(!!aNewAbsoluteContainingBlock == !!aPositionedFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!!aNewAbsoluteContainingBlock == !!aPositionedFrame)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!!aNewAbsoluteContainingBlock == !!aPositionedFrame)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
" (" "We should have both or none" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 853); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 853); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
853 "We should have both or none")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!!aNewAbsoluteContainingBlock == !!aPositionedFrame)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!!aNewAbsoluteContainingBlock == !!aPositionedFrame)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
" (" "We should have both or none" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 853); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 853); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
854 aSaveState.mList = &mAbsoluteList;
855 aSaveState.mChildListID = FrameChildListID::Absolute;
856 aSaveState.mState = this;
857 aSaveState.mSavedList = std::move(mAbsoluteList);
858 aSaveState.mSavedFixedList = mFixedList;
859 mAbsoluteList = AbsoluteFrameList(aNewAbsoluteContainingBlock);
860 mFixedList = [&] {
861 if (!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock()) {
862 // See if we need to treat abspos and fixedpos the same. This happens if
863 // we're a transformed/filtered/etc element, or if we force a null abspos
864 // containing block (for mathml for example).
865 return &mAbsoluteList;
866 }
867 if (aPositionedFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Auto) {
868 // If our new CB is in the top layer, and isn't a fixed CB itself, we also
869 // escape the usual containment.
870 return &mRealFixedList;
871 }
872 if (mFixedList == &mAbsoluteList) {
873 // If we were pointing to our old absolute list, keep pointing to it.
874 return &aSaveState.mSavedList;
875 }
876 // Otherwise keep pointing to the current thing (another ancestor's
877 // absolute list, or the real fixed list, doesn't matter).
878 return mFixedList;
879 }();
880
881 if (aNewAbsoluteContainingBlock &&
882 !aNewAbsoluteContainingBlock->IsAbsoluteContainer()) {
883 aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
884 }
885}
886
887void nsFrameConstructorState::MaybePushFloatContainingBlock(
888 nsContainerFrame* aFloatCBCandidate,
889 nsFrameConstructorSaveState& aSaveState) {
890 // The logic here needs to match the logic in GetFloatContainingBlock().
891 if (ShouldSuppressFloatingOfDescendants(aFloatCBCandidate)) {
892 // Pushing a null float containing block forbids any frames from being
893 // floated until a new float containing block is pushed. See implementation
894 // of nsFrameConstructorState::AddChild().
895 //
896 // XXX we should get rid of null float containing blocks and teach the
897 // various frame classes to deal with floats instead.
898 PushFloatContainingBlock(nullptr, aSaveState);
899 } else if (aFloatCBCandidate->IsFloatContainingBlock()) {
900 PushFloatContainingBlock(aFloatCBCandidate, aSaveState);
901 }
902
903#ifdef DEBUG1
904 mFloatCBCandidate = aFloatCBCandidate;
905#endif
906}
907
908void nsFrameConstructorState::PushFloatContainingBlock(
909 nsContainerFrame* aNewFloatContainingBlock,
910 nsFrameConstructorSaveState& aSaveState) {
911 MOZ_ASSERT(!aNewFloatContainingBlock ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aNewFloatContainingBlock || aNewFloatContainingBlock
->IsFloatContainingBlock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aNewFloatContainingBlock ||
aNewFloatContainingBlock->IsFloatContainingBlock()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
" (" "Please push a real float containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 913); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
912 aNewFloatContainingBlock->IsFloatContainingBlock(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aNewFloatContainingBlock || aNewFloatContainingBlock
->IsFloatContainingBlock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aNewFloatContainingBlock ||
aNewFloatContainingBlock->IsFloatContainingBlock()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
" (" "Please push a real float containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 913); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
913 "Please push a real float containing block!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aNewFloatContainingBlock || aNewFloatContainingBlock
->IsFloatContainingBlock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aNewFloatContainingBlock ||
aNewFloatContainingBlock->IsFloatContainingBlock()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
" (" "Please push a real float containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 913); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
914 NS_ASSERTION(do { if (!(!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants
(aNewFloatContainingBlock))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should not push a frame that is supposed to _suppress_ "
"floats as a float containing block!", "!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 918); MOZ_PretendNoReturn
(); } } while (0)
915 !aNewFloatContainingBlock ||do { if (!(!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants
(aNewFloatContainingBlock))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should not push a frame that is supposed to _suppress_ "
"floats as a float containing block!", "!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 918); MOZ_PretendNoReturn
(); } } while (0)
916 !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock),do { if (!(!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants
(aNewFloatContainingBlock))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should not push a frame that is supposed to _suppress_ "
"floats as a float containing block!", "!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 918); MOZ_PretendNoReturn
(); } } while (0)
917 "We should not push a frame that is supposed to _suppress_ "do { if (!(!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants
(aNewFloatContainingBlock))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should not push a frame that is supposed to _suppress_ "
"floats as a float containing block!", "!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 918); MOZ_PretendNoReturn
(); } } while (0)
918 "floats as a float containing block!")do { if (!(!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants
(aNewFloatContainingBlock))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should not push a frame that is supposed to _suppress_ "
"floats as a float containing block!", "!aNewFloatContainingBlock || !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 918); MOZ_PretendNoReturn
(); } } while (0)
;
919 aSaveState.mList = &mFloatedList;
920 aSaveState.mSavedList = std::move(mFloatedList);
921 aSaveState.mChildListID = FrameChildListID::Float;
922 aSaveState.mState = this;
923 mFloatedList = AbsoluteFrameList(aNewFloatContainingBlock);
924}
925
926nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
927 const nsStyleDisplay& aStyleDisplay,
928 nsContainerFrame* aContentParentFrame) const {
929 // If there is no container for a fixed, absolute, or floating root
930 // frame, we will ignore the positioning. This hack is originally
931 // brought to you by the letter T: tables, since other roots don't
932 // even call into this code. See bug 178855.
933 //
934 // XXX Disabling positioning in this case is a hack. If one was so inclined,
935 // one could support this either by (1) inserting a dummy block between the
936 // table and the canvas or (2) teaching the canvas how to reflow positioned
937 // elements. (1) has the usual problems when multiple frames share the same
938 // content (notice all the special cases in this file dealing with inner
939 // tables and table wrappers which share the same content). (2) requires some
940 // work and possible factoring.
941 //
942 // XXXbz couldn't we just force position to "static" on roots and
943 // float to "none"? That's OK per CSS 2.1, as far as I can tell.
944
945 if (aContentParentFrame && aContentParentFrame->IsInSVGTextSubtree()) {
946 return aContentParentFrame;
947 }
948
949 if (aStyleDisplay.IsFloatingStyle() && mFloatedList.mContainingBlock) {
950 NS_ASSERTION(!aStyleDisplay.IsAbsolutelyPositionedStyle(),do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 951); MOZ_PretendNoReturn(); } } while (0)
951 "Absolutely positioned _and_ floating?")do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 951); MOZ_PretendNoReturn(); } } while (0)
;
952 return mFloatedList.mContainingBlock;
953 }
954
955 if (aStyleDisplay.mTopLayer != StyleTopLayer::None) {
956 MOZ_ASSERT(aStyleDisplay.mTopLayer == StyleTopLayer::Auto,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay.mTopLayer == StyleTopLayer::Auto)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStyleDisplay.mTopLayer == StyleTopLayer::Auto))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
" (" "-moz-top-layer should be either none or auto" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 957); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
957 "-moz-top-layer should be either none or auto")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay.mTopLayer == StyleTopLayer::Auto)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStyleDisplay.mTopLayer == StyleTopLayer::Auto))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
" (" "-moz-top-layer should be either none or auto" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 957); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
958 MOZ_ASSERT(aStyleDisplay.IsAbsolutelyPositionedStyle(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay.IsAbsolutelyPositionedStyle())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStyleDisplay.IsAbsolutelyPositionedStyle()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aStyleDisplay.IsAbsolutelyPositionedStyle()"
" (" "Top layer items should always be absolutely positioned"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 959
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
959 "Top layer items should always be absolutely positioned")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay.IsAbsolutelyPositionedStyle())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStyleDisplay.IsAbsolutelyPositionedStyle()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aStyleDisplay.IsAbsolutelyPositionedStyle()"
" (" "Top layer items should always be absolutely positioned"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 959
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
960 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed) {
961 MOZ_ASSERT(mRealFixedList.mContainingBlock, "No root frame?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRealFixedList.mContainingBlock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRealFixedList.mContainingBlock
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mRealFixedList.mContainingBlock" " (" "No root frame?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealFixedList.mContainingBlock"
") (" "No root frame?" ")"); do { MOZ_CrashSequence(__null, 961
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
962 return mRealFixedList.mContainingBlock;
963 }
964 MOZ_ASSERT(aStyleDisplay.mPosition == StylePositionProperty::Absolute)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay.mPosition == StylePositionProperty::Absolute
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aStyleDisplay.mPosition == StylePositionProperty::Absolute
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStyleDisplay.mPosition == StylePositionProperty::Absolute",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 964); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStyleDisplay.mPosition == StylePositionProperty::Absolute"
")"); do { MOZ_CrashSequence(__null, 964); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
965 MOZ_ASSERT(mTopLayerAbsoluteList.mContainingBlock)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTopLayerAbsoluteList.mContainingBlock)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mTopLayerAbsoluteList.mContainingBlock))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTopLayerAbsoluteList.mContainingBlock"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 965); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mTopLayerAbsoluteList.mContainingBlock" ")"
); do { MOZ_CrashSequence(__null, 965); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 return mTopLayerAbsoluteList.mContainingBlock;
967 }
968
969 if (aStyleDisplay.mPosition == StylePositionProperty::Absolute &&
970 mAbsoluteList.mContainingBlock) {
971 return mAbsoluteList.mContainingBlock;
972 }
973
974 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed &&
975 mFixedList->mContainingBlock) {
976 return mFixedList->mContainingBlock;
977 }
978
979 return aContentParentFrame;
980}
981
982void nsFrameConstructorState::ReparentAbsoluteItems(
983 nsContainerFrame* aNewParent) {
984 // Bug 1491727: This function might not conform to the spec. See
985 // https://github.com/w3c/csswg-drafts/issues/1894.
986
987 MOZ_ASSERT(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Restrict the usage under column hierarchy." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 988); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
988 "Restrict the usage under column hierarchy.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Restrict the usage under column hierarchy." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 988); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
989
990 AbsoluteFrameList newAbsoluteItems(aNewParent);
991
992 nsIFrame* current = mAbsoluteList.FirstChild();
993 while (current) {
994 nsIFrame* placeholder = current->GetPlaceholderFrame();
995
996 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
997 nsIFrame* next = current->GetNextSibling();
998 mAbsoluteList.RemoveFrame(current);
999 newAbsoluteItems.AppendFrame(aNewParent, current);
1000 current = next;
1001 } else {
1002 current = current->GetNextSibling();
1003 }
1004 }
1005
1006 if (newAbsoluteItems.NotEmpty()) {
1007 // ~nsFrameConstructorSaveState() will move newAbsoluteItems to
1008 // aNewParent's absolute child list.
1009 nsFrameConstructorSaveState absoluteSaveState;
1010
1011 // It doesn't matter whether aNewParent has position style or not. Caller
1012 // won't call us if we can't have absolute children.
1013 PushAbsoluteContainingBlock(aNewParent, aNewParent, absoluteSaveState);
1014 mAbsoluteList = std::move(newAbsoluteItems);
1015 }
1016}
1017
1018void nsFrameConstructorState::ReparentFloats(nsContainerFrame* aNewParent) {
1019 MOZ_ASSERT(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Restrict the usage under column hierarchy." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1020); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1020 "Restrict the usage under column hierarchy.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
" (" "Restrict the usage under column hierarchy." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1020); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1021 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->IsFloatContainingBlock())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aNewParent->IsFloatContainingBlock()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewParent->IsFloatContainingBlock()"
" (" "Why calling this method if aNewParent is not a float containing block?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1023
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1023); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1022 aNewParent->IsFloatContainingBlock(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->IsFloatContainingBlock())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aNewParent->IsFloatContainingBlock()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewParent->IsFloatContainingBlock()"
" (" "Why calling this method if aNewParent is not a float containing block?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1023
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1023); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1023 "Why calling this method if aNewParent is not a float containing block?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent->IsFloatContainingBlock())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aNewParent->IsFloatContainingBlock()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewParent->IsFloatContainingBlock()"
" (" "Why calling this method if aNewParent is not a float containing block?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1023
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1023); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1024
1025 // Gather floats that should reparent under aNewParent.
1026 AbsoluteFrameList floats(aNewParent);
1027 nsIFrame* current = mFloatedList.FirstChild();
1028 while (current) {
1029 nsIFrame* placeholder = current->GetPlaceholderFrame();
1030 nsIFrame* next = current->GetNextSibling();
1031 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
1032 mFloatedList.RemoveFrame(current);
1033 floats.AppendFrame(aNewParent, current);
1034 }
1035 current = next;
1036 }
1037
1038 if (floats.NotEmpty()) {
1039 // Make floats move into aNewParent's float child list in
1040 // ~nsFrameConstructorSaveState() when destructing floatSaveState.
1041 nsFrameConstructorSaveState floatSaveState;
1042 PushFloatContainingBlock(aNewParent, floatSaveState);
1043 mFloatedList = std::move(floats);
1044 }
1045}
1046
1047AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
1048 nsIFrame* aNewFrame, bool aCanBePositioned, bool aCanBeFloated,
1049 nsFrameState* aPlaceholderType) {
1050 const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1051 if (aCanBeFloated && disp->IsFloatingStyle()) {
1052 *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1053 return &mFloatedList;
1054 }
1055
1056 if (aCanBePositioned) {
1057 if (disp->mTopLayer != StyleTopLayer::None) {
1058 *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1059 if (disp->mPosition == StylePositionProperty::Fixed) {
1060 *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1061 return &mRealFixedList;
1062 }
1063 *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1064 return &mTopLayerAbsoluteList;
1065 }
1066 if (disp->mPosition == StylePositionProperty::Absolute) {
1067 *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1068 return &mAbsoluteList;
1069 }
1070 if (disp->mPosition == StylePositionProperty::Fixed) {
1071 *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1072 return mFixedList;
1073 }
1074 }
1075 return nullptr;
1076}
1077
1078void nsFrameConstructorState::AddChild(
1079 nsIFrame* aNewFrame, nsFrameList& aFrameList, nsIContent* aContent,
1080 nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated,
1081 bool aInsertAfter, nsIFrame* aInsertAfterFrame) {
1082 MOZ_ASSERT(!aNewFrame->GetNextSibling(), "Shouldn't happen")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aNewFrame->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aNewFrame->GetNextSibling
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aNewFrame->GetNextSibling()" " (" "Shouldn't happen" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1082); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aNewFrame->GetNextSibling()" ") (" "Shouldn't happen"
")"); do { MOZ_CrashSequence(__null, 1082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1083
1084 nsFrameState placeholderType = NS_FRAME_STATE_NONE;
1085 AbsoluteFrameList* outOfFlowFrameList = GetOutOfFlowFrameList(
1086 aNewFrame, aCanBePositioned, aCanBeFloated, &placeholderType);
1087
1088 // The comments in GetGeometricParent regarding root table frames
1089 // all apply here, unfortunately. Thus, we need to check whether
1090 // the returned frame items really has containing block.
1091 nsFrameList* frameList;
1092 if (outOfFlowFrameList && outOfFlowFrameList->mContainingBlock) {
1093 MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewFrame->GetParent() == outOfFlowFrameList->
mContainingBlock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewFrame->GetParent() ==
outOfFlowFrameList->mContainingBlock))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
" (" "Parent of the frame is not the containing block?" ")",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 1094); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1094); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1094 "Parent of the frame is not the containing block?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewFrame->GetParent() == outOfFlowFrameList->
mContainingBlock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewFrame->GetParent() ==
outOfFlowFrameList->mContainingBlock))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
" (" "Parent of the frame is not the containing block?" ")",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 1094); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1094); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1095 frameList = outOfFlowFrameList;
1096 } else {
1097 frameList = &aFrameList;
1098 placeholderType = NS_FRAME_STATE_NONE;
1099 }
1100
1101 if (placeholderType != NS_FRAME_STATE_NONE) {
1102 NS_ASSERTION(frameList != &aFrameList,do { if (!(frameList != &aFrameList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Putting frame in-flow _and_ want a placeholder?", "frameList != &aFrameList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1103); MOZ_PretendNoReturn
(); } } while (0)
1103 "Putting frame in-flow _and_ want a placeholder?")do { if (!(frameList != &aFrameList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Putting frame in-flow _and_ want a placeholder?", "frameList != &aFrameList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1103); MOZ_PretendNoReturn
(); } } while (0)
;
1104 nsIFrame* placeholderFrame =
1105 nsCSSFrameConstructor::CreatePlaceholderFrameFor(
1106 mPresShell, aContent, aNewFrame, aParentFrame, nullptr,
1107 placeholderType);
1108
1109 placeholderFrame->AddStateBits(mAdditionalStateBits);
1110 // Add the placeholder frame to the flow
1111 aFrameList.AppendFrame(nullptr, placeholderFrame);
1112 }
1113#ifdef DEBUG1
1114 else {
1115 NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,do { if (!(aNewFrame->GetParent() == aParentFrame)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "In-flow frame has wrong parent", "aNewFrame->GetParent() == aParentFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1116); MOZ_PretendNoReturn
(); } } while (0)
1116 "In-flow frame has wrong parent")do { if (!(aNewFrame->GetParent() == aParentFrame)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "In-flow frame has wrong parent", "aNewFrame->GetParent() == aParentFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1116); MOZ_PretendNoReturn
(); } } while (0)
;
1117 }
1118#endif
1119
1120 if (aInsertAfter) {
1121 frameList->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1122 } else {
1123 frameList->AppendFrame(nullptr, aNewFrame);
1124 }
1125}
1126
1127// Some of this function's callers recurse 1000 levels deep in crashtests. On
1128// platforms where stack limits are low, we can't afford to incorporate this
1129// function's `AutoTArray`s into its callers' stack frames, so disable inlining.
1130MOZ_NEVER_INLINE__attribute__((noinline)) void nsFrameConstructorState::ProcessFrameInsertions(
1131 AbsoluteFrameList& aFrameList, FrameChildListID aChildListID) {
1132 MOZ_ASSERT(&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1133 &aFrameList == &mTopLayerAbsoluteList ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1134 &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1135 &aFrameList == &mRealFixedList)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(&aFrameList == &mFloatedList || &aFrameList
== &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList
|| &aFrameList == &mAncestorFixedList || &aFrameList
== mFixedList || &aFrameList == &mRealFixedList))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1136 MOZ_ASSERT_IF(&aFrameList == &mFloatedList,do { if (&aFrameList == &mFloatedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Float)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Float))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Float", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1137); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1137 aChildListID == FrameChildListID::Float)do { if (&aFrameList == &mFloatedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Float)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Float))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Float", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1137); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1138 MOZ_ASSERT_IF(&aFrameList == &mAbsoluteList || &aFrameList == mFixedList,do { if (&aFrameList == &mAbsoluteList || &aFrameList
== mFixedList) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aChildListID == FrameChildListID::Absolute)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChildListID == FrameChildListID::Absolute))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aChildListID == FrameChildListID::Absolute"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1139); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1139); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1139 aChildListID == FrameChildListID::Absolute)do { if (&aFrameList == &mAbsoluteList || &aFrameList
== mFixedList) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aChildListID == FrameChildListID::Absolute)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChildListID == FrameChildListID::Absolute))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aChildListID == FrameChildListID::Absolute"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1139); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1139); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1140 MOZ_ASSERT_IF(&aFrameList == &mTopLayerAbsoluteList,do { if (&aFrameList == &mTopLayerAbsoluteList) { do {
static_assert( mozilla::detail::AssertionConditionType<decltype
(aChildListID == FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1141); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1141 aChildListID == FrameChildListID::Absolute)do { if (&aFrameList == &mTopLayerAbsoluteList) { do {
static_assert( mozilla::detail::AssertionConditionType<decltype
(aChildListID == FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1141); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1142 MOZ_ASSERT_IF(&aFrameList == mFixedList && &aFrameList != &mAbsoluteList,do { if (&aFrameList == mFixedList && &aFrameList
!= &mAbsoluteList) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(aChildListID == FrameChildListID
::Absolute)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aChildListID == FrameChildListID::Absolute
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1143 aChildListID == FrameChildListID::Absolute)do { if (&aFrameList == mFixedList && &aFrameList
!= &mAbsoluteList) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(aChildListID == FrameChildListID
::Absolute)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aChildListID == FrameChildListID::Absolute
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1144 MOZ_ASSERT_IF(&aFrameList == &mAncestorFixedList,do { if (&aFrameList == &mAncestorFixedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1145); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1145 aChildListID == FrameChildListID::Absolute)do { if (&aFrameList == &mAncestorFixedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1145); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1146 MOZ_ASSERT_IF(&aFrameList == &mRealFixedList,do { if (&aFrameList == &mRealFixedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1147); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1147 aChildListID == FrameChildListID::Absolute)do { if (&aFrameList == &mRealFixedList) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aChildListID
== FrameChildListID::Absolute)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildListID == FrameChildListID
::Absolute))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChildListID == FrameChildListID::Absolute", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1147); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1148
1149 if (aFrameList.IsEmpty()) {
1150 return;
1151 }
1152
1153 nsContainerFrame* containingBlock = aFrameList.mContainingBlock;
1154
1155 NS_ASSERTION(containingBlock, "Child list without containing block?")do { if (!(containingBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Child list without containing block?", "containingBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1155); MOZ_PretendNoReturn(); } } while (0)
;
1156
1157 // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1158 // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1159 // is set) and doesn't have any frames in the aChildListID child list yet.
1160 const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1161 if (childList.IsEmpty() &&
1162 containingBlock->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1163 // If we're injecting absolutely positioned frames, inject them on the
1164 // absolute containing block
1165 if (aChildListID == FrameChildListID::Absolute) {
1166 containingBlock->GetAbsoluteContainingBlock()->SetInitialChildList(
1167 containingBlock, aChildListID, std::move(aFrameList));
1168 } else {
1169 containingBlock->SetInitialChildList(aChildListID, std::move(aFrameList));
1170 }
1171 } else if (childList.IsEmpty() ||
1172 aChildListID == FrameChildListID::Absolute) {
1173 // The order is not important for abs-pos/fixed-pos frame list, just
1174 // append the frame items to the list directly.
1175 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1176 std::move(aFrameList));
1177 } else {
1178 MOZ_ASSERT(aChildListID == FrameChildListID::Float)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildListID == FrameChildListID::Float)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aChildListID == FrameChildListID::Float))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChildListID == FrameChildListID::Float"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 1178); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float" ")"
); do { MOZ_CrashSequence(__null, 1178); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1179 // Note that whether the frame construction context is doing an append or
1180 // not is not helpful here, since it could be appending to some frame in
1181 // the middle of the document, which means we're not necessarily
1182 // appending to the children of the containing block.
1183 //
1184 // We need to make sure the 'append to the end of document' case is fast.
1185 // So first test the last child of the containing block
1186 nsIFrame* lastChild = childList.LastChild();
1187 lastChild = lastChild->FirstContinuation()->GetPlaceholderFrame();
1188
1189 // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1190 // so this will make out-of-flows respect the ordering of placeholders,
1191 // which is great because it takes care of anonymous content.
1192 nsIFrame* firstNewFrame = aFrameList.FirstChild();
1193 firstNewFrame = firstNewFrame->GetPlaceholderFrame();
1194
1195 // Cache the ancestor chain so that we can reuse it if needed.
1196 AutoTArray<const nsIFrame*, 20> firstNewFrameAncestors;
1197 const nsIFrame* notCommonAncestor = nsLayoutUtils::FillAncestors(
1198 firstNewFrame, containingBlock, &firstNewFrameAncestors);
1199
1200 if (nsLayoutUtils::CompareTreePosition(
1201 lastChild, firstNewFrame, firstNewFrameAncestors,
1202 notCommonAncestor ? containingBlock : nullptr) < 0) {
1203 // lastChild comes before the new children, so just append
1204 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1205 std::move(aFrameList));
1206 } else {
1207 // Try the other children. First collect them to an array so that a
1208 // reasonable fast binary search can be used to find the insertion point.
1209 AutoTArray<std::pair<nsIFrame*, nsPlaceholderFrame*>, 128> children;
1210 for (nsIFrame* f : childList) {
1211 children.AppendElement(
1212 std::make_pair(f, f->FirstContinuation()->GetPlaceholderFrame()));
1213 }
1214
1215 nsIFrame* insertionPoint = nullptr;
1216 int32_t imin = 0;
1217 int32_t max = children.Length();
1218 while (max > imin) {
1219 int32_t imid = imin + ((max - imin) / 2);
1220 const auto& pair = children[imid];
1221 int32_t compare = nsLayoutUtils::CompareTreePosition(
1222 pair.second, firstNewFrame, firstNewFrameAncestors,
1223 notCommonAncestor ? containingBlock : nullptr);
1224 if (compare > 0) {
1225 // f is after the new frame.
1226 max = imid;
1227 insertionPoint = imid > 0 ? children[imid - 1].first : nullptr;
1228 } else if (compare < 0) {
1229 // f is before the new frame.
1230 imin = imid + 1;
1231 insertionPoint = pair.first;
1232 } else {
1233 // This is for the old behavior. Should be removed once it is
1234 // guaranteed that CompareTreePosition can't return 0!
1235 // See bug 928645.
1236 NS_WARNING("Something odd happening???")NS_DebugBreak(NS_DEBUG_WARNING, "Something odd happening???",
nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp",
1236)
;
1237 insertionPoint = nullptr;
1238 for (auto [frame, placeholder] : children) {
1239 if (nsLayoutUtils::CompareTreePosition(
1240 placeholder, firstNewFrame, firstNewFrameAncestors,
1241 notCommonAncestor ? containingBlock : nullptr) > 0) {
1242 break;
1243 }
1244 insertionPoint = frame;
1245 }
1246 break;
1247 }
1248 }
1249 mFrameConstructor->InsertFrames(containingBlock, aChildListID,
1250 insertionPoint, std::move(aFrameList));
1251 }
1252 }
1253
1254 MOZ_ASSERT(aFrameList.IsEmpty(), "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrameList.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrameList.IsEmpty()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aFrameList.IsEmpty()"
" (" "How did that happen?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1254); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrameList.IsEmpty()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 1254); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1255}
1256
1257nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
1258 // Restore the state
1259 if (mList) {
1260 MOZ_ASSERT(mState, "Can't have mList set without having a state!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mState)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mState))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mState" " (" "Can't have mList set without having a state!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1260
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mState" ") (" "Can't have mList set without having a state!"
")"); do { MOZ_CrashSequence(__null, 1260); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1261 mState->ProcessFrameInsertions(*mList, mChildListID);
1262
1263 if (mList == &mState->mAbsoluteList) {
1264 mState->mAbsoluteList = std::move(mSavedList);
1265 mState->mFixedList = mSavedFixedList;
1266 } else {
1267 mState->mFloatedList = std::move(mSavedList);
1268 }
1269
1270 MOZ_ASSERT(mSavedList.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSavedList.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSavedList.IsEmpty()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("mSavedList.IsEmpty()"
" (" "Frames in mSavedList should've moved back into mState!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1271
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1271); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1271 "Frames in mSavedList should've moved back into mState!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSavedList.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSavedList.IsEmpty()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("mSavedList.IsEmpty()"
" (" "Frames in mSavedList should've moved back into mState!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1271
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1271); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1272 MOZ_ASSERT(!mList->LastChild() || !mList->LastChild()->GetNextSibling(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mList->LastChild() || !mList->LastChild()->
GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mList->LastChild() || !mList
->LastChild()->GetNextSibling()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
" (" "Something corrupted our list!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1273); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1273 "Something corrupted our list!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mList->LastChild() || !mList->LastChild()->
GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mList->LastChild() || !mList
->LastChild()->GetNextSibling()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
" (" "Something corrupted our list!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1273); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1274 }
1275}
1276
1277/**
1278 * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1279 * pointer of the frames in the list, and reparents their views as needed.
1280 * nsIFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1281 * ancestors as needed. Then it sets the list as the initial child list
1282 * on aNewParent, unless aNewParent either already has kids or has been
1283 * reflowed; in that case it appends the new frames. Note that this
1284 * method differs from ReparentFrames in that it doesn't change the kids'
1285 * style.
1286 */
1287// XXXbz Since this is only used for {ib} splits, could we just copy the view
1288// bits from aOldParent to aNewParent and then use the
1289// nsFrameList::ApplySetParent? That would still leave us doing two passes
1290// over the list, of course; if we really wanted to we could factor out the
1291// relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1292// views, which would make most of this function go away.
1293static void MoveChildrenTo(nsIFrame* aOldParent, nsContainerFrame* aNewParent,
1294 nsFrameList& aFrameList) {
1295 aFrameList.ApplySetParent(aNewParent);
1296
1297 if (aNewParent->PrincipalChildList().IsEmpty() &&
1298 aNewParent->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1299 aNewParent->SetInitialChildList(FrameChildListID::Principal,
1300 std::move(aFrameList));
1301 } else {
1302 aNewParent->AppendFrames(FrameChildListID::Principal,
1303 std::move(aFrameList));
1304 }
1305}
1306
1307static void EnsureAutoPageName(nsFrameConstructorState& aState,
1308 const nsContainerFrame* const aFrame) {
1309 // Check if we need to figure out our used page name.
1310 // When building the entire document, this should only happen for the
1311 // root, which will mean the loop will immediately end. Either way, this will
1312 // only happen once for each time the frame constructor is run.
1313 if (aState.mAutoPageNameValue) {
1314 return;
1315 }
1316
1317 for (const nsContainerFrame* frame = aFrame; frame;
1318 frame = frame->GetParent()) {
1319 if (const nsAtom* maybePageName = frame->GetStylePageName()) {
1320 aState.mAutoPageNameValue = maybePageName;
1321 return;
1322 }
1323 }
1324 // Ensure that a root with `page: auto` gets an empty page name
1325 // https://drafts.csswg.org/css-page-3/#using-named-pages
1326 aState.mAutoPageNameValue = nsGkAtoms::_empty;
1327}
1328
1329nsCSSFrameConstructor::AutoFrameConstructionPageName::
1330 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1331 nsIFrame* const aFrame)
1332 : mState(aState), mNameToRestore(nullptr) {
1333 if (!aState.mPresContext->IsPaginated()) {
1334 MOZ_ASSERT(!aState.mAutoPageNameValue,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aState.mAutoPageNameValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aState.mAutoPageNameValue))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aState.mAutoPageNameValue"
" (" "Page name should not have been set" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1335); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1335); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1335 "Page name should not have been set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aState.mAutoPageNameValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aState.mAutoPageNameValue))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aState.mAutoPageNameValue"
" (" "Page name should not have been set" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1335); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1335); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1336 return;
1337 }
1338#ifdef DEBUG1
1339 MOZ_ASSERT(!aFrame->mWasVisitedByAutoFrameConstructionPageName,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->mWasVisitedByAutoFrameConstructionPageName
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aFrame->mWasVisitedByAutoFrameConstructionPageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->mWasVisitedByAutoFrameConstructionPageName" " ("
"Frame should only have been visited once" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1340); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1340); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1340 "Frame should only have been visited once")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->mWasVisitedByAutoFrameConstructionPageName
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aFrame->mWasVisitedByAutoFrameConstructionPageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->mWasVisitedByAutoFrameConstructionPageName" " ("
"Frame should only have been visited once" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1340); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1340); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1341 aFrame->mWasVisitedByAutoFrameConstructionPageName = true;
1342#endif
1343
1344 EnsureAutoPageName(aState, aFrame->GetParent());
1345 mNameToRestore = aState.mAutoPageNameValue;
1346
1347 MOZ_ASSERT(mNameToRestore,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNameToRestore)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNameToRestore))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mNameToRestore"
" (" "Page name should have been found by EnsureAutoPageName"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1348
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1348); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1348 "Page name should have been found by EnsureAutoPageName")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNameToRestore)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNameToRestore))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mNameToRestore"
" (" "Page name should have been found by EnsureAutoPageName"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 1348
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1348); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1349 if (const nsAtom* maybePageName = aFrame->GetStylePageName()) {
1350 aState.mAutoPageNameValue = maybePageName;
1351 }
1352 aFrame->SetAutoPageValue(aState.mAutoPageNameValue);
1353}
1354
1355nsCSSFrameConstructor::AutoFrameConstructionPageName::
1356 ~AutoFrameConstructionPageName() {
1357 // This isn't actually useful when not in paginated layout, but it's very
1358 // likely cheaper to unconditionally write this pointer than to test for
1359 // paginated layout and then branch on the result.
1360 mState.mAutoPageNameValue = mNameToRestore;
1361}
1362
1363//----------------------------------------------------------------------
1364
1365nsCSSFrameConstructor::nsCSSFrameConstructor(Document* aDocument,
1366 PresShell* aPresShell)
1367 : nsFrameManager(aPresShell),
1368 mDocument(aDocument),
1369 mFirstFreeFCItem(nullptr),
1370 mFCItemsInUse(0),
1371 mCurrentDepth(0),
1372 mQuotesDirty(false),
1373 mCountersDirty(false),
1374 mAlwaysCreateFramesForIgnorableWhitespace(false),
1375 mRemovingContent(false) {
1376#ifdef DEBUG1
1377 static bool gFirstTime = true;
1378 if (gFirstTime) {
1379 gFirstTime = false;
1380 char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1381 if (flags) {
1382 bool error = false;
1383 for (;;) {
1384 char* comma = strchr(flags, ',');
1385 if (comma) *comma = '\0';
1386
1387 bool found = false;
1388 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1389 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1390 while (flag < limit) {
1391 if (nsCRT::strcasecmp(flag->name, flags) == 0) {
1392 *(flag->on) = true;
1393 printf("nsCSSFrameConstructor: setting %s debug flag on\n",
1394 flag->name);
1395 found = true;
1396 break;
1397 }
1398 ++flag;
1399 }
1400
1401 if (!found) error = true;
1402
1403 if (!comma) break;
1404
1405 *comma = ',';
1406 flags = comma + 1;
1407 }
1408
1409 if (error) {
1410 printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1411 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1412 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1413 while (flag < limit) {
1414 printf(" %s\n", flag->name);
1415 ++flag;
1416 }
1417 printf(
1418 "Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of "
1419 "flag\n");
1420 printf("names (no whitespace)\n");
1421 }
1422 }
1423 }
1424#endif
1425}
1426
1427void nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) {
1428 if (aFrame->StyleDisplay()->IsContainStyle()) {
1429 mContainStyleScopeManager.DestroyScopesFor(aFrame);
1430 }
1431
1432 if (aFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
1433 mContainStyleScopeManager.DestroyQuoteNodesFor(aFrame)) {
1434 QuotesDirty();
1435 }
1436
1437 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1438 mContainStyleScopeManager.DestroyCounterNodesFor(aFrame)) {
1439 // Technically we don't need to update anything if we destroyed only
1440 // USE nodes. However, this is unlikely to happen in the real world
1441 // since USE nodes generally go along with INCREMENT nodes.
1442 CountersDirty();
1443 }
1444
1445 RestyleManager()->NotifyDestroyingFrame(aFrame);
1446}
1447
1448struct nsGenConInitializer {
1449 UniquePtr<nsGenConNode> mNode;
1450 // Null if we should use the quote list.
1451 RefPtr<nsAtom> mCounterListName;
1452
1453 nsGenConInitializer(UniquePtr<nsGenConNode> aNode, nsAtom* aCounterListName)
1454 : mNode(std::move(aNode)), mCounterListName(aCounterListName) {}
1455};
1456
1457already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
1458 nsFrameConstructorState& aState, const nsAString& aString,
1459 UniquePtr<nsGenConInitializer> aInitializer) {
1460 RefPtr<nsTextNode> content = new (mDocument->NodeInfoManager())
1461 nsTextNode(mDocument->NodeInfoManager());
1462 content->SetText(aString, false);
1463 if (aInitializer) {
1464 aInitializer->mNode->mText = content;
1465 content->SetProperty(nsGkAtoms::genConInitializerProperty,
1466 aInitializer.release(),
1467 nsINode::DeleteProperty<nsGenConInitializer>);
1468 aState.mGeneratedContentWithInitializer.AppendElement(content);
1469 }
1470 return content.forget();
1471}
1472
1473void nsCSSFrameConstructor::CreateGeneratedContent(
1474 nsFrameConstructorState& aState, Element& aOriginatingElement,
1475 ComputedStyle& aPseudoStyle, const StyleContentItem& aItem,
1476 size_t aContentIndex, const FunctionRef<void(nsIContent*)> aAddChild) {
1477 using Type = StyleContentItem::Tag;
1478 // Get the content value
1479 const Type type = aItem.tag;
1480
1481 switch (type) {
1482 case Type::Image: {
1483 RefPtr c = GeneratedImageContent::Create(*mDocument, aContentIndex);
1484 aAddChild(c);
1485 return;
1486 }
1487
1488 case Type::String: {
1489 const auto string = aItem.AsString().AsString();
1490 if (string.IsEmpty()) {
1491 return;
1492 }
1493 RefPtr text =
1494 CreateGenConTextNode(aState, NS_ConvertUTF8toUTF16(string), nullptr);
1495 aAddChild(text);
1496 return;
1497 }
1498
1499 case Type::Counter:
1500 case Type::Counters: {
1501 RefPtr<nsAtom> name;
1502 const StyleCounterStyle* style;
1503 nsString separator;
1504 if (type == Type::Counter) {
1505 const auto& counter = aItem.AsCounter();
1506 name = counter._0.AsAtom();
1507 style = &counter._1;
1508 } else {
1509 const auto& counters = aItem.AsCounters();
1510 name = counters._0.AsAtom();
1511 CopyUTF8toUTF16(counters._1.AsString(), separator);
1512 style = &counters._2;
1513 }
1514 auto node = std::make_unique<nsCounterUseNode>(
1515 *style, std::move(separator), aContentIndex,
1516 /* aAllCounters = */ type == Type::Counters);
1517 auto initializer =
1518 std::make_unique<nsGenConInitializer>(std::move(node), name);
1519 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1520 aAddChild(c);
1521 return;
1522 }
1523 case Type::OpenQuote:
1524 case Type::CloseQuote:
1525 case Type::NoOpenQuote:
1526 case Type::NoCloseQuote: {
1527 auto node = std::make_unique<nsQuoteNode>(type, aContentIndex);
1528 auto initializer =
1529 std::make_unique<nsGenConInitializer>(std::move(node), nullptr);
1530 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1531 aAddChild(c);
1532 return;
1533 }
1534
1535 case Type::MozLabelContent: {
1536 nsAutoString value;
1537 aOriginatingElement.GetAttr(nsGkAtoms::value, value);
1538
1539 nsAutoString accesskey;
1540 if (!aOriginatingElement.GetAttr(nsGkAtoms::accesskey, accesskey) ||
1541 accesskey.IsEmpty() || !LookAndFeel::GetMenuAccessKey()) {
1542 // Easy path: just return a regular value attribute content.
1543 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1544 aAddChild(c);
1545 return;
1546 }
1547
1548 auto AppendAccessKeyLabel = [&] {
1549 // Always append accesskey text in uppercase, see bug 1806167.
1550 ToUpperCase(accesskey);
1551 nsAutoString accessKeyLabel = u"("_ns + accesskey + u")"_ns;
1552 if (!StringEndsWith(value, accessKeyLabel)) {
1553 if (InsertSeparatorBeforeAccessKey() && !value.IsEmpty() &&
1554 !NS_IS_SPACE(value.Last())) {
1555 value.Append(' ');
1556 }
1557 value.Append(accessKeyLabel);
1558 }
1559 };
1560 if (AlwaysAppendAccessKey()) {
1561 AppendAccessKeyLabel();
1562 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1563 aAddChild(c);
1564 return;
1565 }
1566
1567 const auto accessKeyStart = [&]() -> Maybe<size_t> {
1568 nsAString::const_iterator start, end;
1569 value.BeginReading(start);
1570 value.EndReading(end);
1571
1572 const auto originalStart = start;
1573 // not appending access key - do case-sensitive search
1574 // first
1575 bool found = true;
1576 if (!FindInReadable(accesskey, start, end)) {
1577 start = originalStart;
1578 // didn't find it - perform a case-insensitive search
1579 found = CaseInsensitiveFindInReadable(accesskey, start, end);
1580 }
1581 if (!found) {
1582 return Nothing();
1583 }
1584 return Some(Distance(originalStart, start));
1585 }();
1586
1587 if (accessKeyStart.isNothing()) {
1588 AppendAccessKeyLabel();
1589 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1590 aAddChild(c);
1591 return;
1592 }
1593
1594 RefPtr wrapper = mDocument->CreateHTMLElement(nsGkAtoms::span);
1595 if (*accessKeyStart != 0) {
1596 RefPtr beginning = CreateGenConTextNode(
1597 aState, Substring(value, 0, *accessKeyStart), nullptr);
1598 wrapper->AppendChildTo(beginning, /* aNotify = */ false,
1599 IgnoreErrors());
1600 }
1601
1602 {
1603 RefPtr accessKeyText = CreateGenConTextNode(
1604 aState, Substring(value, *accessKeyStart, accesskey.Length()),
1605 nullptr);
1606 RefPtr<nsIContent> underline =
1607 mDocument->CreateHTMLElement(nsGkAtoms::u);
1608 underline->AppendChildTo(accessKeyText, /* aNotify = */ false,
1609 IgnoreErrors());
1610 wrapper->AppendChildTo(underline, /* aNotify = */ false,
1611 IgnoreErrors());
1612 }
1613
1614 size_t accessKeyEnd = *accessKeyStart + accesskey.Length();
1615 if (accessKeyEnd != value.Length()) {
1616 RefPtr valueEnd = CreateGenConTextNode(
1617 aState, Substring(value, *accessKeyStart + accesskey.Length()),
1618 nullptr);
1619 wrapper->AppendChildTo(valueEnd, /* aNotify = */ false, IgnoreErrors());
1620 }
1621 aAddChild(wrapper);
1622 break;
1623 }
1624 }
1625}
1626
1627void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
1628 nsFrameConstructorState& aState, Element& aOriginatingElement,
1629 const ComputedStyle& aPseudoStyle,
1630 const FunctionRef<void(nsIContent*)> aAddChild) {
1631 const nsStyleList* styleList = aPseudoStyle.StyleList();
1632 if (!styleList->mListStyleImage.IsNone()) {
1633 RefPtr<nsIContent> child =
1634 GeneratedImageContent::CreateForListStyleImage(*mDocument);
1635 aAddChild(child);
1636 child = CreateGenConTextNode(aState, u" "_ns, nullptr);
1637 aAddChild(child);
1638 return;
1639 }
1640 CreateGeneratedContentFromListStyleType(aState, aOriginatingElement,
1641 aPseudoStyle, aAddChild);
1642}
1643
1644void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
1645 nsFrameConstructorState& aState, Element& aOriginatingElement,
1646 const ComputedStyle& aPseudoStyle,
1647 const FunctionRef<void(nsIContent*)> aAddChild) {
1648 using Tag = StyleCounterStyle::Tag;
1649 const auto& styleType = aPseudoStyle.StyleList()->mListStyleType;
1650 switch (styleType.tag) {
1651 case Tag::None:
1652 return;
1653 case Tag::String: {
1654 nsDependentAtomString string(styleType.AsString().AsAtom());
1655 RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr);
1656 aAddChild(child);
1657 return;
1658 }
1659 case Tag::Name:
1660 case Tag::Symbols:
1661 break;
1662 }
1663
1664 auto node = std::make_unique<nsCounterUseNode>(
1665 nsCounterUseNode::ForLegacyBullet, styleType);
1666 if (styleType.IsName()) {
1667 nsAtom* name = styleType.AsName().AsAtom();
1668 if (name == nsGkAtoms::disc || name == nsGkAtoms::circle ||
1669 name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed ||
1670 name == nsGkAtoms::disclosure_open) {
1671 // We don't need a use node inserted for these.
1672 CounterStyle* counterStyle = mPresShell->GetPresContext()
1673 ->CounterStyleManager()
1674 ->ResolveCounterStyle(name);
1675 nsAutoString text;
1676 node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
1677 // Note that we're done with 'node' in this case. It's not inserted into
1678 // any list so it's deleted when we return.
1679 RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
1680 aAddChild(child);
1681 return;
1682 }
1683 }
1684
1685 auto initializer = std::make_unique<nsGenConInitializer>(
1686 std::move(node), nsGkAtoms::list_item);
1687 RefPtr<nsIContent> child =
1688 CreateGenConTextNode(aState, EmptyString(), std::move(initializer));
1689 aAddChild(child);
1690}
1691
1692// Frames for these may not be leaves in the proper sense, but we still don't
1693// want to expose generated content on them. For the purposes of the page they
1694// should be leaves.
1695static bool HasUAWidget(const Element& aOriginatingElement) {
1696 const ShadowRoot* sr = aOriginatingElement.GetShadowRoot();
1697 return sr && sr->IsUAWidget();
1698}
1699
1700static bool IsBaseAppearanceSelect(const Element& aElement) {
1701 if (const auto* select = HTMLSelectElement::FromNode(aElement)) {
1702 return select->IsBaseSelectAppearance();
1703 }
1704 return false;
1705}
1706
1707/*
1708 * aParentFrame - the frame that should be the parent of the generated
1709 * content. This is the frame for the corresponding content node,
1710 * which must not be a leaf frame.
1711 *
1712 * Any items created are added to aItems.
1713 *
1714 * We create an XML element (tag _moz_generated_content_before/after/marker)
1715 * representing the pseudoelement. We create a DOM node for each 'content'
1716 * item and make those nodes the children of the XML element. Then we create
1717 * a frame subtree for the XML element as if it were a regular child of
1718 * aParentFrame/aParentContent, giving the XML element the ::before, ::after
1719 * or ::marker style.
1720 */
1721void nsCSSFrameConstructor::CreateGeneratedContentItem(
1722 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
1723 Element& aOriginatingElement, ComputedStyle& aStyle,
1724 PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems,
1725 ItemFlags aExtraFlags) {
1726 MOZ_ASSERT(aPseudoElement == PseudoStyleType::Before ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1727 aPseudoElement == PseudoStyleType::After ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1728 aPseudoElement == PseudoStyleType::Marker ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1729 aPseudoElement == PseudoStyleType::Backdrop ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1730 aPseudoElement == PseudoStyleType::Checkmark ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1731 aPseudoElement == PseudoStyleType::PickerIcon,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1732 "unexpected aPseudoElement")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPseudoElement == PseudoStyleType::Before || aPseudoElement
== PseudoStyleType::After || aPseudoElement == PseudoStyleType
::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement
== PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType
::PickerIcon)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aPseudoElement == PseudoStyleType
::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement
== PseudoStyleType::Marker || aPseudoElement == PseudoStyleType
::Backdrop || aPseudoElement == PseudoStyleType::Checkmark ||
aPseudoElement == PseudoStyleType::PickerIcon))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
" (" "unexpected aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPseudoElement == PseudoStyleType::Before || aPseudoElement == PseudoStyleType::After || aPseudoElement == PseudoStyleType::Marker || aPseudoElement == PseudoStyleType::Backdrop || aPseudoElement == PseudoStyleType::Checkmark || aPseudoElement == PseudoStyleType::PickerIcon"
") (" "unexpected aPseudoElement" ")"); do { MOZ_CrashSequence
(__null, 1732); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1733
1734 if (aPseudoElement != PseudoStyleType::Backdrop &&
1735 aPseudoElement != PseudoStyleType::PickerIcon &&
1736 HasUAWidget(aOriginatingElement) &&
1737 !aOriginatingElement.IsHTMLElement(nsGkAtoms::details) &&
1738 !IsBaseAppearanceSelect(aOriginatingElement)) {
1739 // ::before / ::after / ::marker shouldn't work on <video> / <input>.
1740 return;
1741 }
1742
1743 ServoStyleSet* styleSet = mPresShell->StyleSet();
1744
1745 // Probe for the existence of the pseudo-element.
1746 // |ProbePseudoElementStyle| checks the relevant properties for the pseudo.
1747 // It only returns a non-null value if the pseudo should exist.
1748 RefPtr<ComputedStyle> pseudoStyle = styleSet->ProbePseudoElementStyle(
1749 aOriginatingElement, aPseudoElement, nullptr, &aStyle);
1750 if (!pseudoStyle) {
1751 return;
1752 }
1753
1754 nsAtom* elemName = nullptr;
1755 nsAtom* property = nullptr;
1756 switch (aPseudoElement) {
1757 case PseudoStyleType::Before:
1758 elemName = nsGkAtoms::mozgeneratedcontentbefore;
1759 property = nsGkAtoms::beforePseudoProperty;
1760 break;
1761 case PseudoStyleType::After:
1762 elemName = nsGkAtoms::mozgeneratedcontentafter;
1763 property = nsGkAtoms::afterPseudoProperty;
1764 break;
1765 case PseudoStyleType::Marker:
1766 // We want to get a marker style even if we match no rules, but we still
1767 // want to check the result of GeneratedContentPseudoExists.
1768 elemName = nsGkAtoms::mozgeneratedcontentmarker;
1769 property = nsGkAtoms::markerPseudoProperty;
1770 break;
1771 case PseudoStyleType::Backdrop:
1772 elemName = nsGkAtoms::mozgeneratedcontentbackdrop;
1773 property = nsGkAtoms::backdropPseudoProperty;
1774 break;
1775 case PseudoStyleType::Checkmark:
1776 elemName = nsGkAtoms::mozgeneratedcontentcheckmark;
1777 property = nsGkAtoms::checkmarkPseudoProperty;
1778 break;
1779 case PseudoStyleType::PickerIcon:
1780 elemName = nsGkAtoms::mozgeneratedcontentpickericon;
1781 property = nsGkAtoms::pickerIconPseudoProperty;
1782 break;
1783 default:
1784 MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement")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 aPseudoElement" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected aPseudoElement" ")");
do { MOZ_CrashSequence(__null, 1784); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1785 }
1786
1787 auto flags = ItemFlags{ItemFlag::IsGeneratedContent} + aExtraFlags;
1788 if (aState.mCreatingExtraFrames) {
1789 // Extra frames (e.g. repeated table headers) share the pseudo-element of
1790 // the original frame, rather than creating a new one.
1791 RefPtr existing =
1792 static_cast<Element*>(aOriginatingElement.GetProperty(property));
1793 if (!existing || !existing->GetPrimaryFrame()) {
1794 return;
1795 }
1796 AddFrameConstructionItemsInternal(aState, existing, aParentFrame, true,
1797 existing->GetPrimaryFrame()->Style(),
1798 flags, aItems);
1799 return;
1800 }
1801
1802 RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
1803 elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
1804 RefPtr<Element> container;
1805 nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1806 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1807 return;
1808 }
1809
1810 // Cleared when the pseudo is unbound from the tree, so no need to store a
1811 // strong reference, nor a destructor.
1812 aOriginatingElement.SetProperty(property, container.get());
1813
1814 container->SetIsNativeAnonymousRoot();
1815 container->SetPseudoElementType(aPseudoElement);
1816
1817 BindContext context(aOriginatingElement, BindContext::ForNativeAnonymous);
1818 rv = container->BindToTree(context, aOriginatingElement);
1819 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1820 container->UnbindFromTree();
1821 return;
1822 }
1823
1824 if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
1825 container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
1826 }
1827
1828 // Servo has already eagerly computed the style for the container, so we can
1829 // just stick the style on the element and avoid an additional traversal.
1830 //
1831 // We don't do this for pseudos that may trigger animations or transitions,
1832 // since those need to be kicked off by the traversal machinery, nor for
1833 // pseudos that declare timelines or a timeline-scope, which the traversal
1834 // registers.
1835 //
1836 // Note that when a pseudo-element animates, we flag the originating element,
1837 // so we check that flag, but we could also a more expensive (but exhaustive)
1838 // check using EffectSet::GetEffectSet, for example.
1839 if (!Servo_ComputedValues_NeedsAnimationTraversal(pseudoStyle) &&
1840 !aOriginatingElement.MayHaveAnimations()) {
1841 Servo_SetExplicitStyle(container, pseudoStyle);
1842 } else {
1843 // If animations are involved, we avoid the SetExplicitStyle optimization
1844 // above. We need to grab style with animations from the pseudo element and
1845 // replace old one.
1846 mPresShell->StyleSet()->StyleNewSubtree(container);
1847 pseudoStyle = ServoStyleSet::ResolveServoStyle(*container);
1848 }
1849 if (aPseudoElement != PseudoStyleType::Backdrop) {
1850 auto AppendChild = [&container, this](nsIContent* aChild) {
1851 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
1852 // here; it would get set under AppendChildTo. But AppendChildTo might
1853 // think that we're going from not being anonymous to being anonymous and
1854 // do some extra work; setting the flag here avoids that.
1855 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1856 container->AppendChildTo(aChild, false, IgnoreErrors());
1857 if (auto* childElement = Element::FromNode(aChild)) {
1858 // If we created any children elements, Servo needs to traverse them,
1859 // but the root is already set up.
1860 mPresShell->StyleSet()->StyleNewSubtree(childElement);
1861 }
1862 };
1863 auto items = pseudoStyle->StyleContent()->NonAltContentItems();
1864 size_t index = 0;
1865 for (const auto& item : items) {
1866 CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
1867 index++, AppendChild);
1868 }
1869 // If a ::marker has no 'content' then generate it from its 'list-style-*'.
1870 if (index == 0 && aPseudoElement == PseudoStyleType::Marker) {
1871 CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
1872 *pseudoStyle, AppendChild);
1873 }
1874 }
1875 AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
1876 pseudoStyle, flags, aItems);
1877}
1878
1879/****************************************************
1880 ** BEGIN TABLE SECTION
1881 ****************************************************/
1882
1883// The term pseudo frame is being used instead of anonymous frame, since
1884// anonymous frame has been used elsewhere to refer to frames that have
1885// generated content
1886
1887// Return whether the given frame is a table pseudo-frame. Note that
1888// cell-content and table-outer frames have pseudo-types, but are always
1889// created, even for non-anonymous cells and tables respectively. So for those
1890// we have to examine the cell or table frame to see whether it's a pseudo
1891// frame. In particular, a lone table caption will have a table wrapper as its
1892// parent, but will also trigger construction of an empty inner table, which
1893// will be the one we can examine to see whether the wrapper was a pseudo-frame.
1894static bool IsTablePseudo(nsIFrame* aFrame) {
1895 auto pseudoType = aFrame->Style()->GetPseudoType();
1896 if (pseudoType == PseudoStyleType::NotPseudo) {
1897 return false;
1898 }
1899 return pseudoType == PseudoStyleType::MozTable ||
1900 pseudoType == PseudoStyleType::MozInlineTable ||
1901 pseudoType == PseudoStyleType::MozTableColumnGroup ||
1902 pseudoType == PseudoStyleType::MozTableRowGroup ||
1903 pseudoType == PseudoStyleType::MozTableRow ||
1904 pseudoType == PseudoStyleType::MozTableCell ||
1905 (pseudoType == PseudoStyleType::MozCellContent &&
1906 aFrame->GetParent()->Style()->GetPseudoType() ==
1907 PseudoStyleType::MozTableCell) ||
1908 (pseudoType == PseudoStyleType::MozTableWrapper &&
1909 static_cast<nsTableWrapperFrame*>(aFrame)
1910 ->InnerTableFrame()
1911 ->Style()
1912 ->IsPseudoOrAnonBox());
1913}
1914
1915static bool IsRubyPseudo(nsIFrame* aFrame) {
1916 return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudoType());
1917}
1918
1919// Note that this is (subtly) different to ParentIsWrapperAnonBox, since
1920// ParentIsWrapperAnonBox is really just about restyles, but there are wrapper
1921// anon boxes that don't need to return true for that...
1922// FIXME(emilio): This should be less complicated, ParentIsWrapperAnonBox should
1923// probably be renamed to something else, and this should just use
1924// IsWrapperAnonBox or similar...
1925static bool IsWrapperPseudo(nsIFrame* aFrame) {
1926 auto pseudoType = aFrame->Style()->GetPseudoType();
1927 if (!PseudoStyle::IsAnonBox(pseudoType)) {
1928 return false;
1929 }
1930 return PseudoStyle::IsWrapperAnonBox(pseudoType) || IsTablePseudo(aFrame);
1931}
1932
1933static bool IsInAnonymousTable(nsIFrame* aFrame) {
1934 for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
1935 if (!IsWrapperPseudo(f)) {
1936 return false;
1937 }
1938 if (f->IsTableWrapperFrame()) {
1939 return true;
1940 }
1941 }
1942 MOZ_ASSERT_UNREACHABLE("Expected to be called inside tables")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: "
"Expected to be called inside tables" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 1942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Expected to be called inside tables"
")"); do { MOZ_CrashSequence(__null, 1942); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1943 return false;
1944}
1945
1946/* static */
1947nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType(
1948 LayoutFrameType aFrameType) {
1949 if (aFrameType == LayoutFrameType::Table) {
1950 return eTypeTable;
1951 }
1952 if (aFrameType == LayoutFrameType::TableRowGroup) {
1953 return eTypeRowGroup;
1954 }
1955 if (aFrameType == LayoutFrameType::TableRow) {
1956 return eTypeRow;
1957 }
1958 if (aFrameType == LayoutFrameType::TableColGroup) {
1959 return eTypeColGroup;
1960 }
1961 if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1962 return eTypeRubyBaseContainer;
1963 }
1964 if (aFrameType == LayoutFrameType::RubyTextContainer) {
1965 return eTypeRubyTextContainer;
1966 }
1967 if (aFrameType == LayoutFrameType::Ruby) {
1968 return eTypeRuby;
1969 }
1970
1971 return eTypeBlock;
1972}
1973
1974// Pull all the captions present in aItems out into aCaptions.
1975static void PullOutCaptionFrames(nsFrameList& aList, nsFrameList& aCaptions) {
1976 nsIFrame* child = aList.FirstChild();
1977 while (child) {
1978 nsIFrame* nextSibling = child->GetNextSibling();
1979 if (child->StyleDisplay()->mDisplay == StyleDisplay::TableCaption) {
1980 aList.RemoveFrame(child);
1981 aCaptions.AppendFrame(nullptr, child);
1982 }
1983 child = nextSibling;
1984 }
1985}
1986
1987// Construct the outer, inner table frames and the children frames for the
1988// table.
1989// XXX Page break frames for pseudo table frames are not constructed to avoid
1990// the risk associated with revising the pseudo frame mechanism. The long term
1991// solution of having frames handle page-break-before/after will solve the
1992// problem.
1993nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
1994 FrameConstructionItem& aItem,
1995 nsContainerFrame* aParentFrame,
1996 const nsStyleDisplay* aDisplay,
1997 nsFrameList& aFrameList) {
1998 MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::Table ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::Table || aDisplay
->mDisplay == StyleDisplay::InlineTable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::Table || aDisplay->mDisplay == StyleDisplay::InlineTable
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
" (" "Unexpected call" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2000); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2000); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
1999 aDisplay->mDisplay == StyleDisplay::InlineTable,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::Table || aDisplay
->mDisplay == StyleDisplay::InlineTable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::Table || aDisplay->mDisplay == StyleDisplay::InlineTable
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
" (" "Unexpected call" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2000); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2000); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
2000 "Unexpected call")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::Table || aDisplay
->mDisplay == StyleDisplay::InlineTable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::Table || aDisplay->mDisplay == StyleDisplay::InlineTable
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
" (" "Unexpected call" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2000); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2000); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2001
2002 nsIContent* const content = aItem.mContent;
2003 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2004 const bool isMathMLContent = content->IsMathMLElement();
2005
2006 // create the pseudo SC for the table wrapper as a child of the inner SC
2007 RefPtr<ComputedStyle> outerComputedStyle =
2008 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2009 PseudoStyleType::MozTableWrapper, computedStyle);
2010
2011 // Create the table wrapper frame which holds the caption and inner table
2012 // frame
2013 nsContainerFrame* newFrame;
2014 if (isMathMLContent) {
2015 newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
2016 } else {
2017 newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
2018 }
2019
2020 nsContainerFrame* geometricParent = aState.GetGeometricParent(
2021 *outerComputedStyle->StyleDisplay(), aParentFrame);
2022
2023 // Init the table wrapper frame
2024 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2025
2026 // Create the inner table frame
2027 nsContainerFrame* innerFrame;
2028 if (isMathMLContent) {
2029 innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
2030 } else {
2031 innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
2032 }
2033
2034 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2035 innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2036
2037 // Put the newly created frames into the right child list
2038 SetInitialSingleChild(newFrame, innerFrame);
2039
2040 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
2041
2042 if (!mRootElementFrame) {
2043 mRootElementFrame = newFrame;
2044 }
2045
2046 nsFrameList childList;
2047
2048 // Process children
2049 nsFrameConstructorSaveState absoluteSaveState;
2050
2051 // Mark the table frame as an absolute container if needed
2052 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2053 if (newFrame->IsAbsPosContainingBlock()) {
2054 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2055 }
2056
2057 nsFrameConstructorSaveState floatSaveState;
2058 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
2059
2060 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2061 ConstructFramesFromItemList(
2062 aState, aItem.mChildItems, innerFrame,
2063 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2064 } else {
2065 ProcessChildren(aState, content, computedStyle, innerFrame, true, childList,
2066 false);
2067 }
2068
2069 nsFrameList captionList;
2070 PullOutCaptionFrames(childList, captionList);
2071
2072 // Set the inner table frame's principal child list.
2073 innerFrame->SetInitialChildList(FrameChildListID::Principal,
2074 std::move(childList));
2075
2076 // Append caption frames to the table wrapper frame's principal child list.
2077 if (captionList.NotEmpty()) {
2078 captionList.ApplySetParent(newFrame);
2079 newFrame->AppendFrames(FrameChildListID::Principal, std::move(captionList));
2080 }
2081
2082 return newFrame;
2083}
2084
2085static void MakeTablePartAbsoluteContainingBlock(
2086 nsFrameConstructorState& aState, nsFrameConstructorSaveState& aAbsSaveState,
2087 nsContainerFrame* aFrame) {
2088 // If we're positioned, then we need to become an absolute containing block
2089 // for any absolutely positioned children.
2090 aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2091 if (aFrame->IsAbsPosContainingBlock()) {
2092 aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2093 }
2094}
2095
2096nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
2097 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2098 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2099 nsFrameList& aFrameList) {
2100 MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableRow ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay
->mDisplay == StyleDisplay::TableRowGroup || aDisplay->
mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay
== StyleDisplay::TableHeaderGroup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup
|| aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
aDisplay->mDisplay == StyleDisplay::TableHeaderGroup))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
" (" "Not a row or row group" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
") (" "Not a row or row group" ")"); do { MOZ_CrashSequence(
__null, 2104); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2101 aDisplay->mDisplay == StyleDisplay::TableRowGroup ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay
->mDisplay == StyleDisplay::TableRowGroup || aDisplay->
mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay
== StyleDisplay::TableHeaderGroup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup
|| aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
aDisplay->mDisplay == StyleDisplay::TableHeaderGroup))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
" (" "Not a row or row group" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
") (" "Not a row or row group" ")"); do { MOZ_CrashSequence(
__null, 2104); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2102 aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay
->mDisplay == StyleDisplay::TableRowGroup || aDisplay->
mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay
== StyleDisplay::TableHeaderGroup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup
|| aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
aDisplay->mDisplay == StyleDisplay::TableHeaderGroup))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
" (" "Not a row or row group" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
") (" "Not a row or row group" ")"); do { MOZ_CrashSequence(
__null, 2104); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2103 aDisplay->mDisplay == StyleDisplay::TableHeaderGroup,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay
->mDisplay == StyleDisplay::TableRowGroup || aDisplay->
mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay
== StyleDisplay::TableHeaderGroup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup
|| aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
aDisplay->mDisplay == StyleDisplay::TableHeaderGroup))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
" (" "Not a row or row group" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
") (" "Not a row or row group" ")"); do { MOZ_CrashSequence(
__null, 2104); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2104 "Not a row or row group")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay
->mDisplay == StyleDisplay::TableRowGroup || aDisplay->
mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay
== StyleDisplay::TableHeaderGroup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDisplay->mDisplay == StyleDisplay
::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup
|| aDisplay->mDisplay == StyleDisplay::TableFooterGroup ||
aDisplay->mDisplay == StyleDisplay::TableHeaderGroup))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
" (" "Not a row or row group" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableRow || aDisplay->mDisplay == StyleDisplay::TableRowGroup || aDisplay->mDisplay == StyleDisplay::TableFooterGroup || aDisplay->mDisplay == StyleDisplay::TableHeaderGroup"
") (" "Not a row or row group" ")"); do { MOZ_CrashSequence(
__null, 2104); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2105 MOZ_ASSERT(aItem.mComputedStyle->StyleDisplay() == aDisplay,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aItem.mComputedStyle->StyleDisplay() == aDisplay)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aItem.mComputedStyle->StyleDisplay() == aDisplay)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aItem.mComputedStyle->StyleDisplay() == aDisplay"
" (" "Display style doesn't match style" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2106); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2106 "Display style doesn't match style")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aItem.mComputedStyle->StyleDisplay() == aDisplay)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aItem.mComputedStyle->StyleDisplay() == aDisplay)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aItem.mComputedStyle->StyleDisplay() == aDisplay"
" (" "Display style doesn't match style" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2106); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2107 nsIContent* const content = aItem.mContent;
2108 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2109
2110 nsContainerFrame* newFrame;
2111 if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2112 if (content->IsMathMLElement()) {
2113 newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
2114 } else {
2115 newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
2116 }
2117 } else {
2118 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
2119 }
2120
2121 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2122
2123 nsFrameConstructorSaveState absoluteSaveState;
2124 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
2125
2126 nsFrameConstructorSaveState floatSaveState;
2127 aState.MaybePushFloatContainingBlock(newFrame, floatSaveState);
2128
2129 nsFrameList childList;
2130 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2131 ConstructFramesFromItemList(
2132 aState, aItem.mChildItems, newFrame,
2133 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2134 } else {
2135 ProcessChildren(aState, content, computedStyle, newFrame, true, childList,
2136 false);
2137 }
2138
2139 newFrame->SetInitialChildList(FrameChildListID::Principal,
2140 std::move(childList));
2141 aFrameList.AppendFrame(nullptr, newFrame);
2142 return newFrame;
2143}
2144
2145nsIFrame* nsCSSFrameConstructor::ConstructTableCol(
2146 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2147 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2148 nsFrameList& aFrameList) {
2149 nsIContent* const content = aItem.mContent;
2150 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2151
2152 nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
2153 InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2154
2155 NS_ASSERTION(colFrame->Style() == computedStyle, "Unexpected style")do { if (!(colFrame->Style() == computedStyle)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Unexpected style", "colFrame->Style() == computedStyle"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2155); MOZ_PretendNoReturn
(); } } while (0)
;
2156
2157 aFrameList.AppendFrame(nullptr, colFrame);
2158
2159 // construct additional col frames if the col frame has a span > 1
2160 int32_t span = colFrame->GetSpan();
2161 for (int32_t spanX = 1; spanX < span; spanX++) {
2162 nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
2163 InitAndRestoreFrame(aState, content, aParentFrame, newCol,
2164 AllowCounters::No);
2165 aFrameList.LastChild()->SetNextContinuation(newCol);
2166 newCol->SetPrevContinuation(aFrameList.LastChild());
2167 aFrameList.AppendFrame(nullptr, newCol);
2168 newCol->SetColType(eColAnonymousCol);
2169 }
2170
2171 return colFrame;
2172}
2173
2174nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
2175 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2176 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2177 nsFrameList& aFrameList) {
2178 MOZ_ASSERT(aDisplay->mDisplay == StyleDisplay::TableCell, "Unexpected call")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplay->mDisplay == StyleDisplay::TableCell)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aDisplay->mDisplay == StyleDisplay::TableCell))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay->mDisplay == StyleDisplay::TableCell"
" (" "Unexpected call" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableCell"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2178); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2179
2180 nsIContent* const content = aItem.mContent;
2181 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2182 const bool isMathMLContent = content->IsMathMLElement();
2183
2184 nsTableFrame* tableFrame =
2185 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2186 nsContainerFrame* cellFrame;
2187 // <mtable> is border separate in mathml.css and the MathML code doesn't
2188 // implement border collapse. For those users who style <mtable> with border
2189 // collapse, give them the default non-MathML table frames that understand
2190 // border collapse. This won't break us because MathML table frames are all
2191 // subclasses of the default table code, and so we can freely mix <mtable>
2192 // with <mtr> or <tr>, <mtd> or <td>. What will happen is just that non-MathML
2193 // frames won't understand MathML attributes and will therefore miss the
2194 // special handling that the MathML code does.
2195 if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
2196 cellFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
2197 } else {
2198 // Warning: If you change this and add a wrapper frame around table cell
2199 // frames, make sure Bug 368554 doesn't regress!
2200 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2201 cellFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
2202 }
2203
2204 // Initialize the table cell frame
2205 InitAndRestoreFrame(aState, content, aParentFrame, cellFrame);
2206 cellFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2207
2208 // Resolve pseudo style and initialize the body cell frame
2209 RefPtr<ComputedStyle> innerPseudoStyle =
2210 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2211 PseudoStyleType::MozCellContent, computedStyle);
2212
2213 nsContainerFrame* cellInnerFrame;
2214 nsContainerFrame* scrollFrame = nullptr;
2215 bool isScrollable = false;
2216 // Create a block frame that will format the cell's content
2217 if (isMathMLContent) {
2218 cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2219 } else {
2220 isScrollable = innerPseudoStyle->StyleDisplay()->IsScrollableOverflow() &&
2221 !aState.mPresContext->IsPaginated() &&
2222 StaticPrefs::layout_tables_scrollable_cells();
2223 if (isScrollable) {
2224 innerPseudoStyle = BeginBuildingScrollContainerFrame(
2225 aState, content, innerPseudoStyle, cellFrame, false, scrollFrame);
2226 }
2227 cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle);
2228 }
2229 auto* parent = scrollFrame ? scrollFrame : cellFrame;
2230 InitAndRestoreFrame(aState, content, parent, cellInnerFrame);
2231
2232 nsFrameConstructorSaveState absoluteSaveState;
2233 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, cellFrame);
2234
2235 nsFrameConstructorSaveState floatSaveState;
2236 aState.MaybePushFloatContainingBlock(cellInnerFrame, floatSaveState);
2237
2238 nsFrameList childList;
2239 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2240 AutoFrameConstructionPageName pageNameTracker(aState, cellInnerFrame);
2241 ConstructFramesFromItemList(
2242 aState, aItem.mChildItems, cellInnerFrame,
2243 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2244 } else {
2245 // Process the child content
2246 ProcessChildren(aState, content, computedStyle, cellInnerFrame, true,
2247 childList, !isMathMLContent);
2248 }
2249
2250 cellInnerFrame->SetInitialChildList(FrameChildListID::Principal,
2251 std::move(childList));
2252
2253 if (isScrollable) {
2254 FinishBuildingScrollContainerFrame(scrollFrame, cellInnerFrame);
2255 }
2256 SetInitialSingleChild(cellFrame, scrollFrame ? scrollFrame : cellInnerFrame);
2257 aFrameList.AppendFrame(nullptr, cellFrame);
2258 return cellFrame;
2259}
2260
2261static inline bool NeedFrameFor(const nsFrameConstructorState& aState,
2262 nsContainerFrame* aParentFrame,
2263 nsIContent* aChildContent) {
2264 MOZ_ASSERT(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2265); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2265 "Why did we get called?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2265); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2266
2267 // don't create a whitespace frame if aParentFrame doesn't want it.
2268 // always create frames for children in generated content. counter(),
2269 // quotes, and attr() content can easily change dynamically and we don't
2270 // want to be reconstructing frames. It's not even clear that these
2271 // should be considered ignorable just because they evaluate to
2272 // whitespace.
2273
2274 // We could handle all this in CreateNeededPseudoContainers or some other
2275 // place after we build our frame construction items, but that would involve
2276 // creating frame construction items for whitespace kids that ignores
2277 // white-space, where we know we'll be dropping them all anyway, and involve
2278 // an extra walk down the frame construction item list.
2279 auto excludesIgnorableWhitespace = [](nsIFrame* aParentFrame) {
2280 return aParentFrame->IsMathMLFrame();
2281 };
2282 if (!aParentFrame || !excludesIgnorableWhitespace(aParentFrame) ||
2283 aParentFrame->IsGeneratedContentFrame() || !aChildContent->IsText()) {
2284 return true;
2285 }
2286
2287 aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2288 NS_REFRAME_IF_WHITESPACE);
2289 return !aChildContent->TextIsOnlyWhitespace();
2290}
2291
2292/***********************************************
2293 * END TABLE SECTION
2294 ***********************************************/
2295
2296nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
2297 Element* aDocElement) {
2298 MOZ_ASSERT(GetRootFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetRootFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(GetRootFrame()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("GetRootFrame()"
" (" "No viewport? Someone forgot to call ConstructRootFrame!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2299
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2299); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2299 "No viewport? Someone forgot to call ConstructRootFrame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetRootFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(GetRootFrame()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("GetRootFrame()"
" (" "No viewport? Someone forgot to call ConstructRootFrame!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2299
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2299); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2300 MOZ_ASSERT(!mDocElementContainingBlock,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDocElementContainingBlock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDocElementContainingBlock)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDocElementContainingBlock"
" (" "Shouldn't have a doc element containing block here" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2301); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2301); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2301 "Shouldn't have a doc element containing block here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDocElementContainingBlock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDocElementContainingBlock)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDocElementContainingBlock"
" (" "Shouldn't have a doc element containing block here" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2301); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2301); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2302
2303 // Ensure the document element is styled at this point.
2304 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2305 // construction from PresShell::Initialize.
2306 if (!aDocElement->HasServoData()) {
2307 mPresShell->StyleSet()->StyleNewSubtree(aDocElement);
2308 }
2309 aDocElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2310
2311 // Make sure to call UpdateViewportScrollStylesOverride before
2312 // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2313 // properly.
2314 DebugOnly<nsIContent*> propagatedScrollFrom;
2315 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2316 propagatedScrollFrom = presContext->UpdateViewportScrollStylesOverride();
2317 }
2318
2319 SetUpDocElementContainingBlock(aDocElement);
2320
2321 NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now")do { if (!(mDocElementContainingBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should have parent by now", "mDocElementContainingBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2321); MOZ_PretendNoReturn(); } } while (0)
;
2322 nsFrameConstructorState state(
2323 mPresShell,
2324 GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2325 nullptr, nullptr);
2326
2327 RefPtr<ComputedStyle> computedStyle =
2328 ServoStyleSet::ResolveServoStyle(*aDocElement);
2329
2330 const nsStyleDisplay* display = computedStyle->StyleDisplay();
2331
2332 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2333
2334 NS_ASSERTION(!display->IsScrollableOverflow() ||do { if (!(!display->IsScrollableOverflow() || state.mPresContext
->IsPaginated() || propagatedScrollFrom == aDocElement)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Scrollbars should have been propagated to the viewport"
, "!display->IsScrollableOverflow() || state.mPresContext->IsPaginated() || propagatedScrollFrom == aDocElement"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2337); MOZ_PretendNoReturn
(); } } while (0)
2335 state.mPresContext->IsPaginated() ||do { if (!(!display->IsScrollableOverflow() || state.mPresContext
->IsPaginated() || propagatedScrollFrom == aDocElement)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Scrollbars should have been propagated to the viewport"
, "!display->IsScrollableOverflow() || state.mPresContext->IsPaginated() || propagatedScrollFrom == aDocElement"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2337); MOZ_PretendNoReturn
(); } } while (0)
2336 propagatedScrollFrom == aDocElement,do { if (!(!display->IsScrollableOverflow() || state.mPresContext
->IsPaginated() || propagatedScrollFrom == aDocElement)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Scrollbars should have been propagated to the viewport"
, "!display->IsScrollableOverflow() || state.mPresContext->IsPaginated() || propagatedScrollFrom == aDocElement"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2337); MOZ_PretendNoReturn
(); } } while (0)
2337 "Scrollbars should have been propagated to the viewport")do { if (!(!display->IsScrollableOverflow() || state.mPresContext
->IsPaginated() || propagatedScrollFrom == aDocElement)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Scrollbars should have been propagated to the viewport"
, "!display->IsScrollableOverflow() || state.mPresContext->IsPaginated() || propagatedScrollFrom == aDocElement"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2337); MOZ_PretendNoReturn
(); } } while (0)
;
2338
2339 if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)(__builtin_expect(!!(display->mDisplay == StyleDisplay::None
), 0))
) {
2340 return nullptr;
2341 }
2342
2343 // This implements "The Principal Writing Mode".
2344 // https://drafts.csswg.org/css-writing-modes-3/#principal-flow
2345 //
2346 // If there's a <body> element in an HTML document, its writing-mode,
2347 // direction, and text-orientation override the root element's used value.
2348 //
2349 // We need to copy <body>'s WritingMode to mDocElementContainingBlock before
2350 // construct mRootElementFrame so that anonymous internal frames such as
2351 // <html> with table style can copy their parent frame's mWritingMode in
2352 // nsIFrame::Init().
2353 MOZ_ASSERT(!mRootElementFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRootElementFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRootElementFrame))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mRootElementFrame"
" (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2355); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2354 "We need to copy <body>'s principal writing-mode before "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRootElementFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRootElementFrame))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mRootElementFrame"
" (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2355); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2355 "constructing mRootElementFrame.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRootElementFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRootElementFrame))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mRootElementFrame"
" (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2355); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2356
2357 const WritingMode propagatedWM = [&] {
2358 const WritingMode rootWM(computedStyle);
2359 if (computedStyle->StyleDisplay()->IsContainAny()) {
2360 return rootWM;
2361 }
2362 Element* body = mDocument->GetBodyElement();
2363 if (!body) {
2364 return rootWM;
2365 }
2366 RefPtr<ComputedStyle> bodyStyle = ResolveComputedStyle(body);
2367 if (bodyStyle->StyleDisplay()->IsContainAny()) {
2368 return rootWM;
2369 }
2370 const WritingMode bodyWM(bodyStyle);
2371 if (bodyWM != rootWM) {
2372 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Layout"_ns,
2373 mDocument,
2374 PropertiesFile::LAYOUT_PROPERTIES,
2375 "PrincipalWritingModePropagationWarning");
2376 }
2377 return bodyWM;
2378 }();
2379
2380 mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
2381 propagatedWM);
2382
2383 // Push the absolute containing block now so we can absolutely position the
2384 // root element
2385 nsFrameConstructorSaveState canvasCbSaveState;
2386 mCanvasFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2387
2388 state.PushAbsoluteContainingBlock(mCanvasFrame, mCanvasFrame,
2389 canvasCbSaveState);
2390
2391 nsFrameConstructorSaveState docElementCbSaveState;
2392 if (mCanvasFrame != mDocElementContainingBlock) {
2393 mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2394 state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2395 mDocElementContainingBlock,
2396 docElementCbSaveState);
2397 }
2398
2399 // The rules from CSS 2.1, section 9.2.4, have already been applied
2400 // by the style system, so we can assume that display->mDisplay is
2401 // either NONE, BLOCK, or TABLE.
2402
2403 // contentFrame is the primary frame for the root element. frameList contains
2404 // the children of the initial containing block.
2405 //
2406 // The first of those frames is usually `contentFrame`, but it can be
2407 // different, in particular if the root frame is positioned, in which case
2408 // contentFrame is the out-of-flow frame and frameList.FirstChild() is the
2409 // placeholder.
2410 //
2411 // The rest of the frames in frameList are the anonymous content of the canvas
2412 // frame.
2413 nsContainerFrame* contentFrame;
2414 nsFrameList frameList;
2415 bool processChildren = false;
2416
2417 nsFrameConstructorSaveState absoluteSaveState;
2418
2419 if (aDocElement->IsSVGElement()) {
2420 if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2421 return nullptr;
2422 }
2423 // We're going to call the right function ourselves, so no need to give a
2424 // function to this FrameConstructionData.
2425
2426 // XXXbz on the other hand, if we converted this whole function to
2427 // FrameConstructionData/Item, then we'd need the right function
2428 // here... but would probably be able to get away with less code in this
2429 // function in general.
2430 static constexpr FrameConstructionData rootSVGData;
2431 AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
2432 do_AddRef(computedStyle), true);
2433
2434 contentFrame = static_cast<nsContainerFrame*>(ConstructOuterSVG(
2435 state, item, mDocElementContainingBlock, display, frameList));
2436 } else if (display->mDisplay == StyleDisplay::Flex ||
2437 display->mDisplay == StyleDisplay::WebkitBox ||
2438 display->mDisplay == StyleDisplay::Grid ||
2439 display->mDisplay == StyleDisplay::GridLanes) {
2440 auto func = [&] {
2441 if (display->mDisplay == StyleDisplay::Grid ||
2442 display->mDisplay == StyleDisplay::GridLanes) {
2443 return NS_NewGridContainerFrame;
2444 }
2445 return NS_NewFlexContainerFrame;
2446 }();
2447 contentFrame = func(mPresShell, computedStyle);
2448 InitAndRestoreFrame(
2449 state, aDocElement,
2450 state.GetGeometricParent(*display, mDocElementContainingBlock),
2451 contentFrame);
2452 state.AddChild(contentFrame, frameList, aDocElement,
2453 mDocElementContainingBlock);
2454 processChildren = true;
2455
2456 contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2457 if (contentFrame->IsAbsPosContainingBlock()) {
2458 state.PushAbsoluteContainingBlock(contentFrame, contentFrame,
2459 absoluteSaveState);
2460 }
2461 } else if (display->mDisplay == StyleDisplay::Table) {
2462 // We're going to call the right function ourselves, so no need to give a
2463 // function to this FrameConstructionData.
2464
2465 // XXXbz on the other hand, if we converted this whole function to
2466 // FrameConstructionData/Item, then we'd need the right function
2467 // here... but would probably be able to get away with less code in this
2468 // function in general.
2469 static constexpr FrameConstructionData rootTableData;
2470 AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
2471 do_AddRef(computedStyle), true);
2472
2473 // if the document is a table then just populate it.
2474 contentFrame = static_cast<nsContainerFrame*>(ConstructTable(
2475 state, item, mDocElementContainingBlock, display, frameList));
2476 } else if (display->DisplayInside() == StyleDisplayInside::Ruby) {
2477 static constexpr FrameConstructionData data(
2478 &nsCSSFrameConstructor::ConstructBlockRubyFrame);
2479 AutoFrameConstructionItem item(this, &data, aDocElement,
2480 do_AddRef(computedStyle), true);
2481 contentFrame = static_cast<nsContainerFrame*>(ConstructBlockRubyFrame(
2482 state, item,
2483 state.GetGeometricParent(*display, mDocElementContainingBlock), display,
2484 frameList));
2485 } else {
2486 MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(display->mDisplay == StyleDisplay::Block || display
->mDisplay == StyleDisplay::FlowRoot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(display->mDisplay == StyleDisplay
::Block || display->mDisplay == StyleDisplay::FlowRoot))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
" (" "Unhandled display type for root element" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2488); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2488); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2487 display->mDisplay == StyleDisplay::FlowRoot,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(display->mDisplay == StyleDisplay::Block || display
->mDisplay == StyleDisplay::FlowRoot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(display->mDisplay == StyleDisplay
::Block || display->mDisplay == StyleDisplay::FlowRoot))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
" (" "Unhandled display type for root element" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2488); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2488); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2488 "Unhandled display type for root element")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(display->mDisplay == StyleDisplay::Block || display
->mDisplay == StyleDisplay::FlowRoot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(display->mDisplay == StyleDisplay
::Block || display->mDisplay == StyleDisplay::FlowRoot))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
" (" "Unhandled display type for root element" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2488); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2488); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2489 contentFrame = NS_NewBlockFrame(mPresShell, computedStyle);
2490 ConstructBlock(
2491 state, aDocElement,
2492 state.GetGeometricParent(*display, mDocElementContainingBlock),
2493 mDocElementContainingBlock, computedStyle, &contentFrame, frameList,
2494 contentFrame->IsAbsPosContainingBlock() ? contentFrame : nullptr);
2495 }
2496
2497 MOZ_ASSERT(frameList.FirstChild())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(frameList.FirstChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(frameList.FirstChild()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("frameList.FirstChild()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2497); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "frameList.FirstChild()" ")"); do { MOZ_CrashSequence
(__null, 2497); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2498 MOZ_ASSERT(frameList.FirstChild()->GetContent() == aDocElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(frameList.FirstChild()->GetContent() == aDocElement
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(frameList.FirstChild()->GetContent() == aDocElement
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"frameList.FirstChild()->GetContent() == aDocElement", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2498); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameList.FirstChild()->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2498); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2499 MOZ_ASSERT(contentFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentFrame))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentFrame"
")"); do { MOZ_CrashSequence(__null, 2499); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2500
2501 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(processChildren ? !mRootElementFrame : mRootElementFrame
== contentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(processChildren ? !mRootElementFrame
: mRootElementFrame == contentFrame))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
" (" "unexpected mRootElementFrame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2503); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2502 processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(processChildren ? !mRootElementFrame : mRootElementFrame
== contentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(processChildren ? !mRootElementFrame
: mRootElementFrame == contentFrame))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
" (" "unexpected mRootElementFrame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2503); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2503 "unexpected mRootElementFrame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(processChildren ? !mRootElementFrame : mRootElementFrame
== contentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(processChildren ? !mRootElementFrame
: mRootElementFrame == contentFrame))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
" (" "unexpected mRootElementFrame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2503); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2504 if (processChildren) {
2505 mRootElementFrame = contentFrame;
2506 }
2507
2508 // Figure out which frame has the main style for the document element,
2509 // assigning it to mRootElementStyleFrame.
2510 // Backgrounds should be propagated from that frame to the viewport.
2511 contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
2512 bool isChild = mRootElementStyleFrame &&
2513 mRootElementStyleFrame->GetParent() == contentFrame;
2514 if (!isChild) {
2515 mRootElementStyleFrame = mRootElementFrame;
2516 }
2517
2518 if (processChildren) {
2519 // Still need to process the child content
2520 nsFrameList childList;
2521
2522 NS_ASSERTION(do { if (!(!contentFrame->IsBlockFrameOrSubclass() &&
!contentFrame->IsSVGFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only XUL frames should reach here", "!contentFrame->IsBlockFrameOrSubclass() && !contentFrame->IsSVGFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2524); MOZ_PretendNoReturn
(); } } while (0)
2523 !contentFrame->IsBlockFrameOrSubclass() && !contentFrame->IsSVGFrame(),do { if (!(!contentFrame->IsBlockFrameOrSubclass() &&
!contentFrame->IsSVGFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only XUL frames should reach here", "!contentFrame->IsBlockFrameOrSubclass() && !contentFrame->IsSVGFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2524); MOZ_PretendNoReturn
(); } } while (0)
2524 "Only XUL frames should reach here")do { if (!(!contentFrame->IsBlockFrameOrSubclass() &&
!contentFrame->IsSVGFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only XUL frames should reach here", "!contentFrame->IsBlockFrameOrSubclass() && !contentFrame->IsSVGFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2524); MOZ_PretendNoReturn
(); } } while (0)
;
2525
2526 nsFrameConstructorSaveState floatSaveState;
2527 state.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
2528
2529 ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
2530 childList, false);
2531
2532 // Set the initial child lists
2533 contentFrame->SetInitialChildList(FrameChildListID::Principal,
2534 std::move(childList));
2535 }
2536
2537 nsIFrame* newFrame = frameList.FirstChild();
2538 // set the primary frame
2539 aDocElement->SetPrimaryFrame(contentFrame);
2540 mDocElementContainingBlock->AppendFrames(FrameChildListID::Principal,
2541 std::move(frameList));
2542
2543 // NOTE(emilio): This is in the reverse order compared to normal anonymous
2544 // children. We usually generate anonymous kids first, then non-anonymous,
2545 // but we generate the doc element frame the other way around. This is fine
2546 // either way, but generating anonymous children in a different order requires
2547 // changing nsCanvasFrame (and a whole lot of other potentially unknown code)
2548 // to look at the last child to find the root frame rather than the first
2549 // child.
2550 ConstructAnonymousContentForRoot(state, mCanvasFrame,
2551 mRootElementFrame->GetContent(), frameList);
2552 mCanvasFrame->AppendFrames(FrameChildListID::Principal, std::move(frameList));
2553
2554 return newFrame;
2555}
2556
2557RestyleManager* nsCSSFrameConstructor::RestyleManager() const {
2558 return mPresShell->GetPresContext()->RestyleManager();
2559}
2560
2561ViewportFrame* nsCSSFrameConstructor::ConstructRootFrame() {
2562 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ConstructRootFrame",mozilla::AutoProfilerLabelHot raiiObject2563( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
2563 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject2563( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
2564 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
2565
2566 ServoStyleSet* styleSet = mPresShell->StyleSet();
2567
2568 // --------- BUILD VIEWPORT -----------
2569 RefPtr<ComputedStyle> viewportPseudoStyle =
2570 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2571 PseudoStyleType::MozViewport);
2572 ViewportFrame* viewportFrame =
2573 NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2574
2575 // XXXbz do we _have_ to pass a null content pointer to that frame?
2576 // Would it really kill us to pass in the root element or something?
2577 // What would that break?
2578 viewportFrame->Init(nullptr, nullptr, nullptr);
2579
2580 viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2581
2582 mPresShell->SetNeedsWindowPropertiesSync();
2583
2584 // Make it an absolute container for fixed-pos elements
2585 viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2586 viewportFrame->MarkAsAbsoluteContainingBlock();
2587
2588 return viewportFrame;
2589}
2590
2591void nsCSSFrameConstructor::SetUpDocElementContainingBlock(
2592 nsIContent* aDocElement) {
2593 MOZ_ASSERT(aDocElement, "No element?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocElement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aDocElement" " ("
"No element?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2593); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement"
") (" "No element?" ")"); do { MOZ_CrashSequence(__null, 2593
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2594 MOZ_ASSERT(!aDocElement->GetParent(), "Not root content?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aDocElement->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aDocElement->GetParent()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aDocElement->GetParent()" " (" "Not root content?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2594); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aDocElement->GetParent()"
") (" "Not root content?" ")"); do { MOZ_CrashSequence(__null
, 2594); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2595 MOZ_ASSERT(aDocElement->GetUncomposedDoc(), "Not in a document?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocElement->GetUncomposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocElement->GetUncomposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aDocElement->GetUncomposedDoc()" " (" "Not in a document?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2595
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()"
") (" "Not in a document?" ")"); do { MOZ_CrashSequence(__null
, 2595); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2596 MOZ_ASSERT(aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocElement->GetUncomposedDoc()->GetRootElement
() == aDocElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocElement->GetUncomposedDoc
()->GetRootElement() == aDocElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
" (" "Not the root of the document?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2597); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2597 "Not the root of the document?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocElement->GetUncomposedDoc()->GetRootElement
() == aDocElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocElement->GetUncomposedDoc
()->GetRootElement() == aDocElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
" (" "Not the root of the document?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2597); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2598
2599 /*
2600 how the root frame hierarchy should look
2601
2602 Galley presentation, with scrolling:
2603
2604 ViewportFrame [fixed-cb]
2605 ScrollContainerFrame (if needed)
2606 nsCanvasFrame [abs-cb]
2607 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2608 nsTableWrapperFrame, nsPlaceholderFrame,
2609 nsFlexContainerFrame, nsGridContainerFrame)
2610
2611 Print presentation, non-XUL
2612
2613 ViewportFrame
2614 nsCanvasFrame
2615 nsPageSequenceFrame
2616 PrintedSheetFrame
2617 nsPageFrame
2618 nsPageContentFrame [fixed-cb]
2619 nsCanvasFrame [abs-cb]
2620 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2621 nsTableWrapperFrame, nsPlaceholderFrame,
2622 nsFlexContainerFrame,
2623 nsGridContainerFrame)
2624
2625 Print-preview presentation, non-XUL
2626
2627 ViewportFrame
2628 ScrollContainerFrame
2629 nsCanvasFrame
2630 nsPageSequenceFrame
2631 PrintedSheetFrame
2632 nsPageFrame
2633 nsPageContentFrame [fixed-cb]
2634 nsCanvasFrame [abs-cb]
2635 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2636 nsTableWrapperFrame,
2637 nsPlaceholderFrame,
2638 nsFlexContainerFrame,
2639 nsGridContainerFrame)
2640
2641 Print/print preview of XUL is not supported.
2642 [fixed-cb]: the default containing block for fixed-pos content
2643 [abs-cb]: the default containing block for abs-pos content
2644
2645 Meaning of nsCSSFrameConstructor fields:
2646 mRootElementFrame is "root element frame". This is the primary frame for
2647 the root element.
2648 mDocElementContainingBlock is the parent of mRootElementFrame
2649 (i.e. nsCanvasFrame)
2650 mPageSequenceFrame is the nsPageSequenceFrame, or null if there isn't
2651 one
2652 */
2653
2654 // --------- CREATE ROOT FRAME -------
2655
2656 // Create the root frame. The document element's frame is a child of the
2657 // root frame.
2658 //
2659 // The root frame serves two purposes:
2660 // - reserves space for any margins needed for the document element's frame
2661 // - renders the document element's background. This ensures the background
2662 // covers the entire canvas as specified by the CSS2 spec
2663
2664 nsPresContext* presContext = mPresShell->GetPresContext();
2665 const bool isPaginated = presContext->IsRootPaginatedDocument();
2666
2667 const bool isHTML = aDocElement->IsHTMLElement();
2668 const bool isXUL = !isHTML && aDocElement->IsXULElement();
2669
2670 const bool isScrollable = [&] {
2671 if (isPaginated) {
2672 return presContext->HasPaginatedScrolling();
2673 }
2674 // Never create scrollbars for XUL documents or top level XHTML documents
2675 // that disable scrolling.
2676 if (isXUL) {
2677 return false;
2678 }
2679 if (aDocElement->OwnerDoc()->ChromeRulesEnabled() &&
2680 aDocElement->AsElement()->AttrValueIs(
2681 kNameSpaceID_None, nsGkAtoms::scrolling, nsGkAtoms::_false,
2682 eCaseMatters)) {
2683 return false;
2684 }
2685 return true;
2686 }();
2687
2688 nsContainerFrame* viewportFrame =
2689 static_cast<nsContainerFrame*>(GetRootFrame());
2690 ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
2691
2692 nsCanvasFrame* rootCanvasFrame =
2693 NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2694 mCanvasFrame = rootCanvasFrame;
2695 mDocElementContainingBlock = rootCanvasFrame;
2696
2697 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2698
2699 // If the device supports scrolling (e.g., in galley mode on the screen and
2700 // for print-preview, but not when printing), then create a scroll frame that
2701 // will act as the scrolling mechanism for the viewport.
2702 // XXX Do we even need a viewport when printing to a printer?
2703
2704 // We no longer need to do overflow propagation here. It's taken care of
2705 // when we construct frames for the element whose overflow might be
2706 // propagated
2707 NS_ASSERTION(!isScrollable || !isXUL,do { if (!(!isScrollable || !isXUL)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "XUL documents should never be scrollable - see above", "!isScrollable || !isXUL"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2708); MOZ_PretendNoReturn
(); } } while (0)
2708 "XUL documents should never be scrollable - see above")do { if (!(!isScrollable || !isXUL)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "XUL documents should never be scrollable - see above", "!isScrollable || !isXUL"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2708); MOZ_PretendNoReturn
(); } } while (0)
;
2709
2710 nsContainerFrame* newFrame = rootCanvasFrame;
2711 RefPtr<ComputedStyle> rootPseudoStyle;
2712 // we must create a state because if the scrollbars are GFX it needs the
2713 // state to build the scrollbar frames.
2714 nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
2715
2716 // Start off with the viewport as parent; we'll adjust it as needed.
2717 nsContainerFrame* parentFrame = viewportFrame;
2718
2719 ServoStyleSet* styleSet = mPresShell->StyleSet();
2720 // If paginated, make sure we don't put scrollbars in
2721 if (!isScrollable) {
2722 rootPseudoStyle = styleSet->ResolveNonInheritingAnonymousBoxStyle(
2723 PseudoStyleType::MozCanvas);
2724 } else {
2725 // Build the frame. We give it the content we are wrapping which is the
2726 // document element, the root frame, the parent view port frame, and we
2727 // should get back the new frame and the scrollable view if one was
2728 // created.
2729
2730 // Resolve a style for the scrollframe
2731 RefPtr<ComputedStyle> computedStyle =
2732 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2733 PseudoStyleType::MozViewportScroll);
2734
2735 newFrame = nullptr;
2736 rootPseudoStyle = BeginBuildingScrollContainerFrame(
2737 state, aDocElement, computedStyle, viewportFrame, true, newFrame);
2738 parentFrame = newFrame;
2739 }
2740
2741 rootCanvasFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
2742 rootCanvasFrame->Init(aDocElement, parentFrame, nullptr);
2743
2744 if (isScrollable) {
2745 FinishBuildingScrollContainerFrame(parentFrame, rootCanvasFrame);
2746 }
2747
2748 if (isPaginated) {
2749 // Create a page sequence frame
2750 {
2751 RefPtr<ComputedStyle> pageSequenceStyle =
2752 styleSet->ResolveInheritingAnonymousBoxStyle(
2753 PseudoStyleType::MozPageSequence, viewportPseudoStyle);
2754 mPageSequenceFrame =
2755 NS_NewPageSequenceFrame(mPresShell, pageSequenceStyle);
2756 mPageSequenceFrame->Init(aDocElement, rootCanvasFrame, nullptr);
2757 SetInitialSingleChild(rootCanvasFrame, mPageSequenceFrame);
2758 }
2759
2760 // Create the first printed sheet frame, as the sole child (for now) of our
2761 // page sequence frame (mPageSequenceFrame).
2762 auto* printedSheetFrame =
2763 ConstructPrintedSheetFrame(mPresShell, mPageSequenceFrame, nullptr);
2764 SetInitialSingleChild(mPageSequenceFrame, printedSheetFrame);
2765
2766 MOZ_ASSERT(!mNextPageContentFramePageName,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNextPageContentFramePageName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNextPageContentFramePageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mNextPageContentFramePageName" " (" "Next page name should not have been set."
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2767); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2767 "Next page name should not have been set.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNextPageContentFramePageName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNextPageContentFramePageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mNextPageContentFramePageName" " (" "Next page name should not have been set."
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2767
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2767); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2768
2769 // Create the first page, as the sole child (for now) of the printed sheet
2770 // frame that we just created.
2771 nsCanvasFrame* canvasFrame;
2772 nsContainerFrame* pageFrame =
2773 ConstructPageFrame(mPresShell, printedSheetFrame, nullptr, canvasFrame);
2774 pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2775 SetInitialSingleChild(printedSheetFrame, pageFrame);
2776
2777 // The eventual parent of the document element frame.
2778 // XXX should this be set for every new page (in ConstructPageFrame)?
2779 mDocElementContainingBlock = canvasFrame;
2780 }
2781
2782 if (viewportFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
2783 SetInitialSingleChild(viewportFrame, newFrame);
2784 } else {
2785 viewportFrame->AppendFrames(FrameChildListID::Principal,
2786 nsFrameList(newFrame, newFrame));
2787 }
2788
2789 if (ScrollContainerFrame* rootScroll = do_QueryFrame(newFrame)) {
2790 if (nsCOMPtr state = mPresShell->GetDocument()->GetLayoutHistoryState();
2791 state && state->HasStates()) {
2792 rootScroll->RestoreState(state.get());
2793 }
2794 }
2795}
2796
2797void nsCSSFrameConstructor::ConstructAnonymousContentForRoot(
2798 nsFrameConstructorState& aState, nsContainerFrame* aCanvasFrame,
2799 nsIContent* aDocElement, nsFrameList& aFrameList) {
2800 NS_ASSERTION(aCanvasFrame->IsCanvasFrame(), "aFrame should be canvas frame!")do { if (!(aCanvasFrame->IsCanvasFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "aFrame should be canvas frame!", "aCanvasFrame->IsCanvasFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2800); MOZ_PretendNoReturn
(); } } while (0)
;
2801 MOZ_ASSERT(mRootElementFrame->GetContent() == aDocElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRootElementFrame->GetContent() == aDocElement)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mRootElementFrame->GetContent() == aDocElement)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mRootElementFrame->GetContent() == aDocElement"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 2801); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mRootElementFrame->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2801); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2802
2803 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2804 GetAnonymousContent(aDocElement, aCanvasFrame, anonymousItems);
2805
2806 // If we get here, we are rebuilding the anonymous content of the root
2807 // element. In this case, we also need to deal with the custom content
2808 // container.
2809 if (auto* container =
2810 aState.mPresContext->Document()->GetCustomContentContainer()) {
2811 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2812 // construction from PresShell::Initialize. See the similar code-path in
2813 // ConstructDocElementFrame.
2814 if (!container->HasServoData()) {
2815 mPresShell->StyleSet()->StyleNewSubtree(container);
2816 }
2817 anonymousItems.AppendElement(container);
2818 }
2819
2820 if (anonymousItems.IsEmpty()) {
2821 return;
2822 }
2823
2824 AutoFrameConstructionItemList itemsToConstruct(this);
2825 AutoFrameConstructionPageName pageNameTracker(aState, aCanvasFrame);
2826 AddFCItemsForAnonymousContent(aState, aCanvasFrame, anonymousItems,
2827 itemsToConstruct, pageNameTracker);
2828 ConstructFramesFromItemList(aState, itemsToConstruct, aCanvasFrame,
2829 /* aParentIsWrapperAnonBox = */ false,
2830 aFrameList);
2831}
2832
2833PrintedSheetFrame* nsCSSFrameConstructor::ConstructPrintedSheetFrame(
2834 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2835 nsIFrame* aPrevSheetFrame) {
2836 RefPtr<ComputedStyle> printedSheetPseudoStyle =
2837 aPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
2838 PseudoStyleType::MozPrintedSheet);
2839
2840 auto* printedSheetFrame =
2841 NS_NewPrintedSheetFrame(aPresShell, printedSheetPseudoStyle);
2842
2843 printedSheetFrame->Init(nullptr, aParentFrame, aPrevSheetFrame);
2844
2845 return printedSheetFrame;
2846}
2847
2848nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
2849 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2850 nsIFrame* aPrevPageFrame, nsCanvasFrame*& aCanvasFrame) {
2851 ServoStyleSet* styleSet = aPresShell->StyleSet();
2852
2853 RefPtr<ComputedStyle> pagePseudoStyle =
2854 styleSet->ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::MozPage);
2855
2856 nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2857
2858 // Initialize the page frame and force it to have a view. This makes printing
2859 // of the pages easier and faster.
2860 pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2861
2862 RefPtr<const nsAtom> pageName;
2863 if (mNextPageContentFramePageName) {
2864 pageName = mNextPageContentFramePageName.forget();
2865 } else if (aPrevPageFrame) {
2866 pageName = aPrevPageFrame->ComputePageValue();
2867 MOZ_ASSERT(pageName,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pageName))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pageName" " (" "Page name from prev-in-flow should not have been null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2868
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2868 "Page name from prev-in-flow should not have been null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pageName))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pageName" " (" "Page name from prev-in-flow should not have been null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2868
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2869 }
2870 RefPtr<ComputedStyle> pageContentPseudoStyle =
2871 styleSet->ResolvePageContentStyle(pageName,
2872 StylePagePseudoClassFlags::NONE);
2873
2874 nsContainerFrame* pageContentFrame = NS_NewPageContentFrame(
2875 aPresShell, pageContentPseudoStyle, pageName.forget());
2876
2877 nsPageContentFrame* prevPageContentFrame = nullptr;
2878 if (aPrevPageFrame) {
2879 MOZ_ASSERT(aPrevPageFrame->IsPageFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrevPageFrame->IsPageFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrevPageFrame->IsPageFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevPageFrame->IsPageFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevPageFrame->IsPageFrame()"
")"); do { MOZ_CrashSequence(__null, 2879); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2880 prevPageContentFrame =
2881 static_cast<nsPageFrame*>(aPrevPageFrame)->PageContentFrame();
2882 }
2883 pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2884 if (!prevPageContentFrame) {
2885 // The canvas is an inheriting anon box, so needs to be "owned" by the page
2886 // content.
2887 pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES |
2888 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2889 // Make it an absolute container for fixed-pos elements
2890 pageContentFrame->MarkAsAbsoluteContainingBlock();
2891 } else {
2892 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
" (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
") (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")"); do { MOZ_CrashSequence(__null, 2895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2893 pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
" (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
") (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")"); do { MOZ_CrashSequence(__null, 2895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2894 "This bit should've been carried over from the previous continuation "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
" (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
") (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")"); do { MOZ_CrashSequence(__null, 2895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2895 "in nsIFrame::Init().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
" (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->HasAllStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
") (" "This bit should've been carried over from the previous continuation "
"in nsIFrame::Init()." ")"); do { MOZ_CrashSequence(__null, 2895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2896 MOZ_ASSERT(pageContentFrame->GetAbsoluteContainingBlock(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->GetAbsoluteContainingBlock())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->GetAbsoluteContainingBlock())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("pageContentFrame->GetAbsoluteContainingBlock()"
" (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2898
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2897 "nsIFrame::Init() should've constructed AbsoluteContainingBlock "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->GetAbsoluteContainingBlock())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->GetAbsoluteContainingBlock())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("pageContentFrame->GetAbsoluteContainingBlock()"
" (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2898
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2898 "for continuations!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pageContentFrame->GetAbsoluteContainingBlock())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pageContentFrame->GetAbsoluteContainingBlock())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("pageContentFrame->GetAbsoluteContainingBlock()"
" (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2898
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2899 }
2900 SetInitialSingleChild(pageFrame, pageContentFrame);
2901
2902 RefPtr<ComputedStyle> canvasPseudoStyle =
2903 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2904 PseudoStyleType::MozCanvas);
2905 aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2906
2907 nsIFrame* prevCanvasFrame = nullptr;
2908 if (prevPageContentFrame) {
2909 prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
2910 NS_ASSERTION(prevCanvasFrame, "missing canvas frame")do { if (!(prevCanvasFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "missing canvas frame", "prevCanvasFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2910); MOZ_PretendNoReturn(); } } while (0)
;
2911 }
2912 aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
2913 SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2914 return pageFrame;
2915}
2916
2917/* static */
2918nsIFrame* nsCSSFrameConstructor::CreatePlaceholderFrameFor(
2919 PresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame,
2920 nsContainerFrame* aParentFrame, nsIFrame* aPrevInFlow,
2921 nsFrameState aTypeBit) {
2922 RefPtr<ComputedStyle> placeholderStyle =
2923 aPresShell->StyleSet()->ResolveStyleForPlaceholder();
2924
2925 // The placeholder frame gets a pseudo style.
2926 nsPlaceholderFrame* placeholderFrame =
2927 NS_NewPlaceholderFrame(aPresShell, placeholderStyle, aTypeBit);
2928
2929 placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2930
2931 // Associate the placeholder/out-of-flow with each other.
2932 placeholderFrame->SetOutOfFlowFrame(aFrame);
2933 aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
2934
2935 aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2936
2937 return placeholderFrame;
2938}
2939
2940// Clears any lazy bits set in the range [aStartContent, aEndContent). If
2941// aEndContent is null, that means to clear bits in all siblings starting with
2942// aStartContent. aStartContent must not be null unless aEndContent is also
2943// null. We do this so that when new children are inserted under elements whose
2944// frame is a leaf the new children don't cause us to try to construct frames
2945// for the existing children again.
2946static inline void ClearLazyBits(nsIContent* aStartContent,
2947 nsIContent* aEndContent) {
2948 MOZ_ASSERT(aStartContent || !aEndContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartContent || !aEndContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartContent || !aEndContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStartContent || !aEndContent" " (" "Must have start child if we have an end child"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2949
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2949); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2949 "Must have start child if we have an end child")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartContent || !aEndContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartContent || !aEndContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aStartContent || !aEndContent" " (" "Must have start child if we have an end child"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 2949
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2949); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2950
2951 for (nsIContent* cur = aStartContent; cur != aEndContent;
2952 cur = cur->GetNextSibling()) {
2953 cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2954 }
2955}
2956
2957/* static */
2958const nsCSSFrameConstructor::FrameConstructionData*
2959nsCSSFrameConstructor::FindSelectData(const Element& aElement,
2960 ComputedStyle& aStyle) {
2961 // Construct a frame-based listbox or combobox
2962 const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
2963 MOZ_ASSERT(sel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sel)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(sel))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("sel", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sel" ")"); do
{ MOZ_CrashSequence(__null, 2963); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2964 switch (aStyle.StyleDisplay()->EffectiveAppearance()) {
2965 case StyleAppearance::Base:
2966 case StyleAppearance::BaseSelect:
2967 return nullptr;
2968 default:
2969 break;
2970 }
2971 if (sel->IsCombobox()) {
2972 static constexpr FrameConstructionData sComboboxData{
2973 ToCreationFunc(NS_NewComboboxControlFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewComboboxControlFrame(aPs, aStyle); }
};
2974 return &sComboboxData;
2975 }
2976 // FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
2977 // and reuse ConstructScrollableBlock or so?
2978 static constexpr FrameConstructionData sListBoxData{
2979 &nsCSSFrameConstructor::ConstructListBoxSelectFrame};
2980 return &sListBoxData;
2981}
2982
2983nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
2984 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2985 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2986 nsFrameList& aFrameList) {
2987 nsContainerFrame* listFrame =
2988 NS_NewListControlFrame(mPresShell, aItem.mComputedStyle);
2989 InitAndRestoreFrame(aState, aItem.mContent,
2990 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
2991 listFrame);
2992 ConstructScrollableBlockWithScrollContainer(
2993 aState, aItem, aParentFrame, aStyleDisplay, aFrameList, listFrame);
2994 return listFrame;
2995}
2996
2997nsIFrame* nsCSSFrameConstructor::ConstructTextControl(
2998 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2999 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3000 nsFrameList& aFrameList) {
3001 nsContainerFrame* tcf =
3002 NS_NewTextControlFrame(mPresShell, aItem.mComputedStyle);
3003 InitAndRestoreFrame(aState, aItem.mContent,
3004 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3005 tcf);
3006 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
3007 aStyleDisplay, aFrameList, tcf);
3008 return tcf;
3009}
3010
3011nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
3012 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3013 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3014 nsFrameList& aFrameList) {
3015 AutoRestore<bool> savedHasRenderedLegend(aState.mHasRenderedLegend);
3016 aState.mHasRenderedLegend = false;
3017 nsIContent* const content = aItem.mContent;
3018 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3019
3020 nsContainerFrame* fieldsetFrame =
3021 NS_NewFieldSetFrame(mPresShell, computedStyle);
3022
3023 // Initialize it
3024 InitAndRestoreFrame(aState, content,
3025 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3026 fieldsetFrame);
3027
3028 fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3029
3030 // Resolve style and initialize the frame
3031 RefPtr<ComputedStyle> fieldsetContentStyle =
3032 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3033 PseudoStyleType::MozFieldsetContent, computedStyle);
3034
3035 const nsStyleDisplay* fieldsetContentDisplay =
3036 fieldsetContentStyle->StyleDisplay();
3037 const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3038 nsContainerFrame* scrollFrame = nullptr;
3039 if (isScrollable) {
3040 fieldsetContentStyle =
3041 BeginBuildingScrollContainerFrame(aState, content, fieldsetContentStyle,
3042 fieldsetFrame, false, scrollFrame);
3043 }
3044
3045 // Create the inner ::-moz-fieldset-content frame.
3046 nsContainerFrame* contentFrameTop;
3047 nsContainerFrame* contentFrame;
3048 auto* parent = scrollFrame ? scrollFrame : fieldsetFrame;
3049 MOZ_ASSERT(fieldsetContentDisplay->DisplayOutside() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside
::Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside
::Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3050); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3050); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3050 StyleDisplayOutside::Block)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside
::Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside
::Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3050); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3050); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3051 switch (fieldsetContentDisplay->DisplayInside()) {
3052 case StyleDisplayInside::Flex:
3053 contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3054 InitAndRestoreFrame(aState, content, parent, contentFrame);
3055 contentFrameTop = contentFrame;
3056 break;
3057 case StyleDisplayInside::Grid:
3058 contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3059 InitAndRestoreFrame(aState, content, parent, contentFrame);
3060 contentFrameTop = contentFrame;
3061 break;
3062 default: {
3063 MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(fieldsetContentDisplay->mDisplay == StyleDisplay::
Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(fieldsetContentDisplay->mDisplay == StyleDisplay::
Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
" (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3064); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3064); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3064 "bug in StyleAdjuster::adjust_for_fieldset_content?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(fieldsetContentDisplay->mDisplay == StyleDisplay::
Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(fieldsetContentDisplay->mDisplay == StyleDisplay::
Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
" (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3064); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3064); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3065
3066 contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle);
3067 if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) {
3068 contentFrameTop = BeginBuildingColumns(
3069 aState, content, parent, contentFrame, fieldsetContentStyle);
3070 } else {
3071 // No need to create column container. Initialize content frame.
3072 InitAndRestoreFrame(aState, content, parent, contentFrame);
3073 contentFrameTop = contentFrame;
3074 }
3075
3076 break;
3077 }
3078 }
3079
3080 aState.AddChild(fieldsetFrame, aFrameList, content, aParentFrame);
3081
3082 // Process children
3083 nsFrameConstructorSaveState absoluteSaveState;
3084 nsFrameList childList;
3085
3086 contentFrameTop->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3087 if (fieldsetFrame->IsAbsPosContainingBlock()) {
3088 aState.PushAbsoluteContainingBlock(contentFrameTop, fieldsetFrame,
3089 absoluteSaveState);
3090 }
3091
3092 nsFrameConstructorSaveState floatSaveState;
3093 aState.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
3094
3095 ProcessChildren(aState, content, computedStyle, contentFrame, true, childList,
3096 true);
3097 nsFrameList fieldsetKids;
3098 fieldsetKids.AppendFrame(nullptr,
3099 scrollFrame ? scrollFrame : contentFrameTop);
3100
3101 if (!MayNeedToCreateColumnSpanSiblings(contentFrame, childList)) {
3102 // Set the inner frame's initial child lists.
3103 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3104 std::move(childList));
3105 } else {
3106 // Extract any initial non-column-span kids, and put them in inner frame's
3107 // child list.
3108 nsFrameList initialNonColumnSpanKids =
3109 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
3110 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3111 std::move(initialNonColumnSpanKids));
3112
3113 if (childList.NotEmpty()) {
3114 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
3115 aState, contentFrame, childList,
3116 // Column content should never be a absolute/fixed positioned
3117 // containing block. Pass nullptr as aPositionedFrame.
3118 nullptr);
3119 FinishBuildingColumns(aState, contentFrameTop, contentFrame,
3120 columnSpanSiblings);
3121 }
3122 }
3123
3124 if (isScrollable) {
3125 FinishBuildingScrollContainerFrame(scrollFrame, contentFrameTop);
3126 }
3127
3128 // We use AppendFrames here because the rendered legend will already
3129 // be present in the principal child list if it exists.
3130 fieldsetFrame->AppendFrames(FrameChildListID::NoReflowPrincipal,
3131 std::move(fieldsetKids));
3132
3133 return fieldsetFrame;
3134}
3135
3136const nsCSSFrameConstructor::FrameConstructionData*
3137nsCSSFrameConstructor::FindDetailsData(const Element& aElement,
3138 ComputedStyle& aStyle) {
3139 if (!StaticPrefs::layout_details_force_block_layout()) {
3140 return nullptr;
3141 }
3142 static constexpr FrameConstructionData sBlockData[2] = {
3143 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3144 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3145 };
3146 return &sBlockData[aStyle.StyleDisplay()->IsScrollableOverflow()];
3147}
3148
3149nsIFrame* nsCSSFrameConstructor::ConstructBlockRubyFrame(
3150 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3151 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3152 nsFrameList& aFrameList) {
3153 nsIContent* const content = aItem.mContent;
3154 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3155
3156 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, computedStyle);
3157 nsContainerFrame* newFrame = blockFrame;
3158 nsContainerFrame* geometricParent =
3159 aState.GetGeometricParent(*aStyleDisplay, aParentFrame);
3160 AutoFrameConstructionPageName pageNameTracker(aState, blockFrame);
3161 if ((aItem.mFCData->mBits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3162 aStyleDisplay->IsScrollableOverflow()) {
3163 nsContainerFrame* scrollframe = nullptr;
3164 BuildScrollContainerFrame(aState, content, computedStyle, blockFrame,
3165 geometricParent, scrollframe);
3166 newFrame = scrollframe;
3167 } else {
3168 InitAndRestoreFrame(aState, content, geometricParent, blockFrame);
3169 }
3170
3171 RefPtr<ComputedStyle> rubyStyle =
3172 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3173 PseudoStyleType::MozBlockRubyContent, computedStyle);
3174 nsContainerFrame* rubyFrame = NS_NewRubyFrame(mPresShell, rubyStyle);
3175 InitAndRestoreFrame(aState, content, blockFrame, rubyFrame);
3176 SetInitialSingleChild(blockFrame, rubyFrame);
3177 blockFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3178
3179 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
3180
3181 if (!mRootElementFrame) {
3182 mRootElementFrame = newFrame;
3183 }
3184
3185 nsFrameConstructorSaveState absoluteSaveState;
3186 blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3187 if (newFrame->IsAbsPosContainingBlock()) {
3188 aState.PushAbsoluteContainingBlock(blockFrame, blockFrame,
3189 absoluteSaveState);
3190 }
3191 nsFrameConstructorSaveState floatSaveState;
3192 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
3193
3194 nsFrameList childList;
3195 ProcessChildren(aState, content, rubyStyle, rubyFrame, true, childList, false,
3196 nullptr);
3197 rubyFrame->SetInitialChildList(FrameChildListID::Principal,
3198 std::move(childList));
3199
3200 return newFrame;
3201}
3202
3203static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
3204 for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3205 NS_ASSERTION(f->IsGeneratedContentFrame(),do { if (!(f->IsGeneratedContentFrame())) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "should not have exited generated content"
, "f->IsGeneratedContentFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3206); MOZ_PretendNoReturn(); } } while (0)
3206 "should not have exited generated content")do { if (!(f->IsGeneratedContentFrame())) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "should not have exited generated content"
, "f->IsGeneratedContentFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3206); MOZ_PretendNoReturn(); } } while (0)
;
3207 auto pseudo = f->Style()->GetPseudoType();
3208 if (pseudo == PseudoStyleType::Before || pseudo == PseudoStyleType::After ||
3209 pseudo == PseudoStyleType::Marker ||
3210 pseudo == PseudoStyleType::Backdrop ||
3211 pseudo == PseudoStyleType::Checkmark ||
3212 pseudo == PseudoStyleType::PickerIcon) {
3213 return f;
3214 }
3215 }
3216 return nullptr;
3217}
3218
3219/* static */
3220const nsCSSFrameConstructor::FrameConstructionData*
3221nsCSSFrameConstructor::FindTextData(const Text& aTextContent,
3222 nsIFrame* aParentFrame) {
3223 if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3224 if (!aParentFrame->IsInSVGTextSubtree()) {
3225 return nullptr;
3226 }
3227
3228 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
3229 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
3230 // really know how to deal with it. This kinda sucks. :(
3231 if (aParentFrame->GetContent() != aTextContent.GetParent()) {
3232 return nullptr;
3233 }
3234
3235 static constexpr FrameConstructionData sSVGTextData(
3236 NS_NewTextFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_SVG_TEXT0x80000);
3237 return &sSVGTextData;
3238 }
3239
3240 static constexpr FrameConstructionData sTextData(NS_NewTextFrame,
3241 FCDATA_IS_LINE_PARTICIPANT0x2000);
3242 return &sTextData;
3243}
3244
3245void nsCSSFrameConstructor::ConstructTextFrame(
3246 const FrameConstructionData* aData, nsFrameConstructorState& aState,
3247 nsIContent* aContent, nsContainerFrame* aParentFrame,
3248 ComputedStyle* aComputedStyle, nsFrameList& aFrameList) {
3249 MOZ_ASSERT(aData, "Must have frame construction data")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aData)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aData))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aData" " (" "Must have frame construction data"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 3249
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aData" ") (" "Must have frame construction data"
")"); do { MOZ_CrashSequence(__null, 3249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3250
3251 nsIFrame* newFrame =
3252 (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
3253
3254 InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3255
3256 if (newFrame->IsGeneratedContentFrame()) {
3257 UniquePtr<nsGenConInitializer> initializer(
3258 static_cast<nsGenConInitializer*>(
3259 aContent->TakeProperty(nsGkAtoms::genConInitializerProperty)));
3260 if (initializer) {
3261 // All generated text has an element as its parent.
3262 auto* element = aContent->GetParent()->AsElement();
3263 nsGenConList* list = nullptr;
3264 if (initializer->mCounterListName) {
3265 list = mContainStyleScopeManager.GetOrCreateCounterList(
3266 *element, initializer->mCounterListName);
3267 } else {
3268 list = mContainStyleScopeManager.QuoteListFor(*element);
3269 }
3270 if (initializer->mNode.release()->InitTextFrame(
3271 list, FindAncestorWithGeneratedContentPseudo(newFrame),
3272 newFrame)) {
3273 if (initializer->mCounterListName) {
3274 CountersDirty();
3275 } else {
3276 QuotesDirty();
3277 }
3278 }
3279 }
3280 }
3281
3282 // Add the newly constructed frame to the flow
3283 aFrameList.AppendFrame(nullptr, newFrame);
3284
3285 if (!aState.mCreatingExtraFrames || (aContent->IsInNativeAnonymousSubtree() &&
3286 !aContent->GetPrimaryFrame())) {
3287 aContent->SetPrimaryFrame(newFrame);
3288 }
3289}
3290
3291/* static */
3292const nsCSSFrameConstructor::FrameConstructionData*
3293nsCSSFrameConstructor::FindDataByInt(int32_t aInt, const Element& aElement,
3294 ComputedStyle& aComputedStyle,
3295 const FrameConstructionDataByInt* aDataPtr,
3296 uint32_t aDataLength) {
3297 for (const FrameConstructionDataByInt *curData = aDataPtr,
3298 *endData = aDataPtr + aDataLength;
3299 curData != endData; ++curData) {
3300 if (curData->mInt == aInt) {
3301 const FrameConstructionData* data = &curData->mData;
3302 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3303 return data->mFunc.mDataGetter(aElement, aComputedStyle);
3304 }
3305
3306 return data;
3307 }
3308 }
3309
3310 return nullptr;
3311}
3312
3313/* static */
3314const nsCSSFrameConstructor::FrameConstructionData*
3315nsCSSFrameConstructor::FindDataByTag(const Element& aElement,
3316 ComputedStyle& aStyle,
3317 const FrameConstructionDataByTag* aDataPtr,
3318 uint32_t aDataLength) {
3319 const nsAtom* tag = aElement.NodeInfo()->NameAtom();
3320 for (const FrameConstructionDataByTag *curData = aDataPtr,
3321 *endData = aDataPtr + aDataLength;
3322 curData != endData; ++curData) {
3323 if (curData->mTag == tag) {
3324 const FrameConstructionData* data = &curData->mData;
3325 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3326 return data->mFunc.mDataGetter(aElement, aStyle);
3327 }
3328
3329 return data;
3330 }
3331 }
3332
3333 return nullptr;
3334}
3335
3336#define SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40) FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME0x40)
3337#define SIMPLE_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3338 {int32_t(_int), FrameConstructionData(_func)}
3339#define SIMPLE_INT_CHAIN(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3340 {int32_t(_int), FrameConstructionData(_func)}
3341#define COMPLEX_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3342 {int32_t(_int), FrameConstructionData(_func)}
3343
3344#define SIMPLE_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3345 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3346#define SIMPLE_TAG_CHAIN(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3347 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3348#define COMPLEX_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3349 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3350
3351static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) {
3352 auto pseudo = aFrame->Style()->GetPseudoType();
3353 if (pseudo == PseudoStyleType::MozFieldsetContent ||
3354 pseudo == PseudoStyleType::MozScrolledContent ||
3355 pseudo == PseudoStyleType::MozColumnSet ||
3356 pseudo == PseudoStyleType::MozColumnContent) {
3357 return GetFieldSetFrameFor(aFrame->GetParent());
3358 }
3359 return do_QueryFrame(aFrame);
3360}
3361
3362/* static */
3363const nsCSSFrameConstructor::FrameConstructionData*
3364nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
3365 nsIFrame* aParentFrame,
3366 ComputedStyle& aStyle) {
3367 MOZ_ASSERT(aElement.IsHTMLElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement.IsHTMLElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement.IsHTMLElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aElement.IsHTMLElement()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3367); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsHTMLElement()" ")"); do { MOZ_CrashSequence
(__null, 3367); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3368 NS_ASSERTION(!aParentFrame ||do { if (!(!aParentFrame || aParentFrame->Style()->GetPseudoType
() != PseudoStyleType::MozFieldsetContent || aParentFrame->
GetParent()->IsFieldSetFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected parent for fieldset content anon box", "!aParentFrame || aParentFrame->Style()->GetPseudoType() != PseudoStyleType::MozFieldsetContent || aParentFrame->GetParent()->IsFieldSetFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3372); MOZ_PretendNoReturn
(); } } while (0)
3369 aParentFrame->Style()->GetPseudoType() !=do { if (!(!aParentFrame || aParentFrame->Style()->GetPseudoType
() != PseudoStyleType::MozFieldsetContent || aParentFrame->
GetParent()->IsFieldSetFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected parent for fieldset content anon box", "!aParentFrame || aParentFrame->Style()->GetPseudoType() != PseudoStyleType::MozFieldsetContent || aParentFrame->GetParent()->IsFieldSetFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3372); MOZ_PretendNoReturn
(); } } while (0)
3370 PseudoStyleType::MozFieldsetContent ||do { if (!(!aParentFrame || aParentFrame->Style()->GetPseudoType
() != PseudoStyleType::MozFieldsetContent || aParentFrame->
GetParent()->IsFieldSetFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected parent for fieldset content anon box", "!aParentFrame || aParentFrame->Style()->GetPseudoType() != PseudoStyleType::MozFieldsetContent || aParentFrame->GetParent()->IsFieldSetFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3372); MOZ_PretendNoReturn
(); } } while (0)
3371 aParentFrame->GetParent()->IsFieldSetFrame(),do { if (!(!aParentFrame || aParentFrame->Style()->GetPseudoType
() != PseudoStyleType::MozFieldsetContent || aParentFrame->
GetParent()->IsFieldSetFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected parent for fieldset content anon box", "!aParentFrame || aParentFrame->Style()->GetPseudoType() != PseudoStyleType::MozFieldsetContent || aParentFrame->GetParent()->IsFieldSetFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3372); MOZ_PretendNoReturn
(); } } while (0)
3372 "Unexpected parent for fieldset content anon box")do { if (!(!aParentFrame || aParentFrame->Style()->GetPseudoType
() != PseudoStyleType::MozFieldsetContent || aParentFrame->
GetParent()->IsFieldSetFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected parent for fieldset content anon box", "!aParentFrame || aParentFrame->Style()->GetPseudoType() != PseudoStyleType::MozFieldsetContent || aParentFrame->GetParent()->IsFieldSetFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3372); MOZ_PretendNoReturn
(); } } while (0)
;
3373
3374 switch (aStyle.GetPseudoType()) {
3375 case PseudoStyleType::ViewTransitionOld:
3376 case PseudoStyleType::ViewTransitionNew: {
3377 static constexpr FrameConstructionData sViewTransitionData(
3378 NS_NewImageFrameForViewTransition);
3379 return &sViewTransitionData;
3380 }
3381 case PseudoStyleType::MozSelectContent: {
3382 if (aParentFrame && aParentFrame->IsComboboxControlFrame()) {
3383 static constexpr FrameConstructionData sComboboxLabelData(
3384 NS_NewComboboxLabelFrame);
3385 return &sComboboxLabelData;
3386 }
3387 break;
3388 }
3389 case PseudoStyleType::MozFileContent: {
3390 if (aParentFrame && aParentFrame->IsFileControlFrame()) {
3391 static constexpr FrameConstructionData sFileLabelData(
3392 NS_NewFileControlLabelFrame);
3393 return &sFileLabelData;
3394 }
3395 break;
3396 }
3397 case PseudoStyleType::MozReveal:
3398 case PseudoStyleType::MozNumberSpinBox: {
3399 if (aParentFrame && aParentFrame->StyleDisplay()->EffectiveAppearance() ==
3400 StyleAppearance::Textfield) {
3401 // Suppress button-box pseudo-elements with appearance: textfield.
3402 static constexpr FrameConstructionData sSuppressData =
3403 SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
3404 return &sSuppressData;
3405 }
3406 break;
3407 }
3408 default:
3409 break;
3410 }
3411
3412 static constexpr FrameConstructionDataByTag sHTMLData[] = {
3413 SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData){nsGkAtoms::img, FrameConstructionData(nsCSSFrameConstructor::
FindImgData)}
,
3414 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,{nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
3415 nsCSSFrameConstructor::FindGeneratedImageData){nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
,
3416 {nsGkAtoms::br,
3417 {NS_NewBRFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_LINE_BREAK0x4000}},
3418 SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame){nsGkAtoms::wbr, FrameConstructionData(NS_NewWBRFrame)},
3419 SIMPLE_TAG_CHAIN(button, nsCSSFrameConstructor::FindHTMLButtonData){nsGkAtoms::button, FrameConstructionData(nsCSSFrameConstructor
::FindHTMLButtonData)}
,
3420 SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData){nsGkAtoms::input, FrameConstructionData(nsCSSFrameConstructor
::FindInputData)}
,
3421 SIMPLE_TAG_CREATE(textarea, &nsCSSFrameConstructor::ConstructTextControl){nsGkAtoms::textarea, FrameConstructionData(&nsCSSFrameConstructor
::ConstructTextControl)}
,
3422 SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData){nsGkAtoms::select, FrameConstructionData(nsCSSFrameConstructor
::FindSelectData)}
,
3423 SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::object, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3424 SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::embed, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3425 COMPLEX_TAG_CREATE(fieldset,{nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
3426 &nsCSSFrameConstructor::ConstructFieldSetFrame){nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
,
3427 SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame){nsGkAtoms::frameset, FrameConstructionData(NS_NewHTMLFramesetFrame
)}
,
3428 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3429 SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData){nsGkAtoms::canvas, FrameConstructionData(nsCSSFrameConstructor
::FindCanvasData)}
,
3430 SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame){nsGkAtoms::video, FrameConstructionData(NS_NewHTMLVideoFrame
)}
,
3431 SIMPLE_TAG_CREATE(audio, NS_NewHTMLAudioFrame){nsGkAtoms::audio, FrameConstructionData(NS_NewHTMLAudioFrame
)}
,
3432 SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame){nsGkAtoms::progress, FrameConstructionData(NS_NewProgressFrame
)}
,
3433 SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame){nsGkAtoms::meter, FrameConstructionData(NS_NewMeterFrame)},
3434 SIMPLE_TAG_CHAIN(details, nsCSSFrameConstructor::FindDetailsData){nsGkAtoms::details, FrameConstructionData(nsCSSFrameConstructor
::FindDetailsData)}
,
3435 SIMPLE_TAG_CHAIN(label,{nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
3436 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
3437 SIMPLE_TAG_CHAIN(area, SUPPRESS_FCDATA()){nsGkAtoms::area, FrameConstructionData(FrameConstructionData
(nullptr, 0x40))}
,
3438 };
3439
3440 return FindDataByTag(aElement, aStyle, sHTMLData, std::size(sHTMLData));
3441}
3442
3443/* static */
3444const nsCSSFrameConstructor::FrameConstructionData*
3445nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
3446 ComputedStyle&) {
3447 if (!aElement.IsInNativeAnonymousSubtree()) {
3448 return nullptr;
3449 }
3450
3451 auto& generatedContent = static_cast<const GeneratedImageContent&>(aElement);
3452 if (generatedContent.IsForListStyleImageMarker()) {
3453 static constexpr FrameConstructionData sImgData(
3454 NS_NewImageFrameForListStyleImage);
3455 return &sImgData;
3456 }
3457
3458 static constexpr FrameConstructionData sImgData(
3459 NS_NewImageFrameForGeneratedContentIndex);
3460 return &sImgData;
3461}
3462
3463const nsCSSFrameConstructor::FrameConstructionData*
3464nsCSSFrameConstructor::FindHTMLButtonData(const Element&,
3465 ComputedStyle& aStyle) {
3466 // Buttons force a (maybe inline) block unless their display is flex or grid.
3467 // TODO(emilio): It'd be good to remove this restriction more broadly.
3468 // There are some tests that expect block baselines on e.g. a `display: table`
3469 // button, but seems like it would be doable.
3470 const auto* disp = aStyle.StyleDisplay();
3471 const bool respectDisplay = [&] {
3472 if (disp->IsInlineFlow()) {
3473 // For compat, `display: inline` and co need to create an inline-block.
3474 return false;
3475 }
3476 switch (disp->DisplayInside()) {
3477 case StyleDisplayInside::Flex:
3478 case StyleDisplayInside::Grid:
3479 case StyleDisplayInside::FlowRoot:
3480 return true;
3481 default:
3482 return false;
3483 }
3484 }();
3485 if (respectDisplay) {
3486 return nullptr;
3487 }
3488 static constexpr FrameConstructionData sBlockData[2] = {
3489 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3490 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3491 };
3492 return &sBlockData[disp->IsScrollableOverflow()];
3493}
3494
3495/* static */
3496const nsCSSFrameConstructor::FrameConstructionData*
3497nsCSSFrameConstructor::FindImgData(const Element& aElement,
3498 ComputedStyle& aStyle) {
3499 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3500 nsImageFrame::ImageFrameType::ForElementRequest) {
3501 // content: url gets handled by the generic code-path.
3502 return nullptr;
3503 }
3504
3505 static constexpr FrameConstructionData sImgData(NS_NewImageFrame);
3506 return &sImgData;
3507}
3508
3509/* static */
3510const nsCSSFrameConstructor::FrameConstructionData*
3511nsCSSFrameConstructor::FindImgControlData(const Element& aElement,
3512 ComputedStyle& aStyle) {
3513 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3514 nsImageFrame::ImageFrameType::ForElementRequest) {
3515 return nullptr;
3516 }
3517
3518 static constexpr FrameConstructionData sImgControlData(
3519 NS_NewImageControlFrame);
3520 return &sImgControlData;
3521}
3522
3523/* static */
3524const nsCSSFrameConstructor::FrameConstructionData*
3525nsCSSFrameConstructor::FindInputData(const Element& aElement,
3526 ComputedStyle& aStyle) {
3527 static constexpr FrameConstructionDataByInt sInputData[] = {
3528 SIMPLE_INT_CREATE(FormControlType::InputCheckbox,{int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3529 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3530 SIMPLE_INT_CREATE(FormControlType::InputRadio,{int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3531 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3532 SIMPLE_INT_CREATE(FormControlType::InputFile, NS_NewFileControlFrame){int32_t(FormControlType::InputFile), FrameConstructionData(NS_NewFileControlFrame
)}
,
3533 SIMPLE_INT_CHAIN(FormControlType::InputImage,{int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
3534 nsCSSFrameConstructor::FindImgControlData){int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
,
3535 SIMPLE_INT_CREATE(FormControlType::InputEmail,{int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3536 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3537 SIMPLE_INT_CREATE(FormControlType::InputText,{int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3538 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3539 SIMPLE_INT_CREATE(FormControlType::InputTel,{int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3540 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3541 SIMPLE_INT_CREATE(FormControlType::InputUrl,{int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3542 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3543 SIMPLE_INT_CREATE(FormControlType::InputRange, NS_NewRangeFrame){int32_t(FormControlType::InputRange), FrameConstructionData(
NS_NewRangeFrame)}
,
3544 SIMPLE_INT_CREATE(FormControlType::InputPassword,{int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3545 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3546 SIMPLE_INT_CREATE(FormControlType::InputColor, NS_NewColorControlFrame){int32_t(FormControlType::InputColor), FrameConstructionData(
NS_NewColorControlFrame)}
,
3547 SIMPLE_INT_CREATE(FormControlType::InputSearch,{int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3548 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3549 SIMPLE_INT_CREATE(FormControlType::InputNumber,{int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3550 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3551 SIMPLE_INT_CREATE(FormControlType::InputTime, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputTime), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3552 SIMPLE_INT_CREATE(FormControlType::InputDate, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDate), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3553 SIMPLE_INT_CREATE(FormControlType::InputDatetimeLocal,{int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
3554 NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
,
3555 // TODO: this is temporary until a frame is written: bug 888320
3556 SIMPLE_INT_CREATE(FormControlType::InputMonth,{int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3557 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3558 // TODO: this is temporary until a frame is written: bug 888320
3559 SIMPLE_INT_CREATE(FormControlType::InputWeek,{int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3560 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3561 SIMPLE_INT_CREATE(FormControlType::InputSubmit,{int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3562 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3563 SIMPLE_INT_CREATE(FormControlType::InputReset,{int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
3564 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
,
3565 SIMPLE_INT_CREATE(FormControlType::InputButton,{int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3566 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3567 // Keeping hidden inputs out of here on purpose for so they get frames by
3568 // display (in practice, none).
3569 };
3570
3571 auto controlType = HTMLInputElement::FromNode(aElement)->ControlType();
3572
3573 // radio and checkbox inputs with appearance:none should be constructed
3574 // by display type. (Note that we're not checking that appearance is
3575 // not (respectively) StyleAppearance::Radio and StyleAppearance::Checkbox.)
3576 if ((controlType == FormControlType::InputCheckbox ||
3577 controlType == FormControlType::InputRadio) &&
3578 !aStyle.StyleDisplay()->HasNativeAppearance()) {
3579 return nullptr;
3580 }
3581
3582 return FindDataByInt(int32_t(controlType), aElement, aStyle, sInputData,
3583 std::size(sInputData));
3584}
3585
3586/* static */
3587const nsCSSFrameConstructor::FrameConstructionData*
3588nsCSSFrameConstructor::FindObjectData(const Element& aElement,
3589 ComputedStyle& aStyle) {
3590 uint32_t type;
3591 nsCOMPtr<nsIObjectLoadingContent> objContent =
3592 do_QueryInterface(const_cast<Element*>(&aElement));
3593 NS_ASSERTION(objContent,do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3595); MOZ_PretendNoReturn(); } } while (0)
3594 "embed and object must implement "do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3595); MOZ_PretendNoReturn(); } } while (0)
3595 "nsIObjectLoadingContent!")do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3595); MOZ_PretendNoReturn(); } } while (0)
;
3596 objContent->GetDisplayedType(&type);
3597
3598 static constexpr FrameConstructionDataByInt sObjectData[] = {
3599 // TODO(emilio): Can we remove the NS_NewEmptyFrame case and just use a
3600 // subdocument frame here?
3601 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,{int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
3602 NS_NewEmptyFrame){int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
,
3603 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,{int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
3604 NS_NewSubDocumentFrame){int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
,
3605 // Nothing for TYPE_FALLBACK so we'll construct frames by display there
3606 };
3607
3608 return FindDataByInt((int32_t)type, aElement, aStyle, sObjectData,
3609 std::size(sObjectData));
3610}
3611
3612/* static */
3613const nsCSSFrameConstructor::FrameConstructionData*
3614nsCSSFrameConstructor::FindCanvasData(const Element& aElement,
3615 ComputedStyle& aStyle) {
3616 // We want to check whether script is enabled on the document that
3617 // could be painting to the canvas. That's the owner document of
3618 // the canvas, except when the owner document is a static document,
3619 // in which case it's the original document it was cloned from.
3620 Document* doc = aElement.OwnerDoc();
3621 if (doc->IsStaticDocument()) {
3622 doc = doc->GetOriginalDocument();
3623 }
3624 if (!doc->IsScriptEnabled()) {
3625 return nullptr;
3626 }
3627
3628 static constexpr FrameConstructionData sCanvasData(
3629 NS_NewHTMLCanvasFrame, 0, PseudoStyleType::MozHtmlCanvasContent);
3630 return &sCanvasData;
3631}
3632
3633static MOZ_NEVER_INLINE__attribute__((noinline)) void DestroyFramesInList(PresShell* aPs,
3634 nsFrameList& aList) {
3635 nsIFrame::DestroyContext context(aPs);
3636 aList.DestroyFrames(context);
3637}
3638
3639void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
3640 FrameConstructionItem& aItem, nsFrameConstructorState& aState,
3641 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
3642 const FrameConstructionData* data = aItem.mFCData;
3643 NS_ASSERTION(data, "Must have frame construction data")do { if (!(data)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have frame construction data"
, "data", "./../../../layout/base/nsCSSFrameConstructor.cpp",
3643); MOZ_PretendNoReturn(); } } while (0)
;
3644
3645 uint32_t bits = data->mBits;
3646
3647 NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),do { if (!(!(bits & 0x2))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should have dealt with this inside the data finder", "!(bits & FCDATA_FUNC_IS_DATA_GETTER)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3648); MOZ_PretendNoReturn
(); } } while (0)
3648 "Should have dealt with this inside the data finder")do { if (!(!(bits & 0x2))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should have dealt with this inside the data finder", "!(bits & FCDATA_FUNC_IS_DATA_GETTER)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3648); MOZ_PretendNoReturn
(); } } while (0)
;
3649
3650 // Some sets of bits are not compatible with each other
3651#define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3652 NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \do { if (!(!(bits & _bit1) || !(bits & _bit2))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Only one of these bits should be set", "!(bits & _bit1) || !(bits & _bit2)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3653); MOZ_PretendNoReturn
(); } } while (0)
3653 "Only one of these bits should be set")do { if (!(!(bits & _bit1) || !(bits & _bit2))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Only one of these bits should be set", "!(bits & _bit1) || !(bits & _bit2)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3653); MOZ_PretendNoReturn
(); } } while (0)
3654 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3655 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10);
3656 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
3657 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_SKIP_ABSPOS_PUSH0x200);
3658 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3659 FCDATA_DISALLOW_GENERATED_CONTENT0x400);
3660 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_ALLOW_BLOCK_STYLES0x8000);
3661 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3662 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3663 CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS0x20,
3664 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3665#undef CHECK_ONLY_ONE_BIT
3666 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(bits & 0x400000) || (bits & 0x10000))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(bits & 0x400000) || (bits & 0x10000)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!(bits & 0x400000) || (bits & 0x10000)"
" (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 3668
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3668); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3667 !(bits & FCDATA_IS_WRAPPER_ANON_BOX) || (bits & FCDATA_USE_CHILD_ITEMS),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(bits & 0x400000) || (bits & 0x10000))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(bits & 0x400000) || (bits & 0x10000)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!(bits & 0x400000) || (bits & 0x10000)"
" (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 3668
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3668); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3668 "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(bits & 0x400000) || (bits & 0x10000))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(bits & 0x400000) || (bits & 0x10000)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!(bits & 0x400000) || (bits & 0x10000)"
" (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 3668
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3668); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3669
3670 // Don't create a subdocument frame for iframes if we're creating extra frames
3671 if (aState.mCreatingExtraFrames &&
3672 aItem.mContent->IsHTMLElement(nsGkAtoms::iframe)) {
3673 return;
3674 }
3675
3676 nsIContent* const content = aItem.mContent;
3677 nsIFrame* newFrame;
3678 nsIFrame* primaryFrame;
3679 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3680 const nsStyleDisplay* display = computedStyle->StyleDisplay();
3681 if (bits & FCDATA_FUNC_IS_FULL_CTOR0x4) {
3682 newFrame = (this->*(data->mFunc.mFullConstructor))(
3683 aState, aItem, aParentFrame, display, aFrameList);
3684 MOZ_ASSERT(newFrame, "Full constructor failed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("newFrame" " (" "Full constructor failed"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 3684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ") (" "Full constructor failed"
")"); do { MOZ_CrashSequence(__null, 3684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3685 primaryFrame = newFrame;
3686 } else {
3687 newFrame = (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
3688
3689 const bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8);
3690 nsContainerFrame* geometricParent =
3691 allowOutOfFlow ? aState.GetGeometricParent(*display, aParentFrame)
3692 : aParentFrame;
3693
3694 // In the non-scrollframe case, primaryFrame and newFrame are equal; in the
3695 // scrollframe case, newFrame is the scrolled frame while primaryFrame is
3696 // the scrollframe.
3697 if ((bits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3698 display->IsScrollableOverflow()) {
3699 nsContainerFrame* scrollframe = nullptr;
3700 BuildScrollContainerFrame(aState, content, computedStyle, newFrame,
3701 geometricParent, scrollframe);
3702 primaryFrame = scrollframe;
3703 } else {
3704 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3705 primaryFrame = newFrame;
3706 }
3707
3708 // If we need to create a block formatting context to wrap our
3709 // kids, do it now.
3710 nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3711 nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3712 nsIFrame* possiblyLeafFrame = newFrame;
3713 nsContainerFrame* outerFrame = nullptr;
3714 if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000) {
3715 RefPtr<ComputedStyle> outerStyle =
3716 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3717 data->mAnonBoxPseudo, computedStyle);
3718#ifdef DEBUG1
3719 nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3720 MOZ_ASSERT(containerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(containerFrame))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("containerFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3720); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "containerFrame" ")"); do { MOZ_CrashSequence
(__null, 3720); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3721#endif
3722 nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3723 nsContainerFrame* innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
3724 InitAndRestoreFrame(aState, content, container, innerFrame);
3725 outerFrame = innerFrame;
3726
3727 SetInitialSingleChild(container, outerFrame);
3728
3729 container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3730
3731 // Now figure out whether newFrame or outerFrame should be the
3732 // absolute container.
3733 if (outerFrame->IsAbsPosContainingBlock()) {
3734 maybeAbsoluteContainingBlock = outerFrame;
3735 maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3736 innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3737 }
3738
3739 // Our kids should go into the innerFrame.
3740 newFrame = innerFrame;
3741 }
3742
3743 aState.AddChild(primaryFrame, aFrameList, content, aParentFrame,
3744 allowOutOfFlow, allowOutOfFlow);
3745
3746 nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3747 if (newFrameAsContainer) {
3748 // Process the child content if requested
3749 nsFrameList childList;
3750 nsFrameConstructorSaveState absoluteSaveState;
3751
3752 if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10) {
3753 aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3754 } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH0x200)) {
3755 maybeAbsoluteContainingBlock->AddStateBits(
3756 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3757 if (maybeAbsoluteContainingBlockStyleFrame->IsAbsPosContainingBlock()) {
3758 auto* cf =
3759 static_cast<nsContainerFrame*>(maybeAbsoluteContainingBlock);
3760 aState.PushAbsoluteContainingBlock(
3761 cf, maybeAbsoluteContainingBlockStyleFrame, absoluteSaveState);
3762 }
3763 }
3764
3765 nsFrameConstructorSaveState floatSaveState;
3766 aState.MaybePushFloatContainingBlock(newFrameAsContainer, floatSaveState);
3767
3768 if (bits & FCDATA_USE_CHILD_ITEMS0x10000) {
3769 // At this point, we have not set up the auto value for this frame, and
3770 // no caller will have set it so it is not redundant and therefor will
3771 // not assert.
3772 AutoFrameConstructionPageName pageNameTracker(aState,
3773 newFrameAsContainer);
3774 ConstructFramesFromItemList(
3775 aState, aItem.mChildItems, newFrameAsContainer,
3776 bits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
3777 } else {
3778 // Process the child frames.
3779 ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
3780 !(bits & FCDATA_DISALLOW_GENERATED_CONTENT0x400), childList,
3781 (bits & FCDATA_ALLOW_BLOCK_STYLES0x8000) != 0,
3782 possiblyLeafFrame);
3783 }
3784
3785 if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS0x20) {
3786 nsFrameList newList;
3787 nsFrameList currentBlockList;
3788 nsIFrame* f;
3789 while ((f = childList.FirstChild()) != nullptr) {
3790 bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
3791 if (!wrapFrame) {
3792 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3793 currentBlockList, newList);
3794 }
3795
3796 childList.RemoveFrame(f);
3797 if (wrapFrame) {
3798 currentBlockList.AppendFrame(nullptr, f);
3799 } else {
3800 newList.AppendFrame(nullptr, f);
3801 }
3802 }
3803 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3804 currentBlockList, newList);
3805
3806 if (childList.NotEmpty()) {
3807 // an error must have occurred, delete unprocessed frames
3808 DestroyFramesInList(mPresShell, childList);
3809 }
3810
3811 childList = std::move(newList);
3812 }
3813
3814 // Set the frame's initial child list. Note that MathML depends on this
3815 // being called even if childList is empty!
3816 newFrameAsContainer->SetInitialChildList(FrameChildListID::Principal,
3817 std::move(childList));
3818 }
3819 }
3820
3821 NS_ASSERTION(newFrame->IsLineParticipant() ==do { if (!(newFrame->IsLineParticipant() == ((bits & 0x2000
) != 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits"
, "newFrame->IsLineParticipant() == ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3823); MOZ_PretendNoReturn
(); } } while (0)
3822 ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),do { if (!(newFrame->IsLineParticipant() == ((bits & 0x2000
) != 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits"
, "newFrame->IsLineParticipant() == ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3823); MOZ_PretendNoReturn
(); } } while (0)
3823 "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits")do { if (!(newFrame->IsLineParticipant() == ((bits & 0x2000
) != 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits"
, "newFrame->IsLineParticipant() == ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3823); MOZ_PretendNoReturn
(); } } while (0)
;
3824
3825 // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
3826 // generated content that doesn't have one yet. Note that we have to examine
3827 // the frame bit, because by this point mIsGeneratedContent has been cleared
3828 // on aItem.
3829 if ((!aState.mCreatingExtraFrames ||
3830 (aItem.mContent->IsRootOfNativeAnonymousSubtree() &&
3831 !aItem.mContent->GetPrimaryFrame())) &&
3832 !(bits & FCDATA_SKIP_FRAMESET0x1)) {
3833 aItem.mContent->SetPrimaryFrame(primaryFrame);
3834 ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
3835 }
3836}
3837
3838static void GatherSubtreeElements(Element* aElement,
3839 nsTArray<Element*>& aElements) {
3840 aElements.AppendElement(aElement);
3841 StyleChildrenIterator iter(aElement);
3842 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
3843 if (!c->IsElement()) {
3844 continue;
3845 }
3846 GatherSubtreeElements(c->AsElement(), aElements);
3847 }
3848}
3849
3850nsresult nsCSSFrameConstructor::GetAnonymousContent(
3851 nsIContent* aParent, nsIFrame* aParentFrame,
3852 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
3853 nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3854 if (!creator) {
3855 return NS_OK;
3856 }
3857
3858 nsresult rv = creator->CreateAnonymousContent(aContent);
3859 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3860 // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
3861 return rv;
3862 }
3863
3864 if (aContent.IsEmpty()) {
3865 return NS_OK;
3866 }
3867
3868 const bool devtoolsEventsEnabled =
3869 mDocument->DevToolsAnonymousAndShadowEventsEnabled();
3870
3871 MOZ_ASSERT(aParent->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->IsElement()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aParent->IsElement()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3871); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aParent->IsElement()" ")"); do { MOZ_CrashSequence
(__null, 3871); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3872 for (const auto& info : aContent) {
3873 // get our child's content and set its parent to our content
3874 nsIContent* content = info.mContent;
3875 content->SetIsNativeAnonymousRoot();
3876
3877 BindContext context(*aParent->AsElement(), BindContext::ForNativeAnonymous);
3878 rv = content->BindToTree(context, *aParent);
3879
3880 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3881 content->UnbindFromTree();
3882 return rv;
3883 }
3884
3885 if (devtoolsEventsEnabled) {
3886 content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
3887 }
3888 }
3889
3890 // Some situations where we don't cache anonymous content styles:
3891 //
3892 // * when visibility or pointer-events is anything other than the initial
3893 // value; we rely on visibility and pointer-events inheriting into anonymous
3894 // content, but don't bother adding this state to the AnonymousContentKey,
3895 // since it's not so common. Note that with overlay scrollbars, scrollbars
3896 // always start off with pointer-events: none so we don't need to check for
3897 // that in that case.
3898 //
3899 // * when the medium is anything other than screen; some UA style sheet rules
3900 // apply in e.g. print medium, and will give different results from the
3901 // cached styles
3902 Maybe<bool> computedAllowStyleCaching;
3903 auto ComputeAllowStyleCaching = [&] {
3904 if (!StaticPrefs::layout_css_cached_scrollbar_styles_enabled()) {
3905 return false;
3906 }
3907 if (aParentFrame->StyleVisibility()->mVisible != StyleVisibility::Visible) {
3908 return false;
3909 }
3910 nsPresContext* pc = mPresShell->GetPresContext();
3911 if (!pc->UseOverlayScrollbars() &&
3912 aParentFrame->StyleUI()->ComputedPointerEvents() !=
3913 StylePointerEvents::Auto) {
3914 return false;
3915 }
3916 if (pc->Medium() != nsGkAtoms::screen) {
3917 return false;
3918 }
3919 return true;
3920 };
3921
3922 auto AllowStyleCaching = [&] {
3923 if (computedAllowStyleCaching.isNothing()) {
3924 computedAllowStyleCaching.emplace(ComputeAllowStyleCaching());
3925 }
3926 return computedAllowStyleCaching.value();
3927 };
3928
3929 // Compute styles for the anonymous content tree.
3930 ServoStyleSet* styleSet = mPresShell->StyleSet();
3931 for (auto& info : aContent) {
3932 Element* e = Element::FromNode(info.mContent);
3933 if (!e) {
3934 continue;
3935 }
3936
3937 if (info.mKey == AnonymousContentKey::None || !AllowStyleCaching()) {
3938 // Most NAC subtrees do not use caching of computed styles. Just go
3939 // ahead and eagerly style the subtree.
3940 styleSet->StyleNewSubtree(e);
3941 continue;
3942 }
3943
3944 // We have a NAC subtree for which we can use cached styles.
3945 AutoTArray<RefPtr<ComputedStyle>, 2> cachedStyles;
3946 AutoTArray<Element*, 2> elements;
3947
3948 GatherSubtreeElements(e, elements);
3949 styleSet->GetCachedAnonymousContentStyles(info.mKey, cachedStyles);
3950
3951 if (cachedStyles.IsEmpty()) {
3952 // We haven't stored cached styles for this kind of NAC subtree yet.
3953 // Eagerly compute those styles, then cache them for later.
3954 styleSet->StyleNewSubtree(e);
3955 for (Element* e : elements) {
3956 if (e->HasServoData()) {
3957 cachedStyles.AppendElement(ServoStyleSet::ResolveServoStyle(*e));
3958 } else {
3959 cachedStyles.AppendElement(nullptr);
3960 }
3961 }
3962 styleSet->PutCachedAnonymousContentStyles(info.mKey,
3963 std::move(cachedStyles));
3964 continue;
3965 }
3966
3967 // We previously stored cached styles for this kind of NAC subtree.
3968 // Iterate over them and set them on the subtree's elements.
3969 MOZ_ASSERT(cachedStyles.Length() == elements.Length(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles.Length() == elements.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(cachedStyles.Length() == elements.Length()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("cachedStyles.Length() == elements.Length()"
" (" "should always produce the same size NAC subtree" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3970); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3970); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3970 "should always produce the same size NAC subtree")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles.Length() == elements.Length())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(cachedStyles.Length() == elements.Length()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("cachedStyles.Length() == elements.Length()"
" (" "should always produce the same size NAC subtree" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3970); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3970); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3971 for (size_t i = 0, len = cachedStyles.Length(); i != len; ++i) {
3972 if (cachedStyles[i]) {
3973#ifdef DEBUG1
3974 // Assert that our cached style is the same as one we could compute.
3975 RefPtr<ComputedStyle> cs = styleSet->ResolveStyleLazily(*elements[i]);
3976 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
" (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3979); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3977 cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
" (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3979); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3978 "cached anonymous content styles should be identical to those we "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
" (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3979); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3979 "would compute normally")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(cachedStyles[i]->EqualForCachedAnonymousContentStyle
(*cs)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
" (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3979); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3980 // All overlay scrollbars start off as inactive, so we can rely on their
3981 // pointer-events value being always none.
3982 MOZ_ASSERT(!mPresShell->GetPresContext()->UseOverlayScrollbars() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3984); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3984); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3983 cs->StyleUI()->ComputedPointerEvents() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3984); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3984); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3984 StylePointerEvents::None)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mPresShell->GetPresContext()->UseOverlayScrollbars
() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents
::None))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3984); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3984); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3985#endif
3986 Servo_SetExplicitStyle(elements[i], cachedStyles[i]);
3987 }
3988 }
3989 }
3990
3991 return NS_OK;
3992}
3993
3994/* static */
3995const nsCSSFrameConstructor::FrameConstructionData*
3996nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
3997 ComputedStyle& aStyle) {
3998 MOZ_ASSERT(aElement.IsXULElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement.IsXULElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement.IsXULElement()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aElement.IsXULElement()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 3998); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsXULElement()" ")"); do { MOZ_CrashSequence
(__null, 3998); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3999 static constexpr FrameConstructionData kPopupData(NS_NewMenuPopupFrame);
4000
4001 static constexpr FrameConstructionDataByTag sXULTagData[] = {
4002 SIMPLE_TAG_CREATE(image, NS_NewXULImageFrame){nsGkAtoms::image, FrameConstructionData(NS_NewXULImageFrame)
}
,
4003 SIMPLE_TAG_CREATE(treechildren, NS_NewTreeBodyFrame){nsGkAtoms::treechildren, FrameConstructionData(NS_NewTreeBodyFrame
)}
,
4004 SIMPLE_TAG_CHAIN(label,{nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
4005 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
4006 SIMPLE_TAG_CHAIN(description,{nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
4007 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
4008 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4009 SIMPLE_TAG_CREATE(editor, NS_NewSubDocumentFrame){nsGkAtoms::editor, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4010 SIMPLE_TAG_CREATE(browser, NS_NewSubDocumentFrame){nsGkAtoms::browser, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4011 SIMPLE_TAG_CREATE(splitter, NS_NewSplitterFrame){nsGkAtoms::splitter, FrameConstructionData(NS_NewSplitterFrame
)}
,
4012 SIMPLE_TAG_CREATE(scrollbar, NS_NewScrollbarFrame){nsGkAtoms::scrollbar, FrameConstructionData(NS_NewScrollbarFrame
)}
,
4013 SIMPLE_TAG_CREATE(slider, NS_NewSliderFrame){nsGkAtoms::slider, FrameConstructionData(NS_NewSliderFrame)},
4014 SIMPLE_TAG_CREATE(thumb, NS_NewSimpleXULLeafFrame){nsGkAtoms::thumb, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4015 SIMPLE_TAG_CREATE(scrollcorner, NS_NewSimpleXULLeafFrame){nsGkAtoms::scrollcorner, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4016 SIMPLE_TAG_CREATE(resizer, NS_NewSimpleXULLeafFrame){nsGkAtoms::resizer, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4017 SIMPLE_TAG_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame){nsGkAtoms::scrollbarbutton, FrameConstructionData(NS_NewScrollbarButtonFrame
)}
,
4018 {nsGkAtoms::panel, kPopupData},
4019 {nsGkAtoms::menupopup, kPopupData},
4020 {nsGkAtoms::tooltip, kPopupData},
4021 };
4022
4023 return FindDataByTag(aElement, aStyle, sXULTagData, std::size(sXULTagData));
4024}
4025
4026/* static */
4027const nsCSSFrameConstructor::FrameConstructionData*
4028nsCSSFrameConstructor::FindLabelOrDescriptionData(const Element& aElement,
4029 ComputedStyle&) {
4030 if (!aElement.OwnerDoc()->ChromeRulesEnabled()) {
4031 return nullptr;
4032 }
4033
4034 // Follow CSS display value if no value attribute
4035 if (!aElement.HasAttr(nsGkAtoms::value)) {
4036 return nullptr;
4037 }
4038
4039 // Follow CSS display if there's no crop="center".
4040 if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::crop,
4041 nsGkAtoms::center, eCaseMatters)) {
4042 return nullptr;
4043 }
4044
4045 static constexpr FrameConstructionData sMiddleCroppingData(
4046 NS_NewMiddleCroppingLabelFrame);
4047 return &sMiddleCroppingData;
4048}
4049
4050already_AddRefed<ComputedStyle>
4051nsCSSFrameConstructor::BeginBuildingScrollContainerFrame(
4052 nsFrameConstructorState& aState, nsIContent* aContent,
4053 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame, bool aIsRoot,
4054 nsContainerFrame*& aNewFrame) {
4055 nsContainerFrame* scrollContainerFrame = aNewFrame;
4056
4057 if (!scrollContainerFrame) {
4058 scrollContainerFrame =
4059 NS_NewScrollContainerFrame(mPresShell, aContentStyle, aIsRoot);
4060 InitAndRestoreFrame(aState, aContent, aParentFrame, scrollContainerFrame);
4061 }
4062
4063 MOZ_ASSERT(scrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(scrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(scrollContainerFrame))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("scrollContainerFrame"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4063); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "scrollContainerFrame" ")"); do { MOZ_CrashSequence
(__null, 4063); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4064
4065 // if there are any anonymous children for the scroll frame, create
4066 // frames for them.
4067 //
4068 // We can't take the normal ProcessChildren path, because the NAC needs to
4069 // be parented to the scrollframe, and everything else needs to be parented
4070 // to the scrolledframe.
4071 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4072 DebugOnly<nsresult> rv =
4073 GetAnonymousContent(aContent, scrollContainerFrame, scrollNAC);
4074 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4074); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4075 nsFrameList anonymousList;
4076 if (!scrollNAC.IsEmpty()) {
4077 nsFrameConstructorSaveState floatSaveState;
4078 aState.MaybePushFloatContainingBlock(scrollContainerFrame, floatSaveState);
4079
4080 AutoFrameConstructionItemList items(this);
4081 AutoFrameConstructionPageName pageNameTracker(aState, scrollContainerFrame);
4082 AddFCItemsForAnonymousContent(aState, scrollContainerFrame, scrollNAC,
4083 items, pageNameTracker);
4084 ConstructFramesFromItemList(aState, items, scrollContainerFrame,
4085 /* aParentIsWrapperAnonBox = */ false,
4086 anonymousList);
4087 }
4088
4089 aNewFrame = scrollContainerFrame;
4090 scrollContainerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4091
4092 // we used the style that was passed in. So resolve another one.
4093 ServoStyleSet* styleSet = mPresShell->StyleSet();
4094 RefPtr<ComputedStyle> scrolledChildStyle =
4095 styleSet->ResolveInheritingAnonymousBoxStyle(
4096 PseudoStyleType::MozScrolledContent, aContentStyle);
4097
4098 scrollContainerFrame->SetInitialChildList(FrameChildListID::Principal,
4099 std::move(anonymousList));
4100
4101 return scrolledChildStyle.forget();
4102}
4103
4104void nsCSSFrameConstructor::FinishBuildingScrollContainerFrame(
4105 nsContainerFrame* aScrollContainerFrame, nsIFrame* aScrolledFrame) {
4106 aScrollContainerFrame->AppendFrames(
4107 FrameChildListID::Principal, nsFrameList(aScrolledFrame, aScrolledFrame));
4108}
4109
4110void nsCSSFrameConstructor::BuildScrollContainerFrame(
4111 nsFrameConstructorState& aState, nsIContent* aContent,
4112 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
4113 nsContainerFrame* aParentFrame, nsContainerFrame*& aNewFrame) {
4114 RefPtr<ComputedStyle> scrolledContentStyle =
4115 BeginBuildingScrollContainerFrame(aState, aContent, aContentStyle,
4116 aParentFrame, false, aNewFrame);
4117
4118 aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
4119 InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4120
4121 FinishBuildingScrollContainerFrame(aNewFrame, aScrolledFrame);
4122}
4123
4124const nsCSSFrameConstructor::FrameConstructionData*
4125nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
4126 const Element& aElement) {
4127 static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET28)),
4128 "Check eParentTypeCount should not overflow");
4129
4130 // The style system ensures that floated and positioned frames are
4131 // block-level.
4132 NS_ASSERTION(do { if (!(!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle
()) || aDisplay.IsBlockOutsideStyle())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Style system did not apply CSS2.1 section 9.7 fixups", "!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) || aDisplay.IsBlockOutsideStyle()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4135); MOZ_PretendNoReturn
(); } } while (0)
4133 !(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) ||do { if (!(!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle
()) || aDisplay.IsBlockOutsideStyle())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Style system did not apply CSS2.1 section 9.7 fixups", "!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) || aDisplay.IsBlockOutsideStyle()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4135); MOZ_PretendNoReturn
(); } } while (0)
4134 aDisplay.IsBlockOutsideStyle(),do { if (!(!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle
()) || aDisplay.IsBlockOutsideStyle())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Style system did not apply CSS2.1 section 9.7 fixups", "!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) || aDisplay.IsBlockOutsideStyle()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4135); MOZ_PretendNoReturn
(); } } while (0)
4135 "Style system did not apply CSS2.1 section 9.7 fixups")do { if (!(!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle
()) || aDisplay.IsBlockOutsideStyle())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Style system did not apply CSS2.1 section 9.7 fixups", "!(aDisplay.IsFloatingStyle() || aDisplay.IsAbsolutelyPositionedStyle()) || aDisplay.IsBlockOutsideStyle()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4135); MOZ_PretendNoReturn
(); } } while (0)
;
4136
4137 // If this is "body", try propagating its scroll style to the viewport
4138 // Note that we need to do this even if the body is NOT scrollable;
4139 // it might have dynamically changed from scrollable to not scrollable,
4140 // and that might need to be propagated.
4141 // XXXbz is this the right place to do this? If this code moves,
4142 // make this function static.
4143 bool propagatedScrollToViewport = false;
4144 if (aElement.IsHTMLElement(nsGkAtoms::body)) {
4145 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4146 propagatedScrollToViewport =
4147 presContext->UpdateViewportScrollStylesOverride() == &aElement;
4148 MOZ_ASSERT(!propagatedScrollToViewport ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!propagatedScrollToViewport || !mPresShell->GetPresContext
()->IsPaginated())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!propagatedScrollToViewport ||
!mPresShell->GetPresContext()->IsPaginated()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
" (" "Shouldn't propagate scroll in paginated contexts" ")",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 4150); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4149 !mPresShell->GetPresContext()->IsPaginated(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!propagatedScrollToViewport || !mPresShell->GetPresContext
()->IsPaginated())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!propagatedScrollToViewport ||
!mPresShell->GetPresContext()->IsPaginated()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
" (" "Shouldn't propagate scroll in paginated contexts" ")",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 4150); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4150 "Shouldn't propagate scroll in paginated contexts")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!propagatedScrollToViewport || !mPresShell->GetPresContext
()->IsPaginated())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!propagatedScrollToViewport ||
!mPresShell->GetPresContext()->IsPaginated()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
" (" "Shouldn't propagate scroll in paginated contexts" ")",
"./../../../layout/base/nsCSSFrameConstructor.cpp", 4150); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4150); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4151 }
4152 }
4153
4154 switch (aDisplay.DisplayInside()) {
4155 case StyleDisplayInside::Flow:
4156 case StyleDisplayInside::FlowRoot: {
4157 if (aDisplay.IsInlineFlow()) {
4158 static constexpr FrameConstructionData data(
4159 &nsCSSFrameConstructor::ConstructInline,
4160 FCDATA_IS_INLINE0x1000 | FCDATA_IS_LINE_PARTICIPANT0x2000);
4161 return &data;
4162 }
4163
4164 // If the frame is a block-level frame and is scrollable, then wrap it in
4165 // a scroll frame. Except we don't want to do that for paginated contexts
4166 // for frames that are block-outside and aren't frames for native
4167 // anonymous stuff.
4168 // XXX Ignore tables for the time being (except caption)
4169 const uint32_t kCaptionCtorFlags =
4170 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28);
4171 const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
4172 const bool needScrollFrame =
4173 aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport;
4174 if (needScrollFrame) {
4175 const bool suppressScrollFrame =
4176 mPresShell->GetPresContext()->IsPaginated() &&
4177 aDisplay.IsBlockOutsideStyle() &&
4178 !aElement.IsInNativeAnonymousSubtree();
4179 if (!suppressScrollFrame) {
4180 static constexpr FrameConstructionData sScrollableBlockData[2] = {
4181 {&nsCSSFrameConstructor::ConstructScrollableBlock},
4182 {&nsCSSFrameConstructor::ConstructScrollableBlock,
4183 kCaptionCtorFlags}};
4184 return &sScrollableBlockData[caption];
4185 }
4186 }
4187
4188 // Handle various non-scrollable blocks.
4189 static constexpr FrameConstructionData sNonScrollableBlockData[2] = {
4190 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
4191 {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
4192 kCaptionCtorFlags}};
4193 return &sNonScrollableBlockData[caption];
4194 }
4195 case StyleDisplayInside::Table: {
4196 static constexpr FrameConstructionData data(
4197 &nsCSSFrameConstructor::ConstructTable);
4198 return &data;
4199 }
4200 // NOTE: In the unlikely event that we add another table-part here that
4201 // has a desired-parent-type (& hence triggers table fixup), we'll need to
4202 // also update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
4203 case StyleDisplayInside::TableRowGroup: {
4204 static constexpr FrameConstructionData data(
4205 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4206 FCDATA_IS_TABLE_PART0x800 |
4207 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4208 return &data;
4209 }
4210 case StyleDisplayInside::TableColumn: {
4211 static constexpr FrameConstructionData data(
4212 &nsCSSFrameConstructor::ConstructTableCol,
4213 FCDATA_IS_TABLE_PART0x800 |
4214 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup)(((uint32_t)(eTypeColGroup)) << 28));
4215 return &data;
4216 }
4217 case StyleDisplayInside::TableColumnGroup: {
4218 static constexpr FrameConstructionData data(
4219 ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
4220 FCDATA_IS_TABLE_PART0x800 | FCDATA_DISALLOW_OUT_OF_FLOW0x8 |
4221 FCDATA_SKIP_ABSPOS_PUSH0x200 |
4222 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4223 return &data;
4224 }
4225 case StyleDisplayInside::TableHeaderGroup: {
4226 static constexpr FrameConstructionData data(
4227 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4228 FCDATA_IS_TABLE_PART0x800 |
4229 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4230 return &data;
4231 }
4232 case StyleDisplayInside::TableFooterGroup: {
4233 static constexpr FrameConstructionData data(
4234 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4235 FCDATA_IS_TABLE_PART0x800 |
4236 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4237 return &data;
4238 }
4239 case StyleDisplayInside::TableRow: {
4240 static constexpr FrameConstructionData data(
4241 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4242 FCDATA_IS_TABLE_PART0x800 |
4243 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28));
4244 return &data;
4245 }
4246 case StyleDisplayInside::TableCell: {
4247 static constexpr FrameConstructionData data(
4248 &nsCSSFrameConstructor::ConstructTableCell,
4249 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28));
4250 return &data;
4251 }
4252 case StyleDisplayInside::Flex:
4253 case StyleDisplayInside::WebkitBox: {
4254 static constexpr FrameConstructionData nonScrollableData(
4255 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
);
4256 static constexpr FrameConstructionData data(
4257 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
,
4258 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4259 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4260 : &data;
4261 }
4262 case StyleDisplayInside::Grid:
4263 case StyleDisplayInside::GridLanes: {
4264 static constexpr FrameConstructionData nonScrollableData(
4265 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
);
4266 static constexpr FrameConstructionData data(
4267 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
,
4268 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4269 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4270 : &data;
4271 }
4272 case StyleDisplayInside::Ruby: {
4273 static constexpr FrameConstructionData data[] = {
4274 {&nsCSSFrameConstructor::ConstructBlockRubyFrame,
4275 FCDATA_MAY_NEED_SCROLLFRAME0x80},
4276 {ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
, FCDATA_IS_LINE_PARTICIPANT0x2000}};
4277 bool isInline = aDisplay.DisplayOutside() == StyleDisplayOutside::Inline;
4278 return &data[isInline];
4279 }
4280 case StyleDisplayInside::RubyBase: {
4281 static constexpr FrameConstructionData data(
4282 ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
4283 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4284 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28));
4285 return &data;
4286 }
4287 case StyleDisplayInside::RubyBaseContainer: {
4288 static constexpr FrameConstructionData data(
4289 ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
4290 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4291 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4292 return &data;
4293 }
4294 case StyleDisplayInside::RubyText: {
4295 static constexpr FrameConstructionData data(
4296 ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
4297 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4298 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28));
4299 return &data;
4300 }
4301 case StyleDisplayInside::RubyTextContainer: {
4302 static constexpr FrameConstructionData data(
4303 ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
4304 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4305 return &data;
4306 }
4307 default:
4308 MOZ_ASSERT_UNREACHABLE("unknown 'display' 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 'display' value" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown 'display' value" ")"); do
{ MOZ_CrashSequence(__null, 4308); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4309 return nullptr;
4310 }
4311}
4312
4313nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
4314 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4315 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4316 nsFrameList& aFrameList) {
4317 nsContainerFrame* newFrame = nullptr;
4318 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
4319 aDisplay, aFrameList, newFrame);
4320 MOZ_ASSERT(newFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("newFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ")"
); do { MOZ_CrashSequence(__null, 4320); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4321 return newFrame;
4322}
4323
4324void nsCSSFrameConstructor::ConstructScrollableBlockWithScrollContainer(
4325 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4326 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4327 nsFrameList& aFrameList, nsContainerFrame*& aNewFrame) {
4328 nsIContent* const content = aItem.mContent;
4329 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4330 MOZ_ASSERT_IF(aNewFrame, aNewFrame->IsScrollContainerOrSubclass())do { if (aNewFrame) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aNewFrame->IsScrollContainerOrSubclass())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewFrame->IsScrollContainerOrSubclass()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aNewFrame->IsScrollContainerOrSubclass()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4330); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->IsScrollContainerOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 4330); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4331
4332 RefPtr<ComputedStyle> scrolledContentStyle =
4333 BeginBuildingScrollContainerFrame(
4334 aState, content, computedStyle,
4335 aState.GetGeometricParent(*aDisplay, aParentFrame), false, aNewFrame);
4336
4337 // Create our block frame
4338 // pass a temporary stylecontext, the correct one will be set later
4339 nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4340
4341 // Make sure to AddChild before we call ConstructBlock so that we
4342 // end up before our descendants in fixed-pos lists as needed.
4343 aState.AddChild(aNewFrame, aFrameList, content, aParentFrame);
4344
4345 nsFrameList blockList;
4346 ConstructBlock(aState, content, aNewFrame, aNewFrame, scrolledContentStyle,
4347 &scrolledFrame, blockList,
4348 aNewFrame->IsAbsPosContainingBlock() ? aNewFrame : nullptr);
4349
4350 MOZ_ASSERT(blockList.OnlyChild() == scrolledFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(blockList.OnlyChild() == scrolledFrame)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(blockList.OnlyChild() == scrolledFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("blockList.OnlyChild() == scrolledFrame"
" (" "Scrollframe's frameList should be exactly the scrolled frame!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4351
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4351); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4351 "Scrollframe's frameList should be exactly the scrolled frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(blockList.OnlyChild() == scrolledFrame)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(blockList.OnlyChild() == scrolledFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("blockList.OnlyChild() == scrolledFrame"
" (" "Scrollframe's frameList should be exactly the scrolled frame!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4351
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4351); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4352 FinishBuildingScrollContainerFrame(aNewFrame, scrolledFrame);
4353}
4354
4355nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
4356 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4357 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4358 nsFrameList& aFrameList) {
4359 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4360 nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4361 ConstructBlock(aState, aItem.mContent,
4362 aState.GetGeometricParent(*aDisplay, aParentFrame),
4363 aParentFrame, computedStyle, &newFrame, aFrameList,
4364 newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
4365 return newFrame;
4366}
4367
4368void nsCSSFrameConstructor::InitAndRestoreFrame(
4369 const nsFrameConstructorState& aState, nsIContent* aContent,
4370 nsContainerFrame* aParentFrame, nsIFrame* aNewFrame,
4371 AllowCounters aAllowCounters) {
4372 MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewFrame" " (" "Null frame cannot be initialized"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4372
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewFrame" ") (" "Null frame cannot be initialized"
")"); do { MOZ_CrashSequence(__null, 4372); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4373
4374 // Initialize the frame
4375 aNewFrame->Init(aContent, aParentFrame, nullptr);
4376 aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4377
4378 if (aAllowCounters == AllowCounters::Yes && !aState.mCreatingExtraFrames &&
4379 mContainStyleScopeManager.AddCounterChanges(aNewFrame)) {
4380 CountersDirty();
4381 }
4382}
4383
4384already_AddRefed<ComputedStyle> nsCSSFrameConstructor::ResolveComputedStyle(
4385 nsIContent* aContent) {
4386 if (auto* element = Element::FromNode(aContent)) {
4387 return ServoStyleSet::ResolveServoStyle(*element);
4388 }
4389
4390 MOZ_ASSERT(aContent->IsText(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsText())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->IsText()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsText()"
" (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4392
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4392); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4391 "shouldn't waste time creating ComputedStyles for "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsText())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->IsText()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsText()"
" (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4392
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4392); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4392 "comments and processing instructions")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsText())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->IsText()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsText()"
" (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4392
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4392); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4393
4394 Element* parent = aContent->GetFlattenedTreeParentElement();
4395 MOZ_ASSERT(parent, "Text out of the flattened tree?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(parent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("parent" " (" "Text out of the flattened tree?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4395
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "Text out of the flattened tree?"
")"); do { MOZ_CrashSequence(__null, 4395); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4396
4397 // FIXME(emilio): The const_cast is unfortunate, but it's not worse than what
4398 // we did before.
4399 //
4400 // We could use ResolveServoStyle, but that would involve extra unnecessary
4401 // refcount traffic...
4402 auto* parentStyle =
4403 const_cast<ComputedStyle*>(Servo_Element_GetMaybeOutOfDateStyle(parent));
4404 MOZ_ASSERT(parentStyle,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parentStyle)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parentStyle))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("parentStyle" " ("
"How are we inserting text frames in an unstyled element?" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4405); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4405); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4405 "How are we inserting text frames in an unstyled element?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parentStyle)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parentStyle))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("parentStyle" " ("
"How are we inserting text frames in an unstyled element?" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4405); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4405); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4406 return mPresShell->StyleSet()->ResolveStyleForText(aContent, parentStyle);
4407}
4408
4409// MathML Mod - RBS
4410void nsCSSFrameConstructor::FlushAccumulatedBlock(
4411 nsFrameConstructorState& aState, nsIContent* aContent,
4412 nsContainerFrame* aParentFrame, nsFrameList& aBlockList,
4413 nsFrameList& aNewList) {
4414 if (aBlockList.IsEmpty()) {
4415 // Nothing to do
4416 return;
4417 }
4418
4419 auto anonPseudo = PseudoStyleType::MozMathmlAnonymousBlock;
4420
4421 ComputedStyle* parentContext =
4422 nsIFrame::CorrectStyleParentFrame(aParentFrame, anonPseudo)->Style();
4423 ServoStyleSet* styleSet = mPresShell->StyleSet();
4424 RefPtr<ComputedStyle> blockContext =
4425 styleSet->ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
4426
4427 // then, create a block frame that will wrap the child frames. Make it a
4428 // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4429 // is not a suitable block.
4430 nsContainerFrame* blockFrame =
4431 NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
4432
4433 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
4434 ReparentFrames(this, blockFrame, aBlockList, false);
4435 // We have to walk over aBlockList before we hand it over to blockFrame.
4436 for (nsIFrame* f : aBlockList) {
4437 f->SetParentIsWrapperAnonBox();
4438 }
4439 // abs-pos and floats are disabled in MathML children so we don't have to
4440 // worry about messing up those.
4441 blockFrame->SetInitialChildList(FrameChildListID::Principal,
4442 std::move(aBlockList));
4443 aNewList.AppendFrame(nullptr, blockFrame);
4444}
4445
4446// Only <math> elements can be floated or positioned. All other MathML
4447// should be in-flow.
4448#define MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 } \
4449 FrameConstructionData { \
4450 _func, FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | \
4451 FCDATA_WRAP_KIDS_IN_BLOCKS0x20 \
4452 }
4453
4454#define SIMPLE_MATHML_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData { _func, 0x8 | 0x10 |
0x20 }}
{nsGkAtoms::_tag, MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 }}
4455
4456/* static */
4457const nsCSSFrameConstructor::FrameConstructionData*
4458nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
4459 ComputedStyle& aStyle) {
4460 MOZ_ASSERT(aElement.IsMathMLElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement.IsMathMLElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement.IsMathMLElement()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aElement.IsMathMLElement()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4460); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsMathMLElement()" ")"); do { MOZ_CrashSequence
(__null, 4460); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4461
4462 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4463
4464 // Handle <math> specially, because it sometimes produces inlines
4465 if (tag == nsGkAtoms::math) {
4466 // The IsBlockOutsideStyle() check must match what
4467 // specified::Display::equivalent_block_display is checking for
4468 // already-block-outside things. Though the behavior here for the
4469 // display:table case is pretty weird...
4470 if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
4471 static constexpr FrameConstructionData sBlockMathData(
4472 ToCreationFunc(NS_NewMathMLmathBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathBlockFrame(aPs, aStyle); }
,
4473 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4474 return &sBlockMathData;
4475 }
4476
4477 static constexpr FrameConstructionData sInlineMathData(
4478 ToCreationFunc(NS_NewMathMLmathInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathInlineFrame(aPs, aStyle); }
,
4479 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4480 FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4481 return &sInlineMathData;
4482 }
4483
4484 // Special case for elements with a display value other than none
4485 // specified in mathml.css that are not handled by this function.
4486 // These shouldn't be rendered as an mrow.
4487 if (tag == nsGkAtoms::mtable || tag == nsGkAtoms::mtr ||
4488 tag == nsGkAtoms::mlabeledtr || tag == nsGkAtoms::mtd) {
4489 return nullptr;
4490 }
4491
4492 static constexpr FrameConstructionDataByTag sMathMLData[] = {
4493 SIMPLE_MATHML_CREATE(annotation, NS_NewMathMLTokenFrame){nsGkAtoms::annotation, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4494 SIMPLE_MATHML_CREATE(annotation_xml, NS_NewMathMLmrowFrame){nsGkAtoms::annotation_xml, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4495 SIMPLE_MATHML_CREATE(mi, NS_NewMathMLTokenFrame){nsGkAtoms::mi, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4496 SIMPLE_MATHML_CREATE(mn, NS_NewMathMLTokenFrame){nsGkAtoms::mn, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4497 SIMPLE_MATHML_CREATE(ms, NS_NewMathMLTokenFrame){nsGkAtoms::ms, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4498 SIMPLE_MATHML_CREATE(mtext, NS_NewMathMLTokenFrame){nsGkAtoms::mtext, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4499 SIMPLE_MATHML_CREATE(mo, NS_NewMathMLmoFrame){nsGkAtoms::mo, FrameConstructionData { NS_NewMathMLmoFrame, 0x8
| 0x10 | 0x20 }}
,
4500 SIMPLE_MATHML_CREATE(mfrac, NS_NewMathMLmfracFrame){nsGkAtoms::mfrac, FrameConstructionData { NS_NewMathMLmfracFrame
, 0x8 | 0x10 | 0x20 }}
,
4501 SIMPLE_MATHML_CREATE(msup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4502 SIMPLE_MATHML_CREATE(msub, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msub, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4503 SIMPLE_MATHML_CREATE(msubsup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msubsup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4504 SIMPLE_MATHML_CREATE(munder, NS_NewMathMLmunderoverFrame){nsGkAtoms::munder, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4505 SIMPLE_MATHML_CREATE(mover, NS_NewMathMLmunderoverFrame){nsGkAtoms::mover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4506 SIMPLE_MATHML_CREATE(munderover, NS_NewMathMLmunderoverFrame){nsGkAtoms::munderover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4507 SIMPLE_MATHML_CREATE(mphantom, NS_NewMathMLmrowFrame){nsGkAtoms::mphantom, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4508 SIMPLE_MATHML_CREATE(mpadded, NS_NewMathMLmpaddedFrame){nsGkAtoms::mpadded, FrameConstructionData { NS_NewMathMLmpaddedFrame
, 0x8 | 0x10 | 0x20 }}
,
4509 SIMPLE_MATHML_CREATE(mspace, NS_NewMathMLmspaceFrame){nsGkAtoms::mspace, FrameConstructionData { NS_NewMathMLmspaceFrame
, 0x8 | 0x10 | 0x20 }}
,
4510 SIMPLE_MATHML_CREATE(none, NS_NewMathMLmrowFrame){nsGkAtoms::none, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4511 SIMPLE_MATHML_CREATE(mprescripts, NS_NewMathMLmrowFrame){nsGkAtoms::mprescripts, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4512 SIMPLE_MATHML_CREATE(mfenced, NS_NewMathMLmrowFrame){nsGkAtoms::mfenced, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4513 SIMPLE_MATHML_CREATE(mmultiscripts, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::mmultiscripts, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4514 SIMPLE_MATHML_CREATE(mstyle, NS_NewMathMLmrowFrame){nsGkAtoms::mstyle, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4515 SIMPLE_MATHML_CREATE(msqrt, NS_NewMathMLmrootFrame){nsGkAtoms::msqrt, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4516 SIMPLE_MATHML_CREATE(mroot, NS_NewMathMLmrootFrame){nsGkAtoms::mroot, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4517 SIMPLE_MATHML_CREATE(maction, NS_NewMathMLmrowFrame){nsGkAtoms::maction, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4518 SIMPLE_MATHML_CREATE(mrow, NS_NewMathMLmrowFrame){nsGkAtoms::mrow, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4519 SIMPLE_MATHML_CREATE(merror, NS_NewMathMLmrowFrame){nsGkAtoms::merror, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4520 SIMPLE_MATHML_CREATE(menclose, NS_NewMathMLmencloseFrame){nsGkAtoms::menclose, FrameConstructionData { NS_NewMathMLmencloseFrame
, 0x8 | 0x10 | 0x20 }}
,
4521 SIMPLE_MATHML_CREATE(semantics, NS_NewMathMLmrowFrame){nsGkAtoms::semantics, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
};
4522
4523 if (const auto* data = FindDataByTag(aElement, aStyle, sMathMLData,
4524 std::size(sMathMLData))) {
4525 return data;
4526 }
4527 // Unknown MathML elements render as an mrow, see:
4528 // https://w3c.github.io/mathml-core/#ref-for-dfn-unknown-mathml-element-2
4529 static constexpr FrameConstructionData sMrowData =
4530 MATHML_DATA(NS_NewMathMLmrowFrame)FrameConstructionData { NS_NewMathMLmrowFrame, 0x8 | 0x10 | 0x20
}
;
4531 return &sMrowData;
4532}
4533
4534nsContainerFrame* nsCSSFrameConstructor::ConstructSVGFrameWithAnonymousChild(
4535 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4536 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
4537 ContainerFrameCreationFunc aConstructor,
4538 ContainerFrameCreationFunc aInnerConstructor, PseudoStyleType aInnerPseudo,
4539 bool aCandidateRootFrame) {
4540 nsIContent* const content = aItem.mContent;
4541 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4542
4543 // Create the outer frame:
4544 nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4545
4546 InitAndRestoreFrame(aState, content,
4547 aCandidateRootFrame
4548 ? aState.GetGeometricParent(
4549 *computedStyle->StyleDisplay(), aParentFrame)
4550 : aParentFrame,
4551 newFrame);
4552 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4553
4554 // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
4555 RefPtr<ComputedStyle> scForAnon =
4556 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(aInnerPseudo,
4557 computedStyle);
4558
4559 // Create the anonymous inner wrapper frame
4560 nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
4561
4562 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
4563
4564 // Put the newly created frames into the right child list
4565 SetInitialSingleChild(newFrame, innerFrame);
4566
4567 aState.AddChild(newFrame, aFrameList, content, aParentFrame,
4568 aCandidateRootFrame, aCandidateRootFrame);
4569
4570 if (!mRootElementFrame && aCandidateRootFrame) {
4571 mRootElementFrame = newFrame;
4572 }
4573
4574 nsFrameConstructorSaveState floatSaveState;
4575 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
4576
4577 nsFrameList childList;
4578
4579 // Process children
4580 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
4581 ConstructFramesFromItemList(
4582 aState, aItem.mChildItems, innerFrame,
4583 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
4584 } else {
4585 ProcessChildren(aState, content, computedStyle, innerFrame,
4586 /* aCanHaveGeneratedContent = */ false, childList, false);
4587 }
4588
4589 // Set the inner wrapper frame's initial primary list
4590 innerFrame->SetInitialChildList(FrameChildListID::Principal,
4591 std::move(childList));
4592
4593 return newFrame;
4594}
4595
4596nsIFrame* nsCSSFrameConstructor::ConstructOuterSVG(
4597 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4598 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4599 nsFrameList& aFrameList) {
4600 return ConstructSVGFrameWithAnonymousChild(
4601 aState, aItem, aParentFrame, aFrameList, NS_NewSVGOuterSVGFrame,
4602 NS_NewSVGOuterSVGAnonChildFrame, PseudoStyleType::MozSvgOuterSvgAnonChild,
4603 true);
4604}
4605
4606nsIFrame* nsCSSFrameConstructor::ConstructMarker(
4607 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4608 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4609 nsFrameList& aFrameList) {
4610 return ConstructSVGFrameWithAnonymousChild(
4611 aState, aItem, aParentFrame, aFrameList, NS_NewSVGMarkerFrame,
4612 NS_NewSVGMarkerAnonChildFrame, PseudoStyleType::MozSvgMarkerAnonChild,
4613 false);
4614}
4615
4616// Only outer <svg> elements can be floated or positioned. All other SVG
4617// should be in-flow.
4618#define SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
\
4619 FrameConstructionData(ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
, \
4620 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | \
4621 FCDATA_SKIP_ABSPOS_PUSH0x200 | \
4622 FCDATA_DISALLOW_GENERATED_CONTENT0x400)
4623#define SIMPLE_SVG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8
| 0x200 | 0x400)}
\
4624 {nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
}
4625
4626/* static */
4627const nsCSSFrameConstructor::FrameConstructionData*
4628nsCSSFrameConstructor::FindSVGData(const Element& aElement,
4629 nsIFrame* aParentFrame,
4630 bool aIsWithinSVGText,
4631 bool aAllowsTextPathChild,
4632 ComputedStyle& aStyle) {
4633 MOZ_ASSERT(aElement.IsSVGElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement.IsSVGElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement.IsSVGElement()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aElement.IsSVGElement()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 4633); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsSVGElement()" ")"); do { MOZ_CrashSequence
(__null, 4633); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4634
4635 static constexpr FrameConstructionData sSuppressData = SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
4636 static constexpr FrameConstructionData sContainerData =
4637 SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)
;
4638
4639 bool parentIsSVG = aIsWithinSVGText;
4640 nsIContent* parentContent =
4641 aParentFrame ? aParentFrame->GetContent() : nullptr;
4642
4643 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4644
4645 if (aElement.OwnerDoc()->IsSVGGlyphsDocument()) {
4646 // SVG elements that are explicitly not supported in svg-glyphs documents.
4647 // (Partially applies the restrictions mentioned at
4648 // https://learn.microsoft.com/en-us/typography/opentype/spec/svg#svg-capability-requirements-and-restrictions
4649 if (tag == nsGkAtoms::text || tag == nsGkAtoms::tspan ||
4650 tag == nsGkAtoms::textPath || tag == nsGkAtoms::a ||
4651 tag == nsGkAtoms::foreignObject || tag == nsGkAtoms::svgSwitch ||
4652 tag == nsGkAtoms::view) {
4653 return &sSuppressData;
4654 }
4655 }
4656
4657 // XXXbz should this really be based on the tag of the parent frame's content?
4658 // Should it not be based on the type of the parent frame (e.g. whether it's
4659 // an SVG frame)?
4660 if (parentContent) {
4661 // It's not clear whether the SVG spec intends to allow any SVG
4662 // content within svg:foreignObject at all (SVG 1.1, section
4663 // 23.2), but if it does, it better be svg:svg. So given that
4664 // we're allowing it, treat it as a non-SVG parent.
4665 parentIsSVG =
4666 parentContent->IsSVGElement() &&
4667 parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
4668 }
4669
4670 if ((tag != nsGkAtoms::svg && !parentIsSVG) ||
4671 (tag == nsGkAtoms::desc || tag == nsGkAtoms::title ||
4672 tag == nsGkAtoms::metadata)) {
4673 // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4674 // svg:svg not contained within svg:svg are incorrect, although they
4675 // don't seem to specify error handling. Ignore them, since many of
4676 // our frame classes can't deal. It *may* be that the document
4677 // should at that point be considered in error according to F.2, but
4678 // it's hard to tell.
4679 //
4680 // We don't currently handle any UI for desc/title/metadata
4681 return &sSuppressData;
4682 }
4683
4684 // We don't need frames for animation elements
4685 if (aElement.IsSVGAnimationElement()) {
4686 return &sSuppressData;
4687 }
4688
4689 if (tag == nsGkAtoms::svg && !parentIsSVG) {
4690 // We need outer <svg> elements to have an SVGOuterSVGFrame regardless
4691 // of whether they fail conditional processing attributes, since various
4692 // SVG frames assume that one exists. We handle the non-rendering
4693 // of failing outer <svg> element contents like <switch> statements,
4694 // and do the PassesConditionalProcessingTests call in
4695 // SVGOuterSVGFrame::Init.
4696 static constexpr FrameConstructionData sOuterSVGData(
4697 &nsCSSFrameConstructor::ConstructOuterSVG);
4698 return &sOuterSVGData;
4699 }
4700
4701 if (tag == nsGkAtoms::marker) {
4702 static constexpr FrameConstructionData sMarkerSVGData(
4703 &nsCSSFrameConstructor::ConstructMarker);
4704 return &sMarkerSVGData;
4705 }
4706
4707 if (!aElement.PassesConditionalProcessingTests()) {
4708 // Elements with failing conditional processing attributes never get
4709 // rendered. Note that this is not where we select which frame in a
4710 // <switch> to render! That happens in SVGSwitchFrame::PaintSVG.
4711 if (aIsWithinSVGText) {
4712 // SVGTextFrame doesn't handle conditional processing attributes,
4713 // so don't create frames for descendants of <text> with failing
4714 // attributes. We need frames not to be created so that text layout
4715 // is correct.
4716 return &sSuppressData;
4717 }
4718 // If we're not inside <text>, create an SVGContainerFrame (which is a
4719 // frame that doesn't render) so that paint servers can still be referenced,
4720 // even if they live inside an element with failing conditional processing
4721 // attributes.
4722 return &sContainerData;
4723 }
4724
4725 // Ensure that a stop frame is a child of a gradient and that gradients
4726 // can only have stop children.
4727 bool parentIsGradient = aParentFrame && static_cast<SVGGradientFrame*>(
4728 do_QueryFrame(aParentFrame));
4729 bool stop = (tag == nsGkAtoms::stop);
4730 if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
4731 return &sSuppressData;
4732 }
4733
4734 // Prevent bad frame types being children of filters or parents of filter
4735 // primitives. If aParentFrame is null, we know that the frame that will
4736 // be created will be an nsInlineFrame, so it can never be a filter.
4737 bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
4738 if ((parentIsFilter && !aElement.IsSVGFilterPrimitiveElement()) ||
4739 (!parentIsFilter && aElement.IsSVGFilterPrimitiveElement())) {
4740 return &sSuppressData;
4741 }
4742
4743 // Prevent bad frame types being children of filter primitives or parents of
4744 // filter primitive children. If aParentFrame is null, we know that the frame
4745 // that will be created will be an nsInlineFrame, so it can never be a filter
4746 // primitive.
4747 bool parentIsFEContainerFrame =
4748 aParentFrame && aParentFrame->IsSVGFEContainerFrame();
4749 if ((parentIsFEContainerFrame &&
4750 !aElement.IsSVGFilterPrimitiveChildElement()) ||
4751 (!parentIsFEContainerFrame &&
4752 aElement.IsSVGFilterPrimitiveChildElement())) {
4753 return &sSuppressData;
4754 }
4755
4756 // Special cases for text/tspan/textPath, because the kind of frame
4757 // they get depends on the parent frame. We ignore 'a' elements when
4758 // determining the parent, however.
4759 if (aIsWithinSVGText) {
4760 // If aIsWithinSVGText is true, then we know that the "SVG text uses
4761 // CSS frames" pref was true when this SVG fragment was first constructed.
4762 //
4763 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
4764 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
4765 // really know how to deal with it. This kinda sucks. :(
4766 if (aParentFrame && aParentFrame->GetContent() != aElement.GetParent()) {
4767 return &sSuppressData;
4768 }
4769
4770 // We don't use ConstructInline because we want different behavior
4771 // for generated content.
4772 static constexpr FrameConstructionData sTSpanData(
4773 ToCreationFunc(NS_NewInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewInlineFrame(aPs, aStyle); }
,
4774 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_SKIP_ABSPOS_PUSH0x200 |
4775 FCDATA_DISALLOW_GENERATED_CONTENT0x400 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4776 FCDATA_IS_INLINE0x1000 | FCDATA_USE_CHILD_ITEMS0x10000);
4777 if (tag == nsGkAtoms::textPath) {
4778 if (aAllowsTextPathChild) {
4779 return &sTSpanData;
4780 }
4781 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::a) {
4782 return &sTSpanData;
4783 }
4784 return &sSuppressData;
4785 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::textPath) {
4786 return &sSuppressData;
4787 }
4788
4789 static constexpr FrameConstructionDataByTag sSVGData[] = {
4790 SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame){nsGkAtoms::svg, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGInnerSVGFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4791 SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame){nsGkAtoms::g, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4792 SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame){nsGkAtoms::svgSwitch, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGSwitchFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4793 SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame){nsGkAtoms::symbol, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGSymbolFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4794 SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame){nsGkAtoms::polygon, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4795 SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame){nsGkAtoms::polyline, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4796 SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame){nsGkAtoms::circle, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4797 SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame){nsGkAtoms::ellipse, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4798 SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame){nsGkAtoms::line, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4799 SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame){nsGkAtoms::rect, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4800 SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame){nsGkAtoms::path, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4801 SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame){nsGkAtoms::defs, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4802 {nsGkAtoms::text,
4803 {NS_NewSVGTextFrame,
4804 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_ALLOW_BLOCK_STYLES0x8000 |
4805 FCDATA_DISALLOW_GENERATED_CONTENT0x400,
4806 PseudoStyleType::MozSvgText}},
4807 {nsGkAtoms::foreignObject,
4808 {ToCreationFunc(NS_NewSVGForeignObjectFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewSVGForeignObjectFrame(aPs, aStyle); }
,
4809 FCDATA_DISALLOW_OUT_OF_FLOW0x8, PseudoStyleType::MozSvgForeignContent}},
4810 SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame){nsGkAtoms::a, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGAFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4811 SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame){nsGkAtoms::linearGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGLinearGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4812 SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame){nsGkAtoms::radialGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGRadialGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4813 SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame){nsGkAtoms::stop, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGStopFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4814 SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame){nsGkAtoms::use, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGUseFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4815 SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame){nsGkAtoms::view, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGViewFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4816 SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame){nsGkAtoms::image, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGImageFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4817 SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame){nsGkAtoms::clipPath, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGClipPathFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4818 SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame){nsGkAtoms::filter, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFilterFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4819 SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame){nsGkAtoms::pattern, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGPatternFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4820 SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame){nsGkAtoms::mask, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGMaskFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4821 SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feDistantLight, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4822 SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::fePointLight, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4823 SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feSpotLight, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4824 SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame){nsGkAtoms::feBlend, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4825 SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feColorMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4826 SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncR, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4827 SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncG, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4828 SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncB, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4829 SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncA, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4830 SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame){nsGkAtoms::feComposite, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4831 SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame){nsGkAtoms::feComponentTransfer, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4832 SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feConvolveMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4833 SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feDiffuseLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4834 SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame){nsGkAtoms::feDisplacementMap, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4835 SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame){nsGkAtoms::feDropShadow, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4836 SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame){nsGkAtoms::feFlood, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4837 SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame){nsGkAtoms::feGaussianBlur, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4838 SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame){nsGkAtoms::feImage, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEImageFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4839 SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame){nsGkAtoms::feMerge, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4840 SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feMergeNode, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4841 SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame){nsGkAtoms::feMorphology, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4842 SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame){nsGkAtoms::feOffset, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4843 SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feSpecularLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4844 SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame){nsGkAtoms::feTile, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4845 SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame){nsGkAtoms::feTurbulence, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
};
4846
4847 const FrameConstructionData* data =
4848 FindDataByTag(aElement, aStyle, sSVGData, std::size(sSVGData));
4849
4850 if (!data) {
4851 data = &sContainerData;
4852 }
4853
4854 return data;
4855}
4856
4857void nsCSSFrameConstructor::AppendPageBreakItem(
4858 nsIContent* aContent, FrameConstructionItemList& aItems) {
4859 RefPtr<ComputedStyle> pseudoStyle =
4860 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
4861 PseudoStyleType::MozPageBreak);
4862
4863 MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay
::Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay
::Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
" (" "Unexpected display" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4864); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
4864 "Unexpected display")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay
::Block)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay
::Block))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
" (" "Unexpected display" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4864); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4865
4866 static constexpr FrameConstructionData sPageBreakData(NS_NewPageBreakFrame,
4867 FCDATA_SKIP_FRAMESET0x1);
4868 aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
4869 true);
4870}
4871
4872bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
4873 nsFrameConstructorState& aState, nsIContent* aContent,
4874 nsContainerFrame* aParentFrame) {
4875 aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
4876 if (aContent->GetPrimaryFrame() && !aState.mCreatingExtraFrames) {
4877 MOZ_ASSERT(false,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "asked to create frame construction item for a node that "
"already has a frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4879); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4878 "asked to create frame construction item for a node that "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "asked to create frame construction item for a node that "
"already has a frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4879); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4879 "already has a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "asked to create frame construction item for a node that "
"already has a frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 4879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4879); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4880 return false;
4881 }
4882
4883 // don't create a whitespace frame if aParent doesn't want it
4884 if (!NeedFrameFor(aState, aParentFrame, aContent)) {
4885 return false;
4886 }
4887
4888 // never create frames for comments or PIs
4889 if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
4890 return false;
4891 }
4892
4893 return true;
4894}
4895
4896void nsCSSFrameConstructor::AddFrameConstructionItems(
4897 nsFrameConstructorState& aState, nsIContent* aContent,
4898 bool aSuppressWhiteSpaceOptimizations, const ComputedStyle& aParentStyle,
4899 const InsertionPoint& aInsertion, FrameConstructionItemList& aItems,
4900 ItemFlags aFlags) {
4901 nsContainerFrame* parentFrame = aInsertion.mParentFrame;
4902 if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
4903 return;
4904 }
4905
4906 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
4907 auto flags = aFlags + ItemFlag::AllowPageBreak;
4908 if (parentFrame) {
4909 if (parentFrame->IsInSVGTextSubtree()) {
4910 flags += ItemFlag::IsWithinSVGText;
4911 }
4912 if (parentFrame->IsBlockFrame() && parentFrame->GetParent() &&
4913 parentFrame->GetParent()->IsSVGTextFrame()) {
4914 flags += ItemFlag::AllowTextPathChild;
4915 }
4916 }
4917 AddFrameConstructionItemsInternal(aState, aContent, parentFrame,
4918 aSuppressWhiteSpaceOptimizations,
4919 computedStyle, flags, aItems);
4920}
4921
4922// Whether we should suppress frames for a child under a <select> element.
4923// Right now we need this for two things:
4924// * To implement <option label>'s suppression of descendants (sad!)
4925// * To implement hiding of the <select>'s text content (hopefully going away
4926// soon enough, see https://github.com/whatwg/html/issues/12717).
4927static bool ShouldSuppressFrameForSelect(const nsIContent* aParent,
4928 const nsIContent& aChild) {
4929 if (!aParent) {
4930 return false;
4931 }
4932
4933 if (aChild.IsRootOfNativeAnonymousSubtree()) {
4934 // Allow native anonymous content no matter what.
4935 return false;
4936 }
4937
4938 if (aParent->IsHTMLElement(nsGkAtoms::option)) {
4939 // Options with labels have their label text added in ::before by forms.css.
4940 // Suppress frames for their children.
4941 // TODO(emilio): This should probably be done with shadow DOM instead (but a
4942 // ShadowRoot per option seems unfortunate...).
4943 return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
4944 }
4945
4946 if (const auto* select = HTMLSelectElement::FromNode(aParent)) {
4947 // Direct text descendants of listbox <select> are not expected to render.
4948 return !select->IsCombobox() && aChild.IsText() &&
4949 aParent == aChild.GetParent();
4950 }
4951
4952 return false;
4953}
4954
4955const nsCSSFrameConstructor::FrameConstructionData*
4956nsCSSFrameConstructor::FindDataForContent(nsIContent& aContent,
4957 ComputedStyle& aStyle,
4958 nsIFrame* aParentFrame,
4959 ItemFlags aFlags) {
4960 MOZ_ASSERT(aStyle.StyleDisplay()->mDisplay != StyleDisplay::None &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyle.StyleDisplay()->mDisplay != StyleDisplay::
None && aStyle.StyleDisplay()->mDisplay != StyleDisplay
::Contents)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aStyle.StyleDisplay()->mDisplay !=
StyleDisplay::None && aStyle.StyleDisplay()->mDisplay
!= StyleDisplay::Contents))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
" (" "These two special display values should be handled earlier"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4962
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
") (" "These two special display values should be handled earlier"
")"); do { MOZ_CrashSequence(__null, 4962); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4961 aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyle.StyleDisplay()->mDisplay != StyleDisplay::
None && aStyle.StyleDisplay()->mDisplay != StyleDisplay
::Contents)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aStyle.StyleDisplay()->mDisplay !=
StyleDisplay::None && aStyle.StyleDisplay()->mDisplay
!= StyleDisplay::Contents))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
" (" "These two special display values should be handled earlier"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4962
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
") (" "These two special display values should be handled earlier"
")"); do { MOZ_CrashSequence(__null, 4962); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4962 "These two special display values should be handled earlier")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyle.StyleDisplay()->mDisplay != StyleDisplay::
None && aStyle.StyleDisplay()->mDisplay != StyleDisplay
::Contents)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(aStyle.StyleDisplay()->mDisplay !=
StyleDisplay::None && aStyle.StyleDisplay()->mDisplay
!= StyleDisplay::Contents))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
" (" "These two special display values should be handled earlier"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 4962
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyle.StyleDisplay()->mDisplay != StyleDisplay::None && aStyle.StyleDisplay()->mDisplay != StyleDisplay::Contents"
") (" "These two special display values should be handled earlier"
")"); do { MOZ_CrashSequence(__null, 4962); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4963
4964 if (auto* text = Text::FromNode(aContent)) {
4965 return FindTextData(*text, aParentFrame);
4966 }
4967
4968 return FindElementData(*aContent.AsElement(), aStyle, aParentFrame, aFlags);
4969}
4970
4971const nsCSSFrameConstructor::FrameConstructionData*
4972nsCSSFrameConstructor::FindElementData(const Element& aElement,
4973 ComputedStyle& aStyle,
4974 nsIFrame* aParentFrame,
4975 ItemFlags aFlags) {
4976 // Don't create frames for non-SVG element children of SVG elements.
4977 if (!aElement.IsSVGElement()) {
4978 // NOTE: Anon content (from non display: contents) is allowed, the native
4979 // code should know what it's doing. In practice we care about ::backdrop
4980 // and the custom-content-container.
4981 if (aParentFrame && IsFrameForSVG(aParentFrame) &&
4982 !aParentFrame->IsSVGForeignObjectFrame() &&
4983 (aElement.GetParent() != aParentFrame->GetContent() ||
4984 !aElement.IsRootOfNativeAnonymousSubtree())) {
4985 return nullptr;
4986 }
4987 if (aFlags.contains(ItemFlag::IsWithinSVGText)) {
4988 return nullptr;
4989 }
4990 }
4991
4992 if (auto* data = FindElementTagData(aElement, aStyle, aParentFrame, aFlags)) {
4993 return data;
4994 }
4995
4996 // Check for 'content: <image-url>' on the element (which makes us ignore
4997 // 'display' values other than 'none' or 'contents').
4998 if (nsImageFrame::ShouldCreateImageFrameForContentProperty(aElement,
4999 aStyle)) {
5000 static constexpr FrameConstructionData sImgData(
5001 NS_NewImageFrameForContentProperty);
5002 return &sImgData;
5003 }
5004
5005 const bool shouldBlockify = aFlags.contains(ItemFlag::IsForRenderedLegend) ||
5006 aFlags.contains(ItemFlag::IsForOutsideMarker);
5007 if (shouldBlockify && !aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
5008 // Make a temp copy of StyleDisplay and blockify its mDisplay value.
5009 auto display = *aStyle.StyleDisplay();
5010 bool isRootElement = false;
5011 uint16_t rawDisplayValue =
5012 Servo_ComputedValues_BlockifiedDisplay(&aStyle, isRootElement);
5013 display.mDisplay = StyleDisplay{rawDisplayValue};
5014 return FindDisplayData(display, aElement);
5015 }
5016
5017 const auto& display = *aStyle.StyleDisplay();
5018 return FindDisplayData(display, aElement);
5019}
5020
5021const nsCSSFrameConstructor::FrameConstructionData*
5022nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
5023 ComputedStyle& aStyle,
5024 nsIFrame* aParentFrame,
5025 ItemFlags aFlags) {
5026 switch (aElement.GetNameSpaceID()) {
5027 case kNameSpaceID_XHTML3:
5028 return FindHTMLData(aElement, aParentFrame, aStyle);
5029 case kNameSpaceID_MathML6:
5030 return FindMathMLData(aElement, aStyle);
5031 case kNameSpaceID_SVG9:
5032 return FindSVGData(aElement, aParentFrame,
5033 aFlags.contains(ItemFlag::IsWithinSVGText),
5034 aFlags.contains(ItemFlag::AllowTextPathChild), aStyle);
5035 case kNameSpaceID_XUL8:
5036 return FindXULTagData(aElement, aStyle);
5037 default:
5038 return nullptr;
5039 }
5040}
5041
5042void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
5043 nsFrameConstructorState& aState, nsIContent* aContent,
5044 nsContainerFrame* aParentFrame, bool aSuppressWhiteSpaceOptimizations,
5045 ComputedStyle* aComputedStyle, ItemFlags aFlags,
5046 FrameConstructionItemList& aItems) {
5047 MOZ_ASSERT(aContent->IsText() || aContent->IsElement(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsText() || aContent->IsElement())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsText() || aContent->IsElement())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsText() || aContent->IsElement()"
" (" "Shouldn't get anything else here!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5048); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5048 "Shouldn't get anything else here!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsText() || aContent->IsElement())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsText() || aContent->IsElement())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsText() || aContent->IsElement()"
" (" "Shouldn't get anything else here!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5048); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5049 MOZ_ASSERT(aContent->IsInComposedDoc())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsInComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->IsInComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aContent->IsInComposedDoc()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsInComposedDoc()"
")"); do { MOZ_CrashSequence(__null, 5049); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5050 MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5050); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames"
")"); do { MOZ_CrashSequence(__null, 5050); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5051
5052 const bool withinSVGText = aFlags.contains(ItemFlag::IsWithinSVGText);
5053 const bool isGeneratedContent = aFlags.contains(ItemFlag::IsGeneratedContent);
5054 MOZ_ASSERT(!isGeneratedContent || aComputedStyle->IsPseudoElement(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isGeneratedContent || aComputedStyle->IsPseudoElement
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!isGeneratedContent || aComputedStyle->IsPseudoElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!isGeneratedContent || aComputedStyle->IsPseudoElement()"
" (" "Generated content should be a pseudo-element" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5055); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5055 "Generated content should be a pseudo-element")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isGeneratedContent || aComputedStyle->IsPseudoElement
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!isGeneratedContent || aComputedStyle->IsPseudoElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!isGeneratedContent || aComputedStyle->IsPseudoElement()"
" (" "Generated content should be a pseudo-element" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5055); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5056
5057 FrameConstructionItem* item = nullptr;
5058 auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
5059 if (isGeneratedContent && !item && !aState.mCreatingExtraFrames) {
5060 MOZ_ASSERT(!IsDisplayContents(aContent),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDisplayContents(aContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDisplayContents(aContent)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!IsDisplayContents(aContent)" " (" "This would need to change if we support display: contents "
"in generated content" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5062
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5061 "This would need to change if we support display: contents "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDisplayContents(aContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDisplayContents(aContent)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!IsDisplayContents(aContent)" " (" "This would need to change if we support display: contents "
"in generated content" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5062
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5062 "in generated content")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDisplayContents(aContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDisplayContents(aContent)
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!IsDisplayContents(aContent)" " (" "This would need to change if we support display: contents "
"in generated content" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5062
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5063 aContent->UnbindFromTree();
5064 }
5065 });
5066
5067 // 'display:none' elements never creates any frames at all.
5068 const nsStyleDisplay& display = *aComputedStyle->StyleDisplay();
5069 if (display.mDisplay == StyleDisplay::None) {
5070 return;
5071 }
5072
5073 if (display.mDisplay == StyleDisplay::Contents) {
5074 // See the mDisplay fixup code in StyleAdjuster::adjust.
5075 MOZ_ASSERT(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
" (" "display:contents on anonymous content is unsupported" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5076); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5076); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5076 "display:contents on anonymous content is unsupported")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aContent->AsElement()->IsRootOfNativeAnonymousSubtree
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
" (" "display:contents on anonymous content is unsupported" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5076); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5076); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5077
5078 // FIXME(bug 1588477): <svg:text>'s TextNodeCorrespondenceRecorder has
5079 // trouble with everything that looks like display: contents.
5080 if (withinSVGText) {
5081 return;
5082 }
5083
5084 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5085 *aComputedStyle, PseudoStyleType::Before,
5086 aItems);
5087
5088 FlattenedChildIterator iter(aContent);
5089 InsertionPoint insertion(aParentFrame, aContent);
5090 for (nsIContent* child = iter.GetNextChild(); child;
5091 child = iter.GetNextChild()) {
5092 AddFrameConstructionItems(aState, child, aSuppressWhiteSpaceOptimizations,
5093 *aComputedStyle, insertion, aItems, aFlags);
5094 }
5095 aItems.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
5096
5097 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5098 *aComputedStyle, PseudoStyleType::After, aItems);
5099 return;
5100 }
5101
5102 nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
5103 if (ShouldSuppressFrameForSelect(parent, *aContent)) {
5104 return;
5105 }
5106
5107 if (aContent->IsHTMLElement(nsGkAtoms::legend) && aParentFrame) {
5108 const nsFieldSetFrame* const fs = GetFieldSetFrameFor(aParentFrame);
5109 if (fs && !fs->GetLegend() && !aState.mHasRenderedLegend &&
5110 !aComputedStyle->StyleDisplay()->IsFloatingStyle() &&
5111 !aComputedStyle->StyleDisplay()->IsAbsolutelyPositionedStyle()) {
5112 aState.mHasRenderedLegend = true;
5113 aFlags += ItemFlag::IsForRenderedLegend;
5114 }
5115 }
5116
5117 const FrameConstructionData* const data =
5118 FindDataForContent(*aContent, *aComputedStyle, aParentFrame, aFlags);
5119 if (!data) {
5120 return;
5121 }
5122 const uint32_t bits = data->mBits;
5123 if (bits & FCDATA_SUPPRESS_FRAME0x40) {
5124 return;
5125 }
5126 // Create our shadow tree lazily if needed.
5127 // NOTE(emilio): This is rather hacky, we should ideally remove this and make
5128 // shadow tree creation faster, see bug 2017005.
5129 if (const RefPtr input = HTMLInputElement::FromNode(aContent)) {
5130 if (auto* sr = input->CreateShadowTreeFromLayoutIfNeeded()) {
5131 StyleNewChildRange(sr->GetFirstChild(), nullptr);
5132 }
5133 }
5134
5135 const bool canHavePageBreak =
5136 aFlags.contains(ItemFlag::AllowPageBreak) &&
5137 aState.mPresContext->IsPaginated() &&
5138 !display.IsAbsolutelyPositionedStyle() &&
5139 !(aParentFrame && aParentFrame->IsFlexOrGridContainer()) &&
5140 !(bits & FCDATA_IS_TABLE_PART0x800) && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5141 if (canHavePageBreak && display.BreakBefore()) {
5142 AppendPageBreakItem(aContent, aItems);
5143 }
5144
5145 if (!item) {
5146 item = aItems.AppendItem(this, data, aContent, do_AddRef(aComputedStyle),
5147 aSuppressWhiteSpaceOptimizations);
5148 if (aFlags.contains(ItemFlag::IsForRenderedLegend)) {
5149 item->mIsRenderedLegend = true;
5150 }
5151 }
5152 item->mIsText = !aContent->IsElement();
5153 item->mIsGeneratedContent = isGeneratedContent;
5154 item->mIsSharedGeneratedContent =
5155 isGeneratedContent && aState.mCreatingExtraFrames;
5156 if (isGeneratedContent) {
5157 // We need to keep this alive until the frame takes ownership.
5158 // This corresponds to the Release in ConstructFramesFromItem.
5159 item->mContent->AddRef();
5160 }
5161
5162 if (canHavePageBreak && display.BreakAfter()) {
5163 AppendPageBreakItem(aContent, aItems);
5164 }
5165
5166 if (bits & FCDATA_IS_INLINE0x1000) {
5167 // To correctly set item->mIsAllInline we need to build up our child items
5168 // right now.
5169 BuildInlineChildItems(aState, *item,
5170 aFlags.contains(ItemFlag::IsWithinSVGText),
5171 aFlags.contains(ItemFlag::AllowTextPathChild));
5172 item->mIsBlock = false;
5173 } else {
5174 // Compute a boolean isInline which is guaranteed to be false for blocks
5175 // (but may also be false for some inlines).
5176 const bool isInline =
5177 // Table-internal things are inline-outside if and only if they're kids
5178 // of inlines, since they'll trigger construction of inline-table
5179 // pseudos.
5180 ((bits & FCDATA_IS_TABLE_PART0x800) &&
5181 (!aParentFrame || // No aParentFrame means inline
5182 aParentFrame->StyleDisplay()->IsInlineFlow())) ||
5183 // Things that are inline-outside but aren't inline frames are inline
5184 display.IsInlineOutsideStyle();
5185
5186 // Set mIsAllInline conservatively. It just might be that even an inline
5187 // that has mIsAllInline false doesn't need an {ib} split. So this is just
5188 // an optimization to keep from doing too much work in cases when we can
5189 // show that mIsAllInline is true..
5190 item->mIsAllInline =
5191 isInline ||
5192 // Figure out whether we're guaranteed this item will be out of flow.
5193 // This is not a precise test, since one of our ancestor inlines might
5194 // add an absolute containing block (if it's relatively positioned) when
5195 // there wasn't such a containing block before. But it's conservative
5196 // in the sense that anything that will really end up as an in-flow
5197 // non-inline will test false here. In other words, if this test is
5198 // true we're guaranteed to be inline; if it's false we don't know what
5199 // we'll end up as.
5200 //
5201 // If we make this test precise, we can remove some of the code dealing
5202 // with the imprecision in ConstructInline and adjust the comments on
5203 // mIsAllInline and mIsBlock in the header.
5204 (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
5205 aState.GetGeometricParent(display, nullptr));
5206
5207 // Set mIsBlock conservatively. It's OK to set it false for some real
5208 // blocks, but not OK to set it true for things that aren't blocks. Since
5209 // isOutOfFlow might be false even in cases when the frame will end up
5210 // out-of-flow, we can't use it here. But we _can_ say that the frame will
5211 // for sure end up in-flow if it's not floated or absolutely positioned.
5212 item->mIsBlock = !isInline && !display.IsAbsolutelyPositionedStyle() &&
5213 !display.IsFloatingStyle() && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5214 }
5215
5216 if (item->mIsAllInline) {
5217 aItems.InlineItemAdded();
5218 } else if (item->mIsBlock) {
5219 aItems.BlockItemAdded();
5220 }
5221}
5222
5223/**
5224 * Return true if the frame construction item pointed to by aIter will
5225 * create a frame adjacent to a line boundary in the frame tree, and that
5226 * line boundary is induced by a content node adjacent to the frame's
5227 * content node in the content tree. The latter condition is necessary so
5228 * that ContentAppended/ContentInserted/ContentWillBeRemoved can easily find any
5229 * text nodes that were suppressed here.
5230 */
5231bool nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) {
5232 if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5233 return false;
5234 }
5235
5236 if (aIter.AtStart()) {
5237 if (aIter.List()->HasLineBoundaryAtStart() &&
5238 !aIter.item().mContent->GetPreviousSibling()) {
5239 return true;
5240 }
5241 } else {
5242 FCItemIterator prev = aIter;
5243 prev.Prev();
5244 if (prev.item().IsLineBoundary() &&
5245 !prev.item().mSuppressWhiteSpaceOptimizations &&
5246 aIter.item().mContent->GetPreviousSibling() == prev.item().mContent) {
5247 return true;
5248 }
5249 }
5250
5251 FCItemIterator next = aIter;
5252 next.Next();
5253 if (next.IsDone()) {
5254 if (aIter.List()->HasLineBoundaryAtEnd() &&
5255 !aIter.item().mContent->GetNextSibling()) {
5256 return true;
5257 }
5258 } else {
5259 if (next.item().IsLineBoundary() &&
5260 !next.item().mSuppressWhiteSpaceOptimizations &&
5261 aIter.item().mContent->GetNextSibling() == next.item().mContent) {
5262 return true;
5263 }
5264 }
5265
5266 return false;
5267}
5268
5269void nsCSSFrameConstructor::ConstructFramesFromItem(
5270 nsFrameConstructorState& aState, FCItemIterator& aIter,
5271 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
5272 FrameConstructionItem& item = aIter.item();
5273 ComputedStyle* computedStyle = item.mComputedStyle;
5274 if (item.mIsText) {
5275 // If this is collapsible whitespace next to a line boundary,
5276 // don't create a frame. item.IsWhitespace() also sets the
5277 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5278 // end up creating a frame, nsTextFrame::Init will clear the flag.)
5279 // We don't do this for generated content, because some generated
5280 // text content is empty text nodes that are about to be initialized.
5281 // (We check mAdditionalStateBits because only the generated content
5282 // container's frame construction item is marked with
5283 // mIsGeneratedContent, and we might not have an aParentFrame.)
5284 // We don't do it for content that may have Shadow DOM siblings / insertion
5285 // points, because they make it difficult to correctly create the frame due
5286 // to dynamic changes.
5287 // We don't do it for SVG text, since we might need to position and
5288 // measure the white space glyphs due to x/y/dx/dy attributes.
5289 if (AtLineBoundary(aIter) &&
5290 !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
5291 aIter.List()->ParentHasNoShadowDOM() &&
5292 !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
5293 (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) &&
5294 !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT0x80000) &&
5295 !mAlwaysCreateFramesForIgnorableWhitespace &&
5296 item.IsWhitespace(aState)) {
5297 return;
5298 }
5299
5300 ConstructTextFrame(item.mFCData, aState, item.mContent, aParentFrame,
5301 computedStyle, aFrameList);
5302 return;
5303 }
5304
5305 AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
5306 if (item.mIsGeneratedContent) {
5307 // Ensure that frames created here are all tagged with
5308 // NS_FRAME_GENERATED_CONTENT.
5309 aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
5310 }
5311
5312 // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5313 ConstructFrameFromItemInternal(item, aState, aParentFrame, aFrameList);
5314
5315 if (item.mIsGeneratedContent) {
5316 // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
5317 // The frame owns the generated content now.
5318 item.mContent->Release();
5319
5320 // Now that we've passed ownership of item.mContent to the frame, unset
5321 // our generated content flag so we don't release or unbind it ourselves.
5322 item.mIsGeneratedContent = false;
5323 }
5324}
5325
5326nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
5327 nsIFrame* aFrame, ContainingBlockType aType) {
5328 // Starting with aFrame, look for a frame that is absolutely positioned or
5329 // relatively positioned (and transformed, if aType is FIXED)
5330 for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
5331 if (frame->IsMathMLFrame()) {
5332 // If it's mathml, bail out -- no absolute positioning out from inside
5333 // mathml frames. Note that we don't make this part of the loop
5334 // condition because of the stuff at the end of this method...
5335 return nullptr;
5336 }
5337
5338 // Look for the ICB.
5339 if (aType == FIXED_POS &&
5340 (frame->IsViewportFrame() || frame->IsPageContentFrame())) {
5341 return static_cast<nsContainerFrame*>(frame);
5342 }
5343
5344 // If the frame is positioned, we will probably return it as the containing
5345 // block (see the exceptions below). Otherwise, we'll start looking at the
5346 // parent frame, unless we're dealing with a scrollframe.
5347 // Scrollframes are special since they're not positioned, but their
5348 // scrolledframe might be. So, we need to check this special case to return
5349 // the correct containing block (the scrolledframe) in that case.
5350 // If we're looking for a fixed-pos containing block and the frame is
5351 // not transformed, skip it.
5352 if (!frame->IsAbsPosContainingBlock()) {
5353 continue;
5354 }
5355 if (aType == FIXED_POS && !frame->IsFixedPosContainingBlock()) {
5356 continue;
5357 }
5358 nsIFrame* absPosCBCandidate = frame;
5359 if (absPosCBCandidate->IsFieldSetFrame()) {
5360 absPosCBCandidate =
5361 static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
5362 if (!absPosCBCandidate) {
5363 continue;
5364 }
5365 }
5366 if (absPosCBCandidate->IsScrollContainerOrSubclass()) {
5367 ScrollContainerFrame* scrollContainerFrame =
5368 do_QueryFrame(absPosCBCandidate);
5369 absPosCBCandidate = scrollContainerFrame->GetScrolledFrame();
5370 if (!absPosCBCandidate) {
5371 continue;
5372 }
5373 }
5374 // Only first continuations or first IB-split siblings can be containing
5375 // blocks.
5376 absPosCBCandidate =
5377 nsLayoutUtils::FirstContinuationOrIBSplitSibling(absPosCBCandidate);
5378 // Is the frame really an absolute container?
5379 if (!absPosCBCandidate->IsAbsoluteContainer()) {
5380 continue;
5381 }
5382
5383 // For tables, skip the inner frame and consider the table wrapper frame.
5384 if (absPosCBCandidate->IsTableFrame()) {
5385 continue;
5386 }
5387 // For table wrapper frames, we can just return absPosCBCandidate.
5388 MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(absPosCBCandidate),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((nsContainerFrame*)do_QueryFrame(absPosCBCandidate))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((nsContainerFrame*)do_QueryFrame(absPosCBCandidate))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
" (" "abs.pos. containing block must be nsContainerFrame sub-class"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5389
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5389); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5389 "abs.pos. containing block must be nsContainerFrame sub-class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((nsContainerFrame*)do_QueryFrame(absPosCBCandidate))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((nsContainerFrame*)do_QueryFrame(absPosCBCandidate))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
" (" "abs.pos. containing block must be nsContainerFrame sub-class"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5389
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5389); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5390 return static_cast<nsContainerFrame*>(absPosCBCandidate);
5391 }
5392
5393 MOZ_ASSERT(aType != FIXED_POS, "no ICB in this frame tree?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aType != FIXED_POS)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aType != FIXED_POS))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aType != FIXED_POS"
" (" "no ICB in this frame tree?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5393); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aType != FIXED_POS"
") (" "no ICB in this frame tree?" ")"); do { MOZ_CrashSequence
(__null, 5393); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5394
5395 // It is possible for the search for the containing block to fail, because
5396 // no absolute container can be found in the parent chain. In those cases,
5397 // we fall back to the document element's containing block.
5398 return mDocElementContainingBlock;
5399}
5400
5401nsContainerFrame* nsCSSFrameConstructor::GetFloatContainingBlock(
5402 nsIFrame* aFrame) {
5403 // Starting with aFrame, look for a frame that is a float containing block.
5404 // If we hit a frame which prevents its descendants from floating, bail out.
5405 // The logic here needs to match the logic in MaybePushFloatContainingBlock().
5406 for (nsIFrame* containingBlock = aFrame;
5407 containingBlock && !ShouldSuppressFloatingOfDescendants(containingBlock);
5408 containingBlock = containingBlock->GetParent()) {
5409 if (containingBlock->IsFloatContainingBlock()) {
5410 MOZ_ASSERT((nsContainerFrame*)do_QueryFrame(containingBlock),do { static_assert( mozilla::detail::AssertionConditionType<
decltype((nsContainerFrame*)do_QueryFrame(containingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((nsContainerFrame*)do_QueryFrame(containingBlock))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("(nsContainerFrame*)do_QueryFrame(containingBlock)"
" (" "float containing block must be nsContainerFrame sub-class"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5411
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5411); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5411 "float containing block must be nsContainerFrame sub-class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype((nsContainerFrame*)do_QueryFrame(containingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((nsContainerFrame*)do_QueryFrame(containingBlock))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("(nsContainerFrame*)do_QueryFrame(containingBlock)"
" (" "float containing block must be nsContainerFrame sub-class"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5411
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5411); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5412 return static_cast<nsContainerFrame*>(containingBlock);
5413 }
5414 }
5415
5416 // If we didn't find a containing block, then there just isn't
5417 // one.... return null
5418 return nullptr;
5419}
5420
5421/**
5422 * Finds the right parent frame to append content to aParentFrame.
5423 *
5424 * Cannot return or receive null.
5425 */
5426static nsContainerFrame* ContinuationToAppendTo(
5427 nsContainerFrame* aParentFrame) {
5428 MOZ_ASSERT(aParentFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParentFrame))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aParentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5428); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 5428); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5429
5430 if (IsFramePartOfIBSplit(aParentFrame)) {
5431 // If the frame we are manipulating is a ib-split frame (that is, one that's
5432 // been created as a result of a block-in-inline situation) then we need to
5433 // append to the last ib-split sibling, not to the frame itself.
5434 //
5435 // Always make sure to look at the last continuation of the frame for the
5436 // {ib} case, even if that continuation is empty.
5437 //
5438 // We don't do this for the non-ib-split-frame case, since in the other
5439 // cases appending to the last nonempty continuation is fine and in fact not
5440 // doing that can confuse code that doesn't know to pull kids from
5441 // continuations other than its next one.
5442 return static_cast<nsContainerFrame*>(
5443 GetLastIBSplitSibling(aParentFrame)->LastContinuation());
5444 }
5445
5446 return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
5447}
5448
5449/**
5450 * This function will get the next sibling for a frame insert operation given
5451 * the parent and previous sibling. aPrevSibling may be null.
5452 */
5453static nsIFrame* GetInsertNextSibling(nsIFrame* aParentFrame,
5454 nsIFrame* aPrevSibling) {
5455 if (aPrevSibling) {
5456 return aPrevSibling->GetNextSibling();
5457 }
5458
5459 return aParentFrame->PrincipalChildList().FirstChild();
5460}
5461
5462void nsCSSFrameConstructor::AppendFramesToParent(
5463 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
5464 nsFrameList& aFrameList, nsIFrame* aPrevSibling, bool aIsRecursiveCall) {
5465 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling
(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList
().FirstChild())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame
)->PrincipalChildList().FirstChild()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
" (" "aParentFrame has a ib-split sibling with kids?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5468); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5466 !IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling
(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList
().FirstChild())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame
)->PrincipalChildList().FirstChild()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
" (" "aParentFrame has a ib-split sibling with kids?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5468); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5467 !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling
(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList
().FirstChild())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame
)->PrincipalChildList().FirstChild()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
" (" "aParentFrame has a ib-split sibling with kids?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5468); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5468 "aParentFrame has a ib-split sibling with kids?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling
(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList
().FirstChild())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame
)->PrincipalChildList().FirstChild()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
" (" "aParentFrame has a ib-split sibling with kids?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5468); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5469 MOZ_ASSERT(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
" (" "Parent and prevsibling don't match" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5470); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5470 "Parent and prevsibling don't match")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
" (" "Parent and prevsibling don't match" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5470); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5471 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) || !IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParentFrame->HasAnyStateBits
(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit
(aParentFrame)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
" (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")"); do { MOZ_CrashSequence(
__null, 5475); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5472 !aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) || !IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParentFrame->HasAnyStateBits
(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit
(aParentFrame)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
" (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")"); do { MOZ_CrashSequence(
__null, 5475); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5473 !IsFramePartOfIBSplit(aParentFrame),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) || !IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParentFrame->HasAnyStateBits
(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit
(aParentFrame)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
" (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")"); do { MOZ_CrashSequence(
__null, 5475); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5474 "We should have wiped aParentFrame in WipeContainingBlock() "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) || !IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParentFrame->HasAnyStateBits
(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit
(aParentFrame)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
" (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")"); do { MOZ_CrashSequence(
__null, 5475); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5475 "if it's part of an IB split!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) || !IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParentFrame->HasAnyStateBits
(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit
(aParentFrame)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
" (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) || !IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in WipeContainingBlock() "
"if it's part of an IB split!" ")"); do { MOZ_CrashSequence(
__null, 5475); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
5476
5477 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
5478
5479 NS_ASSERTION(nextSibling || !aParentFrame->GetNextContinuation() ||do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
5480 !aParentFrame->GetNextContinuation()do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
5481 ->PrincipalChildList()do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
5482 .FirstChild() ||do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
5483 aIsRecursiveCall,do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
5484 "aParentFrame has later continuations with kids?")do { if (!(nextSibling || !aParentFrame->GetNextContinuation
() || !aParentFrame->GetNextContinuation() ->PrincipalChildList
() .FirstChild() || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aParentFrame has later continuations with kids?", "nextSibling || !aParentFrame->GetNextContinuation() || !aParentFrame->GetNextContinuation() ->PrincipalChildList() .FirstChild() || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5484); MOZ_PretendNoReturn
(); } } while (0)
;
5485 NS_ASSERTION(do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
5486 nextSibling || !IsFramePartOfIBSplit(aParentFrame) ||do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
5487 (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) &&do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
5488 !aParentFrame->GetNextContinuation()) ||do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
5489 aIsRecursiveCall,do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
5490 "aParentFrame is not last?")do { if (!(nextSibling || !IsFramePartOfIBSplit(aParentFrame)
|| (IsInlineFrame(aParentFrame) && !GetIBSplitSibling
(aParentFrame) && !aParentFrame->GetNextContinuation
()) || aIsRecursiveCall)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aParentFrame is not last?", "nextSibling || !IsFramePartOfIBSplit(aParentFrame) || (IsInlineFrame(aParentFrame) && !GetIBSplitSibling(aParentFrame) && !aParentFrame->GetNextContinuation()) || aIsRecursiveCall"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5490); MOZ_PretendNoReturn
(); } } while (0)
;
5491
5492 // If we're inserting a list of frames at the end of the trailing inline
5493 // of an {ib} split, we may need to create additional {ib} siblings to parent
5494 // them.
5495 if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
5496 // When we get here, our frame list might start with a block. If it does
5497 // so, and aParentFrame is an inline, and it and all its previous
5498 // continuations have no siblings, then put the initial blocks from the
5499 // frame list into the previous block of the {ib} split. Note that we
5500 // didn't want to stop at the block part of the split when figuring out
5501 // initial parent, because that could screw up float parenting; it's easier
5502 // to do this little fixup here instead.
5503 if (aFrameList.NotEmpty() && aFrameList.FirstChild()->IsBlockOutside()) {
5504 // See whether our trailing inline is empty
5505 nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
5506 if (firstContinuation->PrincipalChildList().IsEmpty()) {
5507 // Our trailing inline is empty. Collect our starting blocks from
5508 // aFrameList, get the right parent frame for them, and put them in.
5509 nsFrameList blockKids =
5510 aFrameList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
5511 NS_ASSERTION(blockKids.NotEmpty(), "No blocks?")do { if (!(blockKids.NotEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "No blocks?", "blockKids.NotEmpty()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5511); MOZ_PretendNoReturn(); } } while (0)
;
5512
5513 nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
5514 prevBlock =
5515 static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
5516 NS_ASSERTION(prevBlock, "Should have previous block here")do { if (!(prevBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have previous block here"
, "prevBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5516); MOZ_PretendNoReturn(); } } while (0)
;
5517
5518 MoveChildrenTo(aParentFrame, prevBlock, blockKids);
5519 }
5520 }
5521
5522 // We want to put some of the frames into this inline frame.
5523 nsFrameList inlineKids =
5524 aFrameList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
5525
5526 if (!inlineKids.IsEmpty()) {
5527 AppendFrames(aParentFrame, FrameChildListID::Principal,
5528 std::move(inlineKids));
5529 }
5530
5531 if (!aFrameList.IsEmpty()) {
5532 nsFrameList ibSiblings;
5533 CreateIBSiblings(aState, aParentFrame,
5534 aParentFrame->IsAbsPosContainingBlock(), aFrameList,
5535 ibSiblings);
5536
5537 // Make sure to trigger reflow of the inline that used to be our
5538 // last one and now isn't anymore, since its GetSkipSides() has
5539 // changed.
5540 mPresShell->FrameNeedsReflow(aParentFrame,
5541 IntrinsicDirty::FrameAndAncestors,
5542 NS_FRAME_HAS_DIRTY_CHILDREN);
5543
5544 // Recurse so we create new ib siblings as needed for aParentFrame's
5545 // parent
5546 return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
5547 aParentFrame, true);
5548 }
5549 return;
5550 }
5551
5552 // If we're appending a list of frames to the last continuations of a
5553 // ::-moz-column-content, we may need to create column-span siblings for them.
5554 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
5555 // Extract any initial non-column-span kids, and append them to
5556 // ::-moz-column-content's child list.
5557 nsFrameList initialNonColumnSpanKids =
5558 aFrameList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
5559 AppendFrames(aParentFrame, FrameChildListID::Principal,
5560 std::move(initialNonColumnSpanKids));
5561
5562 if (aFrameList.IsEmpty()) {
5563 // No more kids to process (there weren't any column-span kids).
5564 return;
5565 }
5566
5567 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
5568 aState, aParentFrame, aFrameList,
5569 // Column content should never be a absolute/fixed positioned containing
5570 // block. Pass nullptr as aPositionedFrame.
5571 nullptr);
5572
5573 nsContainerFrame* columnSetWrapper = aParentFrame->GetParent();
5574 while (!columnSetWrapper->IsColumnSetWrapperFrame()) {
5575 columnSetWrapper = columnSetWrapper->GetParent();
5576 }
5577 MOZ_ASSERT(columnSetWrapper,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSetWrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSetWrapper))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("columnSetWrapper"
" (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5578
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5578); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5578 "No ColumnSetWrapperFrame ancestor for -moz-column-content?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSetWrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSetWrapper))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("columnSetWrapper"
" (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5578
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5578); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5579
5580 FinishBuildingColumns(aState, columnSetWrapper, aParentFrame,
5581 columnSpanSiblings);
5582
5583 MOZ_ASSERT(columnSpanSiblings.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSpanSiblings.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSpanSiblings.IsEmpty()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"columnSpanSiblings.IsEmpty()" " (" "The column-span siblings should be moved to the proper place!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5584
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5584); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5584 "The column-span siblings should be moved to the proper place!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSpanSiblings.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSpanSiblings.IsEmpty()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"columnSpanSiblings.IsEmpty()" " (" "The column-span siblings should be moved to the proper place!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5584
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5584); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5585 return;
5586 }
5587
5588 // Insert the frames after our aPrevSibling
5589 InsertFrames(aParentFrame, FrameChildListID::Principal, aPrevSibling,
5590 std::move(aFrameList));
5591}
5592
5593template <nsCSSFrameConstructor::SiblingDirection aDirection>
5594nsIFrame* nsCSSFrameConstructor::FindSiblingInternal(
5595 FlattenedChildIterator& aIter) {
5596 auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
5597 return aDirection == SiblingDirection::Forward ? aIter.GetNextChild()
5598 : aIter.GetPreviousChild();
5599 };
5600
5601 auto getInsideMarkerFrame = [](const nsIContent* aContent) -> nsIFrame* {
5602 auto* marker = nsLayoutUtils::GetMarkerFrame(aContent);
5603 const bool isInsideMarker =
5604 marker && marker->GetInFlowParent()->StyleList()->mListStylePosition ==
5605 StyleListStylePosition::Inside;
5606 return isInsideMarker ? marker : nullptr;
5607 };
5608
5609 auto getNearPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5610 if (aDirection == SiblingDirection::Forward) {
5611 if (auto* backdrop = nsLayoutUtils::GetBackdropFrame(aContent)) {
5612 return backdrop;
5613 }
5614 if (auto* marker = getInsideMarkerFrame(aContent)) {
5615 return marker;
5616 }
5617 return nsLayoutUtils::GetBeforeFrame(aContent);
5618 }
5619 return nsLayoutUtils::GetAfterFrame(aContent);
5620 };
5621
5622 auto getFarPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5623 if (aDirection == SiblingDirection::Forward) {
5624 if (auto* pickerIcon = nsLayoutUtils::GetPickerIconFrame(aContent)) {
5625 return pickerIcon;
5626 }
5627 return nsLayoutUtils::GetAfterFrame(aContent);
5628 }
5629 if (auto* before = nsLayoutUtils::GetBeforeFrame(aContent)) {
5630 return before;
5631 }
5632 if (auto* marker = getInsideMarkerFrame(aContent)) {
5633 return marker;
5634 }
5635 return nsLayoutUtils::GetBackdropFrame(aContent);
5636 };
5637
5638 while (nsIContent* sibling = nextDomSibling(aIter)) {
5639 // NOTE(emilio): It's important to check GetPrimaryFrame() before
5640 // IsDisplayContents to get the correct insertion point when multiple
5641 // siblings go from display: non-none to display: contents.
5642 if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
5643 // The rendered legend check is needed because it is conceptually out of
5644 // flow. There can only be one rendered legend at a time, and we reframe
5645 // when that changes, so this is ok. Table captions are a similar case,
5646 // but there can be multiple of them and they instead get pulled out (and
5647 // the sibling fixed up) after building the frame list.
5648 if (!primaryFrame->IsRenderedLegend()) [[likely]] {
5649 return primaryFrame;
5650 }
5651 }
5652
5653 if (IsDisplayContents(sibling)) {
5654 if (nsIFrame* frame = getNearPseudo(sibling)) {
5655 return frame;
5656 }
5657
5658 const bool startFromBeginning = aDirection == SiblingDirection::Forward;
5659 FlattenedChildIterator iter(sibling, startFromBeginning);
5660 nsIFrame* sibling = FindSiblingInternal<aDirection>(iter);
5661 if (sibling) {
5662 return sibling;
5663 }
5664 }
5665 }
5666
5667 MOZ_ASSERT(aIter.ParentNode()->IsContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIter.ParentNode()->IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aIter.ParentNode()->IsContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aIter.ParentNode()->IsContent()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5667); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.ParentNode()->IsContent()"
")"); do { MOZ_CrashSequence(__null, 5667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5668 return getFarPseudo(aIter.ParentNode()->AsContent());
5669}
5670
5671nsIFrame* nsCSSFrameConstructor::AdjustSiblingFrame(
5672 nsIFrame* aSibling, SiblingDirection aDirection) {
5673 if (!aSibling) {
5674 return nullptr;
5675 }
5676
5677 if (aSibling->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
5678 aSibling = aSibling->GetPlaceholderFrame();
5679 MOZ_ASSERT(aSibling)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSibling)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSibling))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aSibling", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSibling" ")"
); do { MOZ_CrashSequence(__null, 5679); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5680 }
5681
5682 MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aSibling->GetPrevContinuation())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aSibling->GetPrevContinuation
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aSibling->GetPrevContinuation()" " (" "How?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5682); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aSibling->GetPrevContinuation()"
") (" "How?" ")"); do { MOZ_CrashSequence(__null, 5682); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5683 if (aDirection == SiblingDirection::Backward) {
5684 // The frame may be a ib-split frame (a split inline frame that contains a
5685 // block). Get the last part of that split.
5686 if (IsFramePartOfIBSplit(aSibling)) {
5687 aSibling = GetLastIBSplitSibling(aSibling);
5688 }
5689
5690 // The frame may have a continuation. If so, we want the last
5691 // non-overflow-container continuation as our previous sibling.
5692 aSibling = aSibling->GetTailContinuation();
5693 }
5694
5695 return aSibling;
5696}
5697
5698nsIFrame* nsCSSFrameConstructor::FindPreviousSibling(
5699 const FlattenedChildIterator& aIter) {
5700 return AdjustSiblingFrame(FindSibling<SiblingDirection::Backward>(aIter),
5701 SiblingDirection::Backward);
5702}
5703
5704nsIFrame* nsCSSFrameConstructor::FindNextSibling(
5705 const FlattenedChildIterator& aIter) {
5706 return AdjustSiblingFrame(FindSibling<SiblingDirection::Forward>(aIter),
5707 SiblingDirection::Forward);
5708}
5709
5710template <nsCSSFrameConstructor::SiblingDirection aDirection>
5711nsIFrame* nsCSSFrameConstructor::FindSibling(
5712 const FlattenedChildIterator& aIter) {
5713 FlattenedChildIterator siblingIter = aIter;
5714 nsIFrame* sibling = FindSiblingInternal<aDirection>(siblingIter);
5715 if (sibling) {
5716 return sibling;
5717 }
5718
5719 // Our siblings (if any) do not have a frame to guide us. The frame for the
5720 // target content should be inserted whereever a frame for the container would
5721 // be inserted. This is needed when inserting into display: contents nodes.
5722 const nsIContent* current = aIter.ParentNode()->AsContent();
5723 while (IsDisplayContents(current)) {
5724 const nsIContent* parent = current->GetFlattenedTreeParent();
5725 MOZ_ASSERT(parent, "No display: contents on the root")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(parent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("parent" " (" "No display: contents on the root"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5725
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "No display: contents on the root"
")"); do { MOZ_CrashSequence(__null, 5725); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5726
5727 FlattenedChildIterator iter(parent);
5728 iter.Seek(current);
5729 sibling = FindSiblingInternal<aDirection>(iter);
5730 if (sibling) {
5731 return sibling;
5732 }
5733
5734 current = parent;
5735 }
5736
5737 return nullptr;
5738}
5739
5740nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
5741 InsertionPoint* aInsertion, nsIContent* aChild, bool* aIsAppend) {
5742 MOZ_ASSERT(aInsertion->mParentFrame, "Must have parent frame to start with")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInsertion->mParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aInsertion->mParentFrame)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aInsertion->mParentFrame"
" (" "Must have parent frame to start with" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInsertion->mParentFrame"
") (" "Must have parent frame to start with" ")"); do { MOZ_CrashSequence
(__null, 5742); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5743
5744 *aIsAppend = false;
5745
5746 // Find the frame that precedes the insertion point.
5747 FlattenedChildIterator iter(aInsertion->mContainer);
5748 if (!aChild->IsRootOfNativeAnonymousSubtree()) {
5749 // The check for IsRootOfNativeAnonymousSubtree() is because editor is
5750 // severely broken and calls us directly for native anonymous
5751 // nodes that it creates.
5752 iter.Seek(aChild);
5753 } else {
5754 // Prime the iterator for the call to FindPreviousSibling.
5755 (void)iter.GetNextChild();
5756 MOZ_ASSERT(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
" (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5758); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5757 "Someone passed native anonymous content directly into frame "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
" (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5758); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5758 "construction. Stop doing that!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->GetProperty(nsGkAtoms::restylableAnonymousNode
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
" (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5758); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5759 }
5760
5761 // Note that FindPreviousSibling is passed the iterator by value, so that
5762 // the later usage of the iterator starts from the same place.
5763 nsIFrame* prevSibling = FindPreviousSibling(iter);
5764
5765 // Now, find the geometric parent so that we can handle continuations
5766 // properly. Use the prev sibling if we have it; otherwise use the next
5767 // sibling.
5768 if (prevSibling) {
5769 aInsertion->mParentFrame =
5770 prevSibling->GetParent()->GetContentInsertionFrame();
5771
5772 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5773 // Special-case anonymous flex / grid items: Elements are blockified
5774 // inside those containers, so the anonymous item is unlikely to be the
5775 // right parent unless we're inserting a non-whitespace text-node.
5776 //
5777 // If we guess wrong, we catch this in WipeContainingBlock, but with a
5778 // performance penalty (and sometimes correctness too, see bug 2014986).
5779 //
5780 // TODO(emilio): Are there other situations where this is worth doing
5781 // (some table anon boxes or something?). Seems hard to do at this stage
5782 // where we still don't _quite_ know the details of what aChild is (in or
5783 // out of flow, display inside or outside...). Maybe WipeContainingBlock
5784 // should be able to fix-up the insertion point at the last minute? But
5785 // that seems more sketchy since some code does rely on looking at the
5786 // insertion point to decide what to construct.
5787 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5788 if (!prevSibling->GetNextSibling() &&
5789 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5790 prevSibling = aInsertion->mParentFrame->GetTailContinuation();
5791 aInsertion->mParentFrame = prevSibling->GetParent();
5792 }
5793 }
5794
5795 *aIsAppend =
5796 !::GetInsertNextSibling(aInsertion->mParentFrame, prevSibling) &&
5797 !nsLayoutUtils::GetNextContinuationOrIBSplitSibling(
5798 aInsertion->mParentFrame) &&
5799 !IsWrapperPseudo(aInsertion->mParentFrame);
5800 } else if (nsIFrame* nextSibling = FindNextSibling(iter)) {
5801 // If there is no previous sibling, then find the frame that follows
5802 aInsertion->mParentFrame =
5803 nextSibling->GetParent()->GetContentInsertionFrame();
5804 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5805 // See the prevSibling special-case above.
5806 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5807 if (!nextSibling->GetPrevSibling() &&
5808 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5809 aInsertion->mParentFrame =
5810 aInsertion->mParentFrame->FirstContinuation()->GetParent();
5811 }
5812 }
5813 } else {
5814 // No previous or next sibling, so treat this like an appended frame.
5815 *aIsAppend = true;
5816
5817 aInsertion->mParentFrame =
5818 ::ContinuationToAppendTo(aInsertion->mParentFrame);
5819
5820 prevSibling = aInsertion->mParentFrame->PrincipalChildList().LastChild();
5821 }
5822
5823 return prevSibling;
5824}
5825
5826nsContainerFrame* nsCSSFrameConstructor::GetContentInsertionFrameFor(
5827 nsIContent* aContent) {
5828 nsIFrame* frame;
5829 while (!(frame = aContent->GetPrimaryFrame())) {
5830 if (!IsDisplayContents(aContent)) {
5831 return nullptr;
5832 }
5833
5834 aContent = aContent->GetFlattenedTreeParent();
5835 if (!aContent) {
5836 return nullptr;
5837 }
5838 }
5839
5840 nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
5841
5842 NS_ASSERTION(!insertionFrame || insertionFrame == frame || !frame->IsLeaf(),do { if (!(!insertionFrame || insertionFrame == frame || !frame
->IsLeaf())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The insertion frame is the primary frame or the primary frame "
"isn't a leaf", "!insertionFrame || insertionFrame == frame || !frame->IsLeaf()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5844); MOZ_PretendNoReturn
(); } } while (0)
5843 "The insertion frame is the primary frame or the primary frame "do { if (!(!insertionFrame || insertionFrame == frame || !frame
->IsLeaf())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The insertion frame is the primary frame or the primary frame "
"isn't a leaf", "!insertionFrame || insertionFrame == frame || !frame->IsLeaf()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5844); MOZ_PretendNoReturn
(); } } while (0)
5844 "isn't a leaf")do { if (!(!insertionFrame || insertionFrame == frame || !frame
->IsLeaf())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The insertion frame is the primary frame or the primary frame "
"isn't a leaf", "!insertionFrame || insertionFrame == frame || !frame->IsLeaf()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5844); MOZ_PretendNoReturn
(); } } while (0)
;
5845
5846 return insertionFrame;
5847}
5848
5849static bool IsSpecialFramesetChild(nsIContent* aContent) {
5850 // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
5851 return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
5852}
5853
5854static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode);
5855
5856void nsCSSFrameConstructor::AddTextItemIfNeeded(
5857 nsFrameConstructorState& aState, const ComputedStyle& aParentStyle,
5858 const InsertionPoint& aInsertion, nsIContent* aPossibleTextContent,
5859 FrameConstructionItemList& aItems) {
5860 MOZ_ASSERT(aPossibleTextContent, "Must have node")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPossibleTextContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPossibleTextContent))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aPossibleTextContent"
" (" "Must have node" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleTextContent"
") (" "Must have node" ")"); do { MOZ_CrashSequence(__null, 5860
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5861 if (!aPossibleTextContent->IsText() ||
5862 !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5863 aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
5864 // Not text, or not suppressed due to being all-whitespace (if it were being
5865 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5866 // going to be reframed anyway.
5867 return;
5868 }
5869 MOZ_ASSERT(!aPossibleTextContent->GetPrimaryFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPossibleTextContent->GetPrimaryFrame())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aPossibleTextContent->GetPrimaryFrame()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aPossibleTextContent->GetPrimaryFrame()"
" (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5870
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5870 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPossibleTextContent->GetPrimaryFrame())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aPossibleTextContent->GetPrimaryFrame()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aPossibleTextContent->GetPrimaryFrame()"
" (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5870
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5871 AddFrameConstructionItems(aState, aPossibleTextContent, false, aParentStyle,
5872 aInsertion, aItems);
5873}
5874
5875void nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent) {
5876 if (!aContent->IsText() ||
5877 !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5878 aContent->HasFlag(NODE_NEEDS_FRAME)) {
5879 // Not text, or not suppressed due to being all-whitespace (if it were being
5880 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5881 // going to be reframed anyway.
5882 return;
5883 }
5884 MOZ_ASSERT(!aContent->GetPrimaryFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aContent->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aContent->GetPrimaryFrame()" " (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5885
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5885); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5885 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aContent->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aContent->GetPrimaryFrame()" " (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5885
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5885); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5886 ContentInserted(aContent, InsertionKind::Async);
5887}
5888
5889#ifdef DEBUG1
5890void nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(
5891 nsIContent* aParent) {
5892 // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
5893 // we want to assert, but leaf frames that process their own children and may
5894 // ignore anonymous children (eg framesets) make this complicated. So we set
5895 // these two booleans if we encounter these situations and unset them if we
5896 // hit a node with a leaf frame.
5897 //
5898 // It's fine if one of node without primary frame is in a display:none
5899 // subtree.
5900 //
5901 // Also, it's fine if one of the nodes without primary frame is a display:
5902 // contents node.
5903 bool noPrimaryFrame = false;
5904 bool needsFrameBitSet = false;
5905 nsIContent* content = aParent;
5906 while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
5907 if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
5908 noPrimaryFrame = needsFrameBitSet = false;
5909 }
5910 if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
5911 noPrimaryFrame = !IsDisplayContents(content);
5912 }
5913 if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
5914 needsFrameBitSet = true;
5915 }
5916
5917 content = content->GetFlattenedTreeParent();
5918 }
5919 if (content && content->GetPrimaryFrame() &&
5920 content->GetPrimaryFrame()->IsLeaf()) {
5921 noPrimaryFrame = needsFrameBitSet = false;
5922 }
5923 MOZ_ASSERT(!noPrimaryFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!noPrimaryFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!noPrimaryFrame))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!noPrimaryFrame"
" (" "Ancestors of nodes with frames to be " "constructed lazily should have frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5925
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5924 "Ancestors of nodes with frames to be "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!noPrimaryFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!noPrimaryFrame))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!noPrimaryFrame"
" (" "Ancestors of nodes with frames to be " "constructed lazily should have frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5925
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5925 "constructed lazily should have frames")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!noPrimaryFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!noPrimaryFrame))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!noPrimaryFrame"
" (" "Ancestors of nodes with frames to be " "constructed lazily should have frames"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5925
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5926 MOZ_ASSERT(!needsFrameBitSet,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!needsFrameBitSet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!needsFrameBitSet))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!needsFrameBitSet"
" (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5928
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5928); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5927 "Ancestors of nodes with frames to be "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!needsFrameBitSet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!needsFrameBitSet))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!needsFrameBitSet"
" (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5928
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5928); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5928 "constructed lazily should not have NEEDS_FRAME bit set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!needsFrameBitSet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!needsFrameBitSet))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!needsFrameBitSet"
" (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 5928
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5928); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5929}
5930#endif
5931
5932// Returns true if this operation can be lazy, false if not.
5933//
5934// NOTE(emilio): This function assumes that the flattened tree
5935// parent of all the appended children is the same, which holds because this
5936// gets called after GetRangeInsertionPoint which otherwise splits the range.
5937void nsCSSFrameConstructor::ConstructLazily(nsIContent* aStartChild,
5938 nsIContent* aEndChild) {
5939 MOZ_ASSERT(aStartChild->GetParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartChild->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartChild->GetParent())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aStartChild->GetParent()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5939); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStartChild->GetParent()" ")"); do { MOZ_CrashSequence
(__null, 5939); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5940
5941 // We can construct lazily; just need to set suitable bits in the content
5942 // tree.
5943 Element* parent = aStartChild->GetFlattenedTreeParentElement();
5944 if (!parent) {
5945 // Not part of the flat tree, nothing to do.
5946 return;
5947 }
5948
5949 if (Servo_Element_IsDisplayNone(parent)) {
5950 // Nothing to do either.
5951 //
5952 // FIXME(emilio): This should be an assert, except for weird <frameset>
5953 // stuff that does its own frame construction. Such an assert would fire in
5954 // layout/style/crashtests/1411478.html, for example.
5955 return;
5956 }
5957
5958 // Set NODE_NEEDS_FRAME on the new nodes.
5959 for (nsIContent* child = aStartChild; child != aEndChild;
5960 child = child->GetNextSibling()) {
5961 NS_ASSERTION(!child->GetPrimaryFrame(),do { if (!(!child->GetPrimaryFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5962); MOZ_PretendNoReturn
(); } } while (0)
5962 "setting NEEDS_FRAME on a node that already has a frame?")do { if (!(!child->GetPrimaryFrame())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5962); MOZ_PretendNoReturn
(); } } while (0)
;
5963 child->SetFlags(NODE_NEEDS_FRAME);
5964 }
5965
5966 CheckBitsForLazyFrameConstruction(parent);
5967 parent->NoteDescendantsNeedFramesForServo();
5968}
5969
5970void nsCSSFrameConstructor::IssueShadowHostChildrenInsertNotifications(
5971 const ShadowRoot& aShadow, nsIContent* aStartChild, nsIContent* aEndChild,
5972 InsertionKind aInsertionKind) {
5973 // When slots are named we're guaranteed that siblings in the DOM tree are
5974 // also siblings in the flat tree as long as they share the slot.
5975 const bool namedSlots = aShadow.SlotAssignment() == SlotAssignmentMode::Named;
5976 nsIContent* runStart = aStartChild;
5977 do {
5978 nsIContent* runEnd = runStart->GetNextSibling();
5979 auto* slot = runStart->GetAssignedSlot();
5980 if (!slot || namedSlots) {
5981 while (runEnd != aEndChild && runEnd->GetAssignedSlot() == slot) {
5982 runEnd = runEnd->GetNextSibling();
5983 }
5984 }
5985 ContentRangeInserted(runStart, runEnd, aInsertionKind,
5986 SameInsertionPoint::Yes);
5987 runStart = runEnd;
5988 } while (runStart != aEndChild);
5989}
5990
5991nsCSSFrameConstructor::InsertionPoint
5992nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
5993 nsIContent* aEndChild,
5994 InsertionKind aInsertionKind) {
5995 MOZ_ASSERT(aStartChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartChild))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStartChild", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
")"); do { MOZ_CrashSequence(__null, 5995); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5996 MOZ_ASSERT(aStartChild->GetParentNode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartChild->GetParentNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartChild->GetParentNode
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aStartChild->GetParentNode()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 5996); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5997
5998 if (auto* shadow = aStartChild->GetParentNode()->GetShadowRoot()) {
5999 // If the children of the container may be distributed to different
6000 // insertion points, insert them in separate batches and bail out.
6001 IssueShadowHostChildrenInsertNotifications(*shadow, aStartChild, aEndChild,
6002 aInsertionKind);
6003 return {};
6004 }
6005
6006#ifdef DEBUG1
6007 {
6008 nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
6009 for (nsIContent* child = aStartChild->GetNextSibling(); child;
6010 child = child->GetNextSibling()) {
6011 MOZ_ASSERT(child->GetFlattenedTreeParent() == expectedParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(child->GetFlattenedTreeParent() == expectedParent
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(child->GetFlattenedTreeParent() == expectedParent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"child->GetFlattenedTreeParent() == expectedParent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetFlattenedTreeParent() == expectedParent"
")"); do { MOZ_CrashSequence(__null, 6011); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6012 }
6013 }
6014#endif
6015
6016 // Now the flattened tree parent of all the siblings is the same, just use the
6017 // same insertion point.
6018 return GetInsertionPoint(aStartChild);
6019}
6020
6021bool nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6022 nsIContent* aStartChild,
6023 nsIContent* aEndChild) {
6024 if (aParentFrame->IsFrameSetFrame()) {
6025 // Check whether we have any kids we care about.
6026 for (nsIContent* cur = aStartChild; cur != aEndChild;
6027 cur = cur->GetNextSibling()) {
6028 if (IsSpecialFramesetChild(cur)) {
6029 // Just reframe the parent, since framesets are weird like that.
6030 RecreateFramesForContent(aParentFrame->GetContent(),
6031 InsertionKind::Async);
6032 return true;
6033 }
6034 }
6035 }
6036 return false;
6037}
6038
6039void nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
6040 nsIContent* aEndChild) {
6041 for (nsIContent* child = aStartChild; child != aEndChild;
6042 child = child->GetNextSibling()) {
6043 if (child->IsElement()) {
6044 child->AsElement()->NoteDirtyForServo();
6045 }
6046 }
6047}
6048
6049#ifdef DEBUG1
6050static bool IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild) {
6051 FlattenedChildIterator iter(aParent);
6052 for (nsIContent* node = iter.GetNextChild(); node;
6053 node = iter.GetNextChild()) {
6054 if (node == aChild) {
6055 return true;
6056 }
6057 }
6058 return false;
6059}
6060#endif
6061
6062void nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
6063 nsIContent* aEndChild) {
6064 ServoStyleSet* styleSet = mPresShell->StyleSet();
6065
6066 for (nsIContent* child = aStartChild; child != aEndChild;
6067 child = child->GetNextSibling()) {
6068 if (!child->IsElement()) {
6069 continue;
6070 }
6071
6072 Element* childElement = child->AsElement();
6073
6074 // We only come in here from non-lazy frame construction, so the children
6075 // should be unstyled.
6076 MOZ_ASSERT(!childElement->HasServoData())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!childElement->HasServoData())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!childElement->HasServoData
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!childElement->HasServoData()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childElement->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 6076); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6077
6078#ifdef DEBUG1
6079 {
6080 // Furthermore, all of them should have the same flattened tree parent
6081 // (GetRangeInsertionPoint ensures it). And that parent should be styled,
6082 // otherwise we would've never found an insertion point at all.
6083 Element* parent = childElement->GetFlattenedTreeParentElement();
6084 MOZ_ASSERT(parent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(parent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("parent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ")"
); do { MOZ_CrashSequence(__null, 6084); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6085 MOZ_ASSERT(parent->HasServoData())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->HasServoData())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parent->HasServoData())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("parent->HasServoData()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6085); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parent->HasServoData()" ")"); do { MOZ_CrashSequence
(__null, 6085); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6086 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFlattenedTreeChild(parent, child))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFlattenedTreeChild(parent,
child)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsFlattenedTreeChild(parent, child)" " (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6088
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6088); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6087 IsFlattenedTreeChild(parent, child),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFlattenedTreeChild(parent, child))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFlattenedTreeChild(parent,
child)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsFlattenedTreeChild(parent, child)" " (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6088
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6088); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6088 "GetFlattenedTreeParent and ChildIterator don't agree, fix this!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFlattenedTreeChild(parent, child))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFlattenedTreeChild(parent,
child)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsFlattenedTreeChild(parent, child)" " (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6088
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6088); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6089 }
6090#endif
6091
6092 styleSet->StyleNewSubtree(childElement);
6093 }
6094}
6095
6096// This is a bit slow, but sometimes we need it.
6097static bool ParentIsWrapperAnonBox(nsIFrame* aParent) {
6098 nsIFrame* maybeAnonBox = aParent;
6099 if (maybeAnonBox->Style()->GetPseudoType() ==
6100 PseudoStyleType::MozCellContent) {
6101 // The thing that would maybe be a wrapper anon box is the cell.
6102 maybeAnonBox = maybeAnonBox->GetParent();
6103 }
6104 return maybeAnonBox->Style()->IsWrapperAnonBox();
6105}
6106
6107void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
6108 InsertionKind aInsertionKind) {
6109 return ContentRangeInserted(aFirstNewContent, nullptr, aInsertionKind);
6110}
6111
6112void nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
6113 InsertionKind aInsertionKind) {
6114 ContentRangeInserted(aChild, aChild->GetNextSibling(), aInsertionKind);
6115}
6116
6117// It's very likely that we don't have any existing captions (because we only
6118// render one of them, see bug 144517). We also don't fragment table captions.
6119// So, prefer just walking the existing captions and searching it, rather than
6120// adding a special GetInsertionPrevSibling() version that skips everything but
6121// table captions.
6122static nsIFrame* FindCaptionPrevSibling(nsTableWrapperFrame* aTable,
6123 nsIContent* aCaptionContent) {
6124 nsIFrame* prevSibling = aTable->InnerTableFrame();
6125 if (nsIFrame* firstCaption = prevSibling->GetNextSibling()) {
6126 nsContentUtils::NodeIndexCache cache;
6127 for (auto* caption = firstCaption; caption;
6128 caption = caption->GetNextSibling()) {
6129 if (nsContentUtils::CompareTreePosition<TreeKind::Flat>(
6130 caption->GetContent(), aCaptionContent, nullptr, &cache) >= 0) {
6131 break;
6132 }
6133 prevSibling = caption;
6134 }
6135 }
6136 return prevSibling;
6137}
6138
6139// ContentRangeInserted handles creating frames for a range of nodes that
6140// might not be at the end of their childlist. ContentRangeInserted isn't a real
6141// content notification, but rather it handles regular ContentInserted calls
6142// for a single node as well as the lazy construction of frames for a range of
6143// nodes when called from CreateNeededFrames. For a range of nodes to be
6144// suitable to have its frames constructed all at once they must meet the same
6145// conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6146// these), plus more.
6147void nsCSSFrameConstructor::ContentRangeInserted(
6148 nsIContent* aStartChild, nsIContent* aEndChild,
6149 InsertionKind aInsertionKind, SameInsertionPoint aSameInsertionPoint) {
6150 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRangeInserted",mozilla::AutoProfilerLabelHot raiiObject6151( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6151 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6151( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6152 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6153
6154 MOZ_ASSERT(aStartChild, "must always pass a child")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartChild))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aStartChild" " ("
"must always pass a child" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
") (" "must always pass a child" ")"); do { MOZ_CrashSequence
(__null, 6154); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6155
6156#ifdef DEBUG1
6157 if (gNoisyContentUpdates) {
6158 printf(
6159 "nsCSSFrameConstructor::ContentRangeInserted container=%p "
6160 "start-child=%p end-child=%p lazy=%d\n",
6161 aStartChild->GetParent(), aStartChild, aEndChild,
6162 aInsertionKind == InsertionKind::Async);
6163 if (gReallyNoisyContentUpdates) {
6164 if (aStartChild->GetParent()) {
6165 aStartChild->GetParent()->List(stdoutstdout, 0);
6166 } else {
6167 aStartChild->List(stdoutstdout, 0);
6168 }
6169 }
6170 }
6171
6172 for (nsIContent* child = aStartChild; child != aEndChild;
6173 child = child->GetNextSibling()) {
6174 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!child->GetPrimaryFrame()" " (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6176
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame()"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6175 !child->GetPrimaryFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!child->GetPrimaryFrame()" " (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6176
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame()"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6176 "asked to construct a frame for a node that already has a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!child->GetPrimaryFrame()" " (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6176
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame()"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6177 }
6178#endif
6179
6180 // If we have a null parent, then this must be the document element being
6181 // inserted, or some other child of the document in the DOM (might be a
6182 // processing instruction or comment).
6183 if (!aStartChild->GetParent()) {
6184 Element* docElement = mDocument->GetRootElement();
6185 const bool foundRoot = [&] {
6186 for (nsIContent* cur = aStartChild; cur != aEndChild;
6187 cur = cur->GetNextSibling()) {
6188 if (cur == docElement) {
6189 return true;
6190 }
6191 }
6192 return false;
6193 }();
6194
6195 if (!foundRoot) {
6196 // Not the root element (could be e.g. a comment), just bail out
6197 return;
6198 }
6199
6200 MOZ_ASSERT(!mRootElementFrame, "root element frame already created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRootElementFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRootElementFrame))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mRootElementFrame"
" (" "root element frame already created" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6200); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "root element frame already created" ")"); do { MOZ_CrashSequence
(__null, 6200); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6201 if (aInsertionKind == InsertionKind::Async) {
6202 docElement->SetFlags(NODE_NEEDS_FRAME);
6203 LazilyStyleNewChildRange(docElement, nullptr);
6204 return;
6205 }
6206
6207 // Create frames for the document element and its child elements
6208 if (ConstructDocElementFrame(docElement)) {
6209 InvalidateCanvasIfNeeded(mPresShell, docElement);
6210#ifdef DEBUG1
6211 if (gReallyNoisyContentUpdates) {
6212 printf(
6213 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6214 "model:\n");
6215 mRootElementFrame->List(stdoutstdout);
6216 }
6217#endif
6218 }
6219
6220#ifdef ACCESSIBILITY1
6221 if (nsAccessibilityService* accService = GetAccService()) {
6222 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6223 }
6224#endif
6225 return;
6226 }
6227
6228 const bool isSingleInsert = aStartChild->GetNextSibling() == aEndChild;
6229 InsertionPoint insertion;
6230 if (isSingleInsert || aSameInsertionPoint == SameInsertionPoint::Yes) {
6231 // See if we have a Shadow DOM insertion point. If so, then that's our real
6232 // parent frame; if not, then the frame hasn't been built yet and we just
6233 // bail.
6234 insertion = GetInsertionPoint(aStartChild);
6235#ifdef DEBUG1
6236 for (nsIContent* child = aStartChild->GetNextSibling(); child != aEndChild;
6237 child = child->GetNextSibling()) {
6238 MOZ_ASSERT(GetInsertionPoint(child) == insertion,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetInsertionPoint(child) == insertion)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(GetInsertionPoint(child) == insertion))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("GetInsertionPoint(child) == insertion"
" (" "Caller lied, not the same insertion point" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetInsertionPoint(child) == insertion"
") (" "Caller lied, not the same insertion point" ")"); do {
MOZ_CrashSequence(__null, 6239); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6239 "Caller lied, not the same insertion point")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetInsertionPoint(child) == insertion)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(GetInsertionPoint(child) == insertion))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("GetInsertionPoint(child) == insertion"
" (" "Caller lied, not the same insertion point" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetInsertionPoint(child) == insertion"
") (" "Caller lied, not the same insertion point" ")"); do {
MOZ_CrashSequence(__null, 6239); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6240 }
6241#endif
6242 } else {
6243 // Get our insertion point. If we need to issue single ContentInserteds
6244 // GetRangeInsertionPoint will take care of that for us.
6245 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6246 insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
6247 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6248 }
6249
6250 if (!insertion.mParentFrame) {
6251 // We're punting on frame construction because there's no container frame.
6252 // The Servo-backed style system handles this case like the lazy frame
6253 // construction case, except when we're already constructing frames, in
6254 // which case we shouldn't need to do anything else.
6255 if (aInsertionKind == InsertionKind::Async) {
6256 LazilyStyleNewChildRange(aStartChild, aEndChild);
6257 }
6258 return;
6259 }
6260
6261 if (aInsertionKind == InsertionKind::Async) {
6262 ConstructLazily(aStartChild, aEndChild);
6263 LazilyStyleNewChildRange(aStartChild, aEndChild);
6264 return;
6265 }
6266
6267 bool isAppend;
6268 nsIFrame* prevSibling =
6269 GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6270
6271 LayoutFrameType frameType = insertion.mParentFrame->Type();
6272 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6273 if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild,
6274 aEndChild)) {
6275 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6276 return;
6277 }
6278 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6279
6280 // Don't construct kids of leaves
6281 if (insertion.mParentFrame->IsLeaf()) {
6282 // Clear lazy bits so we don't try to construct again.
6283 ClearLazyBits(aStartChild, aEndChild);
6284 return;
6285 }
6286
6287 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6288 if (WipeInsertionParent(insertion.mParentFrame)) {
6289 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6290 return;
6291 }
6292 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6293
6294 nsFrameConstructorState state(
6295 mPresShell, GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
6296 GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
6297 GetFloatContainingBlock(insertion.mParentFrame));
6298
6299 // Recover state for the containing block - we need to know if
6300 // it has :first-letter or :first-line style applied to it. The
6301 // reason we care is that the internal structure in these cases
6302 // is not the normal structure and requires custom updating
6303 // logic.
6304 nsContainerFrame* containingBlock = state.mFloatedList.mContainingBlock;
6305 bool haveFirstLetterStyle = false;
6306 bool haveFirstLineStyle = false;
6307
6308 // In order to shave off some cycles, we only dig up the
6309 // containing block haveFirst* flags if the parent frame where
6310 // the insertion/append is occurring is an inline or block
6311 // container. For other types of containers this isn't relevant.
6312 StyleDisplayInside parentDisplayInside =
6313 insertion.mParentFrame->StyleDisplay()->DisplayInside();
6314
6315 // Examine the insertion.mParentFrame where the insertion is taking
6316 // place. If it's a certain kind of container then some special
6317 // processing is done.
6318 if (StyleDisplayInside::Flow == parentDisplayInside) {
6319 // Recover the special style flags for the containing block
6320 if (containingBlock) {
6321 haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
6322 haveFirstLineStyle = ShouldHaveFirstLineStyle(
6323 containingBlock->GetContent(), containingBlock->Style());
6324 }
6325
6326 if (haveFirstLetterStyle) {
6327 // If our current insertion.mParentFrame is a Letter frame, use its parent
6328 // as our new parent hint
6329 if (insertion.mParentFrame->IsLetterFrame()) {
6330 // If insertion.mParentFrame is out of flow, then we actually want the
6331 // parent of the placeholder frame.
6332 if (insertion.mParentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6333 nsPlaceholderFrame* placeholderFrame =
6334 insertion.mParentFrame->GetPlaceholderFrame();
6335 NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?")do { if (!(placeholderFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "No placeholder for out-of-flow?", "placeholderFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6335); MOZ_PretendNoReturn(); } } while (0)
;
6336 insertion.mParentFrame = placeholderFrame->GetParent();
6337 } else {
6338 insertion.mParentFrame = insertion.mParentFrame->GetParent();
6339 }
6340 }
6341
6342 // Remove the old letter frames before doing the insertion
6343 RemoveLetterFrames(mPresShell, state.mFloatedList.mContainingBlock);
6344
6345 // Removing the letterframes messes around with the frame tree, removing
6346 // and creating frames. We need to reget our prevsibling, parent frame,
6347 // etc.
6348 prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6349 frameType = insertion.mParentFrame->Type();
6350 }
6351 }
6352
6353 // This handles fallback to 'list-style-type' when a 'list-style-image' fails
6354 // to load.
6355 if (aStartChild->IsInNativeAnonymousSubtree() &&
6356 aStartChild->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
6357 MOZ_ASSERT(isSingleInsert)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSingleInsert)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSingleInsert))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("isSingleInsert"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6357); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "isSingleInsert" ")"); do { MOZ_CrashSequence
(__null, 6357); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6358 MOZ_ASSERT(insertion.mParentFrame->Style()->GetPseudoType() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertion.mParentFrame->Style()->GetPseudoType
() == PseudoStyleType::Marker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(insertion.mParentFrame->Style
()->GetPseudoType() == PseudoStyleType::Marker))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
" (" "we can only handle ::marker fallback for now" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6360); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6359 PseudoStyleType::Marker,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertion.mParentFrame->Style()->GetPseudoType
() == PseudoStyleType::Marker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(insertion.mParentFrame->Style
()->GetPseudoType() == PseudoStyleType::Marker))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
" (" "we can only handle ::marker fallback for now" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6360); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6360 "we can only handle ::marker fallback for now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertion.mParentFrame->Style()->GetPseudoType
() == PseudoStyleType::Marker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(insertion.mParentFrame->Style
()->GetPseudoType() == PseudoStyleType::Marker))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
" (" "we can only handle ::marker fallback for now" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6360); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6361 nsIContent* const nextSibling = aStartChild->GetNextSibling();
6362 MOZ_ASSERT(nextSibling && nextSibling->IsText(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nextSibling && nextSibling->IsText())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nextSibling && nextSibling->IsText()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("nextSibling && nextSibling->IsText()"
" (" "expected a text node after the list-style-image image"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6363
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6363); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6363 "expected a text node after the list-style-image image")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nextSibling && nextSibling->IsText())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nextSibling && nextSibling->IsText()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("nextSibling && nextSibling->IsText()"
" (" "expected a text node after the list-style-image image"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6363
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6363); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6364 DestroyContext context(mPresShell);
6365 RemoveFrame(context, FrameChildListID::Principal,
6366 nextSibling->GetPrimaryFrame());
6367 auto* const container = aStartChild->GetParent()->AsElement();
6368 nsIContent* firstNewChild = nullptr;
6369 auto InsertChild = [this, container, nextSibling,
6370 &firstNewChild](RefPtr<nsIContent>&& aChild) {
6371 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
6372 // here; it would get set under AppendChildTo. But AppendChildTo might
6373 // think that we're going from not being anonymous to being anonymous and
6374 // do some extra work; setting the flag here avoids that.
6375 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
6376 container->InsertChildBefore(aChild, nextSibling, false, IgnoreErrors());
6377 if (auto* childElement = Element::FromNode(aChild)) {
6378 // If we created any children elements, Servo needs to traverse them,
6379 // but the root is already set up.
6380 mPresShell->StyleSet()->StyleNewSubtree(childElement);
6381 }
6382 if (!firstNewChild) {
6383 firstNewChild = aChild;
6384 }
6385 };
6386 CreateGeneratedContentFromListStyleType(
6387 state, *insertion.mContainer->AsElement(),
6388 *insertion.mParentFrame->Style(), InsertChild);
6389 if (!firstNewChild) {
6390 // No fallback content - we're done.
6391 return;
6392 }
6393 aStartChild = firstNewChild;
6394 MOZ_ASSERT(firstNewChild->GetNextSibling() == nextSibling,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(firstNewChild->GetNextSibling() == nextSibling)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(firstNewChild->GetNextSibling() == nextSibling)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("firstNewChild->GetNextSibling() == nextSibling"
" (" "list-style-type should only create one child" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6395); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6395 "list-style-type should only create one child")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(firstNewChild->GetNextSibling() == nextSibling)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(firstNewChild->GetNextSibling() == nextSibling)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("firstNewChild->GetNextSibling() == nextSibling"
" (" "list-style-type should only create one child" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6395); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6396 }
6397
6398 AutoFrameConstructionItemList items(this);
6399 RefPtr<ComputedStyle> parentStyle =
6400 ResolveComputedStyle(insertion.mContainer);
6401 ParentType parentType = GetParentType(frameType);
6402 FlattenedChildIterator iter(insertion.mContainer);
6403 const bool haveNoShadowDOM =
6404 !iter.ShadowDOMInvolved() || !iter.GetNextChild();
6405 if (aStartChild->GetPreviousSibling() && parentType == eTypeBlock &&
6406 haveNoShadowDOM) {
6407 // If there's a text node in the normal content list just before the
6408 // new nodes, and it has no frame, make a frame construction item for
6409 // it, because it might need a frame now. No need to do this if our
6410 // parent type is not block, though, since WipeContainingBlock
6411 // already handles that situation.
6412 AddTextItemIfNeeded(state, *parentStyle, insertion,
6413 aStartChild->GetPreviousSibling(), items);
6414 }
6415
6416 const bool suppressWhiteSpaceOptimizations =
6417 isSingleInsert && aStartChild->IsRootOfNativeAnonymousSubtree();
6418 for (nsIContent* child = aStartChild; child != aEndChild;
6419 child = child->GetNextSibling()) {
6420 AddFrameConstructionItems(state, child, suppressWhiteSpaceOptimizations,
6421 *parentStyle, insertion, items);
6422 }
6423
6424 if (aEndChild && parentType == eTypeBlock && haveNoShadowDOM) {
6425 // If there's a text node in the normal content list just after the
6426 // new nodes, and it has no frame, make a frame construction item for
6427 // it, because it might need a frame now. No need to do this if our
6428 // parent type is not block, though, since WipeContainingBlock
6429 // already handles that situation.
6430 AddTextItemIfNeeded(state, *parentStyle, insertion, aEndChild, items);
6431 }
6432
6433 // Perform special check for diddling around with the frames in a special
6434 // inline frame. If we're appending before :after content, then we're not
6435 // really appending, so let WipeContainingBlock know that.
6436 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6437 if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
6438 isAppend, prevSibling)) {
6439 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6440 return;
6441 }
6442 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6443
6444 // If the parent is a block frame, and we're not in a special case
6445 // where frames can be moved around, determine if the list is for the
6446 // start or end of the block.
6447 if (insertion.mParentFrame->IsBlockFrameOrSubclass() &&
6448 !haveFirstLetterStyle && !haveFirstLineStyle &&
6449 !IsFramePartOfIBSplit(insertion.mParentFrame)) {
6450 items.SetLineBoundaryAtStart(!prevSibling ||
6451 !prevSibling->IsInlineOutside() ||
6452 prevSibling->IsBrFrame());
6453 auto* nextSibling =
6454 ::GetInsertNextSibling(insertion.mParentFrame, prevSibling);
6455 items.SetLineBoundaryAtEnd(!nextSibling ||
6456 !nextSibling->IsInlineOutside() ||
6457 nextSibling->IsBrFrame());
6458 }
6459 // To suppress whitespace-only text frames, we have to verify that
6460 // our container's DOM child list matches its flattened tree child list.
6461 items.SetParentHasNoShadowDOM(haveNoShadowDOM);
6462
6463 nsFrameConstructorSaveState floatSaveState;
6464 state.MaybePushFloatContainingBlock(insertion.mParentFrame, floatSaveState);
6465
6466 if (state.mPresContext->IsPaginated()) {
6467 // Because this function can be called outside frame construction, we need
6468 // to set state.mAutoPageNameValue based on what the parent frame's auto
6469 // value is.
6470 // Calling this from outside the frame constructor can violate many of the
6471 // expectations in AutoFrameConstructionPageName, and unlike during frame
6472 // construction we already have an auto value from parentFrame, so we do
6473 // not use AutoFrameConstructionPageName here.
6474 state.mAutoPageNameValue = insertion.mParentFrame->GetAutoPageValue();
6475#ifdef DEBUG1
6476 insertion.mParentFrame->mWasVisitedByAutoFrameConstructionPageName = true;
6477#endif
6478 }
6479
6480 // If the container is a table and a caption will be appended, it needs to be
6481 // put in the table wrapper frame's additional child list.
6482 // We make no attempt here to set flags to indicate whether the list
6483 // will be at the start or end of a block. It doesn't seem worthwhile.
6484 nsFrameList frameList, captionList;
6485 ConstructFramesFromItemList(state, items, insertion.mParentFrame,
6486 ParentIsWrapperAnonBox(insertion.mParentFrame),
6487 frameList);
6488
6489 if (frameList.NotEmpty()) {
6490 for (nsIContent* child = aStartChild; child != aEndChild;
6491 child = child->GetNextSibling()) {
6492 InvalidateCanvasIfNeeded(mPresShell, child);
6493 }
6494
6495 if (LayoutFrameType::Table == frameType ||
6496 LayoutFrameType::TableWrapper == frameType) {
6497 PullOutCaptionFrames(frameList, captionList);
6498 if (prevSibling && prevSibling->IsTableCaption()) {
6499 // This can happen, but only if the table is empty (otherwise
6500 // SafeToInsertPseudoNeedingChildren bails).
6501 prevSibling = nullptr;
6502 }
6503 }
6504 }
6505
6506 if (haveFirstLineStyle && insertion.mParentFrame == containingBlock &&
6507 isAppend) {
6508 // It's possible that the new frame goes into a first-line
6509 // frame. Look at it and see...
6510 AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
6511 frameList);
6512 } else if (insertion.mParentFrame->Style()->IsInFirstLineSubtree()) {
6513 CheckForFirstLineInsertion(insertion.mParentFrame, frameList);
6514 CheckForFirstLineInsertion(insertion.mParentFrame, captionList);
6515 }
6516
6517 // We might have captions; put them into the principal child list of the table
6518 // wrapper frame.
6519 if (captionList.NotEmpty()) {
6520 NS_ASSERTION(LayoutFrameType::Table == frameType ||do { if (!(LayoutFrameType::Table == frameType || LayoutFrameType
::TableWrapper == frameType)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "parent for caption is not table?", "LayoutFrameType::Table == frameType || LayoutFrameType::TableWrapper == frameType"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6522); MOZ_PretendNoReturn
(); } } while (0)
6521 LayoutFrameType::TableWrapper == frameType,do { if (!(LayoutFrameType::Table == frameType || LayoutFrameType
::TableWrapper == frameType)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "parent for caption is not table?", "LayoutFrameType::Table == frameType || LayoutFrameType::TableWrapper == frameType"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6522); MOZ_PretendNoReturn
(); } } while (0)
6522 "parent for caption is not table?")do { if (!(LayoutFrameType::Table == frameType || LayoutFrameType
::TableWrapper == frameType)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "parent for caption is not table?", "LayoutFrameType::Table == frameType || LayoutFrameType::TableWrapper == frameType"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6522); MOZ_PretendNoReturn
(); } } while (0)
;
6523 // We need to determine where to put the caption items; start with the
6524 // the parent frame that has already been determined and get the insertion
6525 // prevsibling of the first caption item.
6526 nsContainerFrame* outerTable = insertion.mParentFrame->IsTableFrame()
6527 ? insertion.mParentFrame->GetParent()
6528 : insertion.mParentFrame;
6529
6530 // If the parent is not a table wrapper frame we will try to add frames
6531 // to a named child list that the parent does not honor and the frames
6532 // will get lost.
6533 MOZ_ASSERT(outerTable->IsTableWrapperFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(outerTable->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(outerTable->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("outerTable->IsTableWrapperFrame()" " (" "Pseudo frame construction failure; "
"a caption can be only a child of a table wrapper frame" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6535); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "outerTable->IsTableWrapperFrame()" ") ("
"Pseudo frame construction failure; " "a caption can be only a child of a table wrapper frame"
")"); do { MOZ_CrashSequence(__null, 6535); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6534 "Pseudo frame construction failure; "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(outerTable->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(outerTable->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("outerTable->IsTableWrapperFrame()" " (" "Pseudo frame construction failure; "
"a caption can be only a child of a table wrapper frame" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6535); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "outerTable->IsTableWrapperFrame()" ") ("
"Pseudo frame construction failure; " "a caption can be only a child of a table wrapper frame"
")"); do { MOZ_CrashSequence(__null, 6535); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6535 "a caption can be only a child of a table wrapper frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(outerTable->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(outerTable->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("outerTable->IsTableWrapperFrame()" " (" "Pseudo frame construction failure; "
"a caption can be only a child of a table wrapper frame" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6535); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "outerTable->IsTableWrapperFrame()" ") ("
"Pseudo frame construction failure; " "a caption can be only a child of a table wrapper frame"
")"); do { MOZ_CrashSequence(__null, 6535); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6536
6537 nsIFrame* captionPrevSibling =
6538 FindCaptionPrevSibling(static_cast<nsTableWrapperFrame*>(outerTable),
6539 captionList.FirstChild()->GetContent());
6540 captionList.ApplySetParent(outerTable);
6541 if (!captionPrevSibling->GetNextSibling()) {
6542 AppendFrames(outerTable, FrameChildListID::Principal,
6543 std::move(captionList));
6544 } else {
6545 InsertFrames(outerTable, FrameChildListID::Principal, captionPrevSibling,
6546 std::move(captionList));
6547 }
6548 }
6549
6550 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6551 if (MaybeRecreateForColumnSpan(state, insertion.mParentFrame, frameList,
6552 prevSibling)) {
6553 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6554 return;
6555 }
6556 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6557
6558 if (frameList.NotEmpty()) {
6559 // Notify the parent frame
6560 if (isAppend) {
6561 AppendFramesToParent(state, insertion.mParentFrame, frameList,
6562 prevSibling);
6563 } else {
6564 InsertFrames(insertion.mParentFrame, FrameChildListID::Principal,
6565 prevSibling, std::move(frameList));
6566 }
6567 }
6568
6569 if (haveFirstLetterStyle) {
6570 // Recover the letter frames for the containing block when
6571 // it has first-letter style.
6572 RecoverLetterFrames(state.mFloatedList.mContainingBlock);
6573 }
6574
6575#ifdef DEBUG1
6576 if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
6577 printf(
6578 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6579 "model:\n");
6580 insertion.mParentFrame->List(stdoutstdout);
6581 }
6582#endif
6583
6584#ifdef ACCESSIBILITY1
6585 if (nsAccessibilityService* accService = GetAccService()) {
6586 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6587 }
6588#endif
6589}
6590
6591static bool IsWhitespaceFrame(const nsIFrame* aFrame) {
6592 MOZ_ASSERT(aFrame, "invalid argument")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "invalid argument"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6592
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 6592); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6593 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
6594}
6595
6596static bool IsSyntheticColGroup(const nsIFrame* aFrame) {
6597 return aFrame->IsTableColGroupFrame() &&
6598 static_cast<const nsTableColGroupFrame*>(aFrame)->IsSynthetic();
6599}
6600
6601static bool IsOnlyNonWhitespaceFrameInList(
6602 const nsFrameList& aFrameList, const nsIFrame* aFrame,
6603 const nsIFrame* aIgnoreFrame = nullptr) {
6604 for (const nsIFrame* f : aFrameList) {
6605 if (f == aIgnoreFrame) {
6606 continue;
6607 }
6608 if (f == aFrame) {
6609 // If we have continuations, ignore them too.
6610 aFrame = aFrame->GetNextContinuation();
6611 } else if (!IsWhitespaceFrame(f) && !IsSyntheticColGroup(f)) {
6612 // Synthetic colgroups get created unconditionally, so let's not consider
6613 // them as giving us a non-whitespace frame.
6614 return false;
6615 }
6616 }
6617 return true;
6618}
6619
6620static bool AllChildListsAreEffectivelyEmpty(nsIFrame* aFrame) {
6621 for (auto& [list, listID] : aFrame->ChildLists()) {
6622 if (list.IsEmpty()) {
6623 continue;
6624 }
6625 // We have some existing frame, usually that would be considered as making
6626 // this list nonempty. But let's make an exception for the synthetic
6627 // colgroup that tables have, since that gets created unconditionally.
6628 if (listID == FrameChildListID::Principal && aFrame->IsTableFrame()) {
6629 if (nsIFrame* f = list.OnlyChild(); f && IsSyntheticColGroup(f)) {
6630 continue;
6631 }
6632 }
6633 return false;
6634 }
6635 return true;
6636}
6637
6638static bool SafeToInsertPseudoNeedingChildren(nsIFrame* aFrame) {
6639 return AllChildListsAreEffectivelyEmpty(aFrame);
6640}
6641
6642// Returns true if aFrame is the only meaningful child of aParent (which is
6643// known to be a wrapper-pseudo). This lets us determine whether aParent can be
6644// removed, as a result of aFrame being removed.
6645static bool IsOnlyMeaningfulChildOfWrapperPseudo(nsIFrame* aFrame,
6646 nsIFrame* aParent) {
6647 MOZ_ASSERT(IsWrapperPseudo(aParent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsWrapperPseudo(aParent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsWrapperPseudo(aParent)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("IsWrapperPseudo(aParent)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6647); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsWrapperPseudo(aParent)" ")"); do { MOZ_CrashSequence
(__null, 6647); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6648 // Handle a few special cases with tables and colgroups / captions.
6649 if (aParent->IsTableFrame()) {
6650 auto* wrapper = aParent->GetParent();
6651 MOZ_ASSERT(wrapper)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wrapper))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("wrapper", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper" ")"
); do { MOZ_CrashSequence(__null, 6651); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6652 MOZ_ASSERT(wrapper->IsTableWrapperFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wrapper->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wrapper->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("wrapper->IsTableWrapperFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6652); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6653 MOZ_ASSERT(!aFrame->IsTableCaption(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "Caption parent should be the wrapper"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6654
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6654); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6654 "Caption parent should be the wrapper")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "Caption parent should be the wrapper"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6654
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6654); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6655 // We can't remove the table if there are any captions present (captions are
6656 // never anonymous themselves), because table wrapper always relies on
6657 // having a table frame.
6658 if (!wrapper->PrincipalChildList().OnlyChild()) {
6659 return false;
6660 }
6661 }
6662 if (aFrame->IsTableCaption()) {
6663 MOZ_ASSERT(aParent->IsTableWrapperFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->IsTableWrapperFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6663); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6664 auto* table = static_cast<nsTableWrapperFrame*>(aParent)->InnerTableFrame();
6665 MOZ_ASSERT(table)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(table)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(table))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("table", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "table" ")")
; do { MOZ_CrashSequence(__null, 6665); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6666 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame,
6667 /* aIgnoreFrame = */ table) &&
6668 // This checks for both colgroups and the principal list of the table
6669 // frame.
6670 AllChildListsAreEffectivelyEmpty(table);
6671 }
6672 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame);
6673}
6674
6675static bool CanRemoveWrapperPseudoForChildRemoval(nsIFrame* aFrame,
6676 nsIFrame* aParent) {
6677 if (!IsOnlyMeaningfulChildOfWrapperPseudo(aFrame, aParent)) {
6678 return false;
6679 }
6680 if (aParent->GetPrevContinuation() || aParent->GetNextContinuation()) {
6681 // If our parent is fragmented we're not really the only meaningful child.
6682 return false;
6683 }
6684 if (aParent->IsRubyBaseContainerFrame()) {
6685 // We can't remove the first ruby base container of a ruby frame unless
6686 // it has no siblings. See CreateNeededPseudoSiblings.
6687 return aParent->GetPrevSibling() || !aParent->GetNextSibling();
6688 }
6689 return true;
6690}
6691
6692bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild,
6693 RemovalKind aKind) {
6694 MOZ_ASSERT(aChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 6694); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6695 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChild->IsRootOfNativeAnonymousSubtree() || !aChild
->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChild->IsRootOfNativeAnonymousSubtree
() || !aChild->GetNextSibling()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
" (" "Anonymous roots don't have siblings" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6697); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6696 !aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChild->IsRootOfNativeAnonymousSubtree() || !aChild
->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChild->IsRootOfNativeAnonymousSubtree
() || !aChild->GetNextSibling()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
" (" "Anonymous roots don't have siblings" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6697); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6697 "Anonymous roots don't have siblings")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChild->IsRootOfNativeAnonymousSubtree() || !aChild
->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aChild->IsRootOfNativeAnonymousSubtree
() || !aChild->GetNextSibling()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
" (" "Anonymous roots don't have siblings" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6697); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6698 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentWillBeRemoved",mozilla::AutoProfilerLabelHot raiiObject6699( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6699 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6699( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6700 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6701 nsPresContext* presContext = mPresShell->GetPresContext();
6702 MOZ_ASSERT(presContext, "Our presShell should have a valid presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Our presShell should have a valid presContext" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Our presShell should have a valid presContext" ")"); do
{ MOZ_CrashSequence(__null, 6702); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6703
6704 const bool wasRemovingContent = mRemovingContent;
6705 auto _ = MakeScopeExit([&] { mRemovingContent = wasRemovingContent; });
6706 mRemovingContent = true;
6707
6708 // We want to detect when the viewport override element stored in the
6709 // prescontext is in the subtree being removed. Except in fullscreen cases
6710 // (which are handled in Element::UnbindFromTree and do not get stored on the
6711 // prescontext), the override element is always either the root element or a
6712 // <body> child of the root element. So we can only be removing the stored
6713 // override element if the thing being removed is either the override element
6714 // itself or the root element (which can be a parent of the override element).
6715 //
6716 // The !wasRemovingContent check makes sure that we don't re-enter here from
6717 // other ContentWillBeRemoved calls, as that'd be useless work, and we don't
6718 // want to incorrectly pick aChild again as our viewport scroll style element
6719 // if it's getting removed from the DOM.
6720 if ((aChild == presContext->GetViewportScrollStylesOverrideElement() ||
6721 aChild->IsRootElement()) &&
6722 !wasRemovingContent) {
6723 // We might be removing the element that we propagated viewport scrollbar
6724 // styles from. Recompute those. (This clause covers two of the three
6725 // possible scrollbar-propagation sources: the <body> [as aChild or a
6726 // descendant] and the root node. The other possible scrollbar-propagation
6727 // source is a fullscreen element, and we have code elsewhere to update
6728 // scrollbars after fullscreen elements are removed -- specifically, it's
6729 // part of the fullscreen cleanup code called by Element::UnbindFromTree.
6730 // We don't handle the fullscreen case here, because it doesn't change the
6731 // scrollbar styles override element stored on the prescontext.)
6732 const Element* removingElement =
6733 aKind == RemovalKind::Dom ? aChild->AsElement() : nullptr;
6734 Element* newOverrideElement =
6735 presContext->UpdateViewportScrollStylesOverride(removingElement);
6736
6737 // If aChild is the root, then we don't need to do any reframing of
6738 // newOverrideElement, because we're about to tear down the whole frame tree
6739 // anyway. And we need to make sure we don't do any such reframing, because
6740 // reframing the <body> can trigger a reframe of the <html> and then reenter
6741 // here.
6742 //
6743 // But if aChild is not the root, and if newOverrideElement is not the root
6744 // and isn't aChild (which it could be if all we're doing here is reframing
6745 // the current override element), it needs reframing. In particular, it
6746 // used to have a scrollframe (because its overflow was not "visible"), but
6747 // now it will propagate its overflow to the viewport, so it should not need
6748 // a scrollframe anymore.
6749 if (aChild->GetParent() && newOverrideElement &&
6750 newOverrideElement->GetParent() && newOverrideElement != aChild) {
6751 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6752 RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
6753 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6754 }
6755 }
6756
6757#ifdef DEBUG1
6758 if (gNoisyContentUpdates) {
6759 printf(
6760 "nsCSSFrameConstructor::ContentWillBeRemoved container=%p child=%p\n",
6761 aChild->GetParent(), aChild);
6762 if (gReallyNoisyContentUpdates) {
6763 aChild->GetParent()->List(stdoutstdout, 0);
6764 }
6765 }
6766#endif
6767
6768 nsIFrame* childFrame = aChild->GetPrimaryFrame();
6769
6770 // If we're removing the root, then make sure to remove things starting at
6771 // the viewport's child instead of the primary frame (which might even be
6772 // null if the root was display:none, even though the frames above it got
6773 // created). Detecting removal of a root is a little exciting; in particular,
6774 // having no parent is necessary but NOT sufficient.
6775 //
6776 // Due to how we process reframes, the content node might not even be in our
6777 // document by now. So explicitly check whether the viewport's first kid's
6778 // content node is aChild.
6779 //
6780 // FIXME(emilio): I think the "might not be in our document" bit is impossible
6781 // now.
6782 bool isRoot = false;
6783 if (!aChild->GetParent()) {
6784 if (nsIFrame* viewport = GetRootFrame()) {
6785 nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
6786 if (firstChild && firstChild->GetContent() == aChild) {
6787 isRoot = true;
6788 childFrame = firstChild;
6789 NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?")do { if (!(!childFrame->GetNextSibling())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "How did that happen?", "!childFrame->GetNextSibling()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6789); MOZ_PretendNoReturn
(); } } while (0)
;
6790 }
6791 }
6792 }
6793
6794 // We need to be conservative about when to determine whether something has
6795 // display: contents or not because at this point our actual display may be
6796 // different.
6797 //
6798 // Consider the case of:
6799 //
6800 // <div id="A" style="display: contents"><div id="B"></div></div>
6801 //
6802 // If we reconstruct A because its display changed to "none", we still need to
6803 // cleanup the frame on B, but A's display is now "none", so we can't poke at
6804 // the style of it.
6805 //
6806 // FIXME(emilio, bug 1450366): We can make this faster without adding much
6807 // complexity for the display: none -> other case, which right now
6808 // unnecessarily walks the content tree down.
6809 auto CouldHaveBeenDisplayContents = [aKind](nsIContent* aContent) -> bool {
6810 return aContent->IsElement() && (aKind != RemovalKind::Dom ||
6811 IsDisplayContents(aContent->AsElement()));
6812 };
6813
6814 if (!childFrame) {
6815 if (CouldHaveBeenDisplayContents(aChild)) {
6816 // NOTE(emilio): We may iterate through ::before and ::after here and they
6817 // may be gone after the respective ContentWillBeRemoved call. Right now
6818 // StyleChildrenIterator handles that properly, so it's not an issue.
6819 StyleChildrenIterator iter(aChild);
6820 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
6821 if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(c)) {
6822 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6823 bool didReconstruct = ContentWillBeRemoved(c, aKind);
6824 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6825 if (didReconstruct) {
6826 return true;
6827 }
6828 }
6829 }
6830 }
6831 return false;
6832 }
6833
6834 InvalidateCanvasIfNeeded(mPresShell, aChild);
6835
6836 // Get the childFrame's parent frame
6837 nsIFrame* parentFrame = childFrame->GetParent();
6838 LayoutFrameType parentType = parentFrame->Type();
6839
6840 if (parentType == LayoutFrameType::FrameSet &&
6841 IsSpecialFramesetChild(aChild)) {
6842 // Just reframe the parent, since framesets are weird like that.
6843 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6844 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6845 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6846 return true;
6847 }
6848
6849 // If we're a child of MathML, then we should reframe the MathML content.
6850 // If we're non-MathML, then we would be wrapped in a block so we need to
6851 // check our grandparent in that case.
6852 nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
6853 ? parentFrame->GetParent()
6854 : parentFrame;
6855 if (possibleMathMLAncestor->IsMathMLFrame()) {
6856 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6857 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6858 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6859 return true;
6860 }
6861
6862 // Examine the containing-block for the removed content and see if
6863 // :first-letter style applies.
6864 nsIFrame* inflowChild = childFrame;
6865 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6866 inflowChild = childFrame->GetPlaceholderFrame();
6867 NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?")do { if (!(inflowChild)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "No placeholder for out-of-flow?"
, "inflowChild", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6867); MOZ_PretendNoReturn(); } } while (0)
;
6868 }
6869 nsContainerFrame* containingBlock =
6870 GetFloatContainingBlock(inflowChild->GetParent());
6871 bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
6872 if (haveFLS) {
6873 // Trap out to special routine that handles adjusting a blocks
6874 // frame tree when first-letter style is present.
6875#ifdef NOISY_FIRST_LETTER
6876 printf("ContentWillBeRemoved: containingBlock=");
6877 containingBlock->ListTag(stdoutstdout);
6878 printf(" parentFrame=");
6879 parentFrame->ListTag(stdoutstdout);
6880 printf(" childFrame=");
6881 childFrame->ListTag(stdoutstdout);
6882 printf("\n");
6883#endif
6884
6885 // First update the containing blocks structure by removing the
6886 // existing letter frames. This makes the subsequent logic
6887 // simpler.
6888 RemoveLetterFrames(mPresShell, containingBlock);
6889
6890 // Recover childFrame and parentFrame
6891 childFrame = aChild->GetPrimaryFrame();
6892 if (!childFrame) {
6893 return false;
6894 }
6895 parentFrame = childFrame->GetParent();
6896 parentType = parentFrame->Type();
Value stored to 'parentType' is never read
6897
6898#ifdef NOISY_FIRST_LETTER
6899 printf(" ==> revised parentFrame=");
6900 parentFrame->ListTag(stdoutstdout);
6901 printf(" childFrame=");
6902 childFrame->ListTag(stdoutstdout);
6903 printf("\n");
6904#endif
6905 }
6906
6907 // See whether we need to remove more than just childFrame
6908 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6909 if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
6910 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6911 return true;
6912 }
6913 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6914
6915#ifdef ACCESSIBILITY1
6916 if (aKind != RemovalKind::ForReconstruction) {
6917 if (nsAccessibilityService* accService = GetAccService()) {
6918 accService->ContentRemoved(mPresShell, aChild);
6919 }
6920 }
6921#endif
6922
6923#ifdef DEBUG1
6924 if (gReallyNoisyContentUpdates) {
6925 printf("nsCSSFrameConstructor::ContentWillBeRemoved: childFrame=");
6926 childFrame->ListTag(stdoutstdout);
6927 putchar('\n');
6928 parentFrame->List(stdoutstdout);
6929 }
6930#endif
6931
6932 // Notify the parent frame that it should delete the frame
6933 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6934 childFrame = childFrame->GetPlaceholderFrame();
6935 NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.")do { if (!(childFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Missing placeholder frame for out of flow."
, "childFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6935); MOZ_PretendNoReturn(); } } while (0)
;
6936 parentFrame = childFrame->GetParent();
6937 }
6938
6939 // Take care of wrapper anonymous boxes that we might need to remove while
6940 // at it. Note that MaybeRecreateContainerForFrameRemoval takes care of
6941 // harder cases (merging sibling anonymous boxes etc).
6942 while (IsWrapperPseudo(parentFrame) &&
6943 CanRemoveWrapperPseudoForChildRemoval(childFrame, parentFrame)) {
6944 childFrame = parentFrame;
6945 parentFrame = childFrame->GetParent();
6946 }
6947
6948 const bool canSkipWhitespaceFixup = [&] {
6949 if (aKind == RemovalKind::ForReconstruction) {
6950 // If we're just reconstructing frames for the element, then the
6951 // following ContentInserted notification on the element will
6952 // take care of fixing up any adjacent white-space text nodes.
6953 return true;
6954 }
6955 switch (parentFrame->Type()) {
6956 case LayoutFrameType::Table:
6957 case LayoutFrameType::TableRow:
6958 case LayoutFrameType::TableRowGroup:
6959 case LayoutFrameType::TableCol:
6960 case LayoutFrameType::TableColGroup:
6961 case LayoutFrameType::TableWrapper: {
6962 // Tables ignore all whitespace within their wrappers, so we can avoid
6963 // reconstructing adjacent whitespace if the table is not anonymous.
6964 if (!IsInAnonymousTable(parentFrame)) {
6965 return true;
6966 }
6967 // If the table is anonymous and the child is at the edges, we might
6968 // need to create whitespace at the edges of the table that wasn't
6969 // there before, so we can only skip the check if childFrame has frames
6970 // around. Captions are extra-special here, because they're siblings
6971 // with the main table frame, so we can't count that as a relevant
6972 // sibling for our purposes.
6973 auto* prevSibling = childFrame->GetPrevSibling();
6974 return prevSibling && !prevSibling->IsTableFrame() &&
6975 childFrame->GetNextSibling();
6976 }
6977 case LayoutFrameType::GridContainer:
6978 case LayoutFrameType::FlexContainer:
6979 // Flex and grid containers similarly skip whitespace and wrap
6980 // non-whitespace in anonymous flex items, so any change to
6981 // white-space that could matter would have triggered the
6982 // reconstruction of the container itself due to merging anonymous
6983 // grid / flex items.
6984 return true;
6985 default:
6986 break;
6987 }
6988 return false;
6989 }();
6990 DestroyContext context(mPresShell);
6991 RemoveFrame(context, nsLayoutUtils::GetChildListNameFor(childFrame),
6992 childFrame);
6993
6994 // NOTE(emilio): aChild could be dead here already if it is a ::before or
6995 // ::after pseudo-element (since in that case it was owned by childFrame,
6996 // which we just destroyed).
6997
6998 if (isRoot) {
6999 mRootElementFrame = nullptr;
7000 mRootElementStyleFrame = nullptr;
7001 mDocElementContainingBlock = nullptr;
7002 mCanvasFrame = nullptr;
7003 mPageSequenceFrame = nullptr;
7004 }
7005
7006 if (haveFLS && mRootElementFrame) {
7007 RecoverLetterFrames(containingBlock);
7008 }
7009
7010 if (!canSkipWhitespaceFixup) {
7011 MOZ_ASSERT(aChild->GetParentNode(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetParentNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChild->GetParentNode()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->GetParentNode()"
" (" "How did we have a sibling without a parent?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7012); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7012 "How did we have a sibling without a parent?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->GetParentNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChild->GetParentNode()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->GetParentNode()"
" (" "How did we have a sibling without a parent?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7012); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7013 // Adjacent whitespace-only text nodes might have been suppressed if
7014 // this node does not have inline ends. Create frames for them now
7015 // if necessary.
7016 // Reframe any text node just before the node being removed, if there is
7017 // one, and if it's not the last child or the first child. If a whitespace
7018 // textframe was being suppressed and it's now the last child or first
7019 // child then it can stay suppressed since the parent must be a block
7020 // and hence it's adjacent to a block end.
7021 // If aOldNextSibling is null, then the text node before the node being
7022 // removed is the last node, and we don't need to worry about it.
7023 nsIContent* prevSibling = aChild->GetPreviousSibling();
7024 if (prevSibling && prevSibling->GetPreviousSibling()) {
7025 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7026 ReframeTextIfNeeded(prevSibling);
7027 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7028 }
7029 // Reframe any text node just after the node being removed, if there is
7030 // one, and if it's not the last child or the first child.
7031 nsIContent* nextSibling = aChild->GetNextSibling();
7032 if (nextSibling && prevSibling && nextSibling->GetNextSibling()) {
7033 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7034 ReframeTextIfNeeded(nextSibling);
7035 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7036 }
7037 }
7038
7039#ifdef DEBUG1
7040 if (gReallyNoisyContentUpdates && parentFrame) {
7041 printf(
7042 "nsCSSFrameConstructor::ContentWillBeRemoved: resulting frame "
7043 "model:\n");
7044 parentFrame->List(stdoutstdout);
7045 }
7046#endif
7047
7048 return false;
7049}
7050
7051/**
7052 * This method invalidates the canvas when frames are removed or added for a
7053 * node that might have its background propagated to the canvas, i.e., a
7054 * document root node or an HTML BODY which is a child of the root node.
7055 *
7056 * @param aFrame a frame for a content node about to be removed or a frame that
7057 * was just created for a content node that was inserted.
7058 */
7059static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode) {
7060 MOZ_ASSERT(aPresShell->GetRootFrame(), "What happened here?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell->GetRootFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell->GetRootFrame(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPresShell->GetRootFrame()" " (" "What happened here?" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7060); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPresShell->GetRootFrame()" ") (" "What happened here?"
")"); do { MOZ_CrashSequence(__null, 7060); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7061 MOZ_ASSERT(aPresShell->GetPresContext(), "Say what?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell->GetPresContext())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell->GetPresContext
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPresShell->GetPresContext()" " (" "Say what?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell->GetPresContext()"
") (" "Say what?" ")"); do { MOZ_CrashSequence(__null, 7061)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
7062
7063 // Note that both in ContentWillBeRemoved and ContentInserted the content
7064 // node will still have the right parent pointer, so looking at that is ok.
7065
7066 nsIContent* parent = aNode->GetParent();
7067 if (parent) {
7068 // Has a parent; might not be what we want
7069 nsIContent* grandParent = parent->GetParent();
7070 if (grandParent) {
7071 // Has a grandparent, so not what we want
7072 return;
7073 }
7074
7075 // Check whether it's an HTML body
7076 if (!aNode->IsHTMLElement(nsGkAtoms::body)) {
7077 return;
7078 }
7079 }
7080
7081 // At this point the node has no parent or it's an HTML <body> child of the
7082 // root. We might not need to invalidate in this case (eg we might be in
7083 // XHTML or something), but chances are we want to. Play it safe.
7084 // Invalidate the viewport.
7085
7086 nsIFrame* rootFrame = aPresShell->GetRootFrame();
7087 rootFrame->InvalidateFrameSubtree();
7088}
7089
7090bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
7091 CharacterData* aContent) {
7092 if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
7093 return false;
7094 }
7095
7096 if (mAlwaysCreateFramesForIgnorableWhitespace) {
7097 return false;
7098 }
7099
7100 // Text frame may have been suppressed. Disable suppression and signal that a
7101 // flush should be performed. We do this on a document-wide basis so that
7102 // pages that repeatedly query metrics for collapsed-whitespace text nodes
7103 // don't trigger pathological behavior.
7104 mAlwaysCreateFramesForIgnorableWhitespace = true;
7105 Element* root = mDocument->GetRootElement();
7106 if (!root) {
7107 return false;
7108 }
7109
7110 RestyleManager()->PostRestyleEvent(root, RestyleHint{0},
7111 nsChangeHint_ReconstructFrame);
7112 return true;
7113}
7114
7115void nsCSSFrameConstructor::CharacterDataChanged(
7116 nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
7117 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::CharacterDataChanged",mozilla::AutoProfilerLabelHot raiiObject7118( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
7118 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject7118( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
7119 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
7120
7121 if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
7122 !aContent->TextIsOnlyWhitespace()) ||
7123 (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
7124 aContent->TextIsOnlyWhitespace())) {
7125#ifdef DEBUG1
7126 nsIFrame* frame = aContent->GetPrimaryFrame();
7127 NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),do { if (!(!frame || !frame->IsGeneratedContentFrame())) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Bit should never be set on generated content"
, "!frame || !frame->IsGeneratedContentFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7128); MOZ_PretendNoReturn(); } } while (0)
7128 "Bit should never be set on generated content")do { if (!(!frame || !frame->IsGeneratedContentFrame())) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Bit should never be set on generated content"
, "!frame || !frame->IsGeneratedContentFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7128); MOZ_PretendNoReturn(); } } while (0)
;
7129#endif
7130 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7131 RecreateFramesForContent(aContent, InsertionKind::Async);
7132 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7133 return;
7134 }
7135
7136 // It's possible the frame whose content changed isn't inserted into the
7137 // frame hierarchy yet, or that there is no frame that maps the content
7138 nsIFrame* frame = aContent->GetPrimaryFrame();
7139 if (!frame) {
7140 return;
7141 }
7142
7143 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7144 if (ShouldRebuildFrameTreeForReplicatedFrames(frame)) {
7145 // NOTE: This also defers the destruction, effectively, unlike
7146 // RecreateFramesForContent(). CharacterDataChanged may run during counter
7147 // updates where tearing down the whole frame tree isn't safe.
7148 RestyleManager()->PostRestyleEvent(mDocument->GetRootElement(),
7149 RestyleHint{0},
7150 nsChangeHint_ReconstructFrame);
7151 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7152 return;
7153 }
7154 if (frame->HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI)) {
7155 RecreateFramesForContent(aContent, InsertionKind::Async);
7156 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7157 return;
7158 }
7159 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7160
7161 // Special check for text content that is a child of a letter frame. If
7162 // this happens, we should remove the letter frame, do whatever we're
7163 // planning to do with this notification, then put the letter frame back.
7164 // Note that this is basically what RecreateFramesForContent ends up doing;
7165 // the reason we dont' want to call that here is that our text content
7166 // could be native anonymous, in which case RecreateFramesForContent would
7167 // completely barf on it. And recreating the non-anonymous ancestor would
7168 // just lead us to come back into this notification (e.g. if quotes or
7169 // counters are involved), leading to a loop.
7170 nsContainerFrame* block = GetFloatContainingBlock(frame);
7171 // See if the block has first-letter style applied to it.
7172 bool haveFirstLetterStyle = block && HasFirstLetterStyle(block);
7173 if (haveFirstLetterStyle) {
7174 RemoveLetterFrames(mPresShell, block);
7175 // Reget |frame|, since we might have killed it.
7176 // Do we really need to call CharacterDataChanged in this case, though?
7177 frame = aContent->GetPrimaryFrame();
7178 NS_ASSERTION(frame, "Should have frame here!")do { if (!(frame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have frame here!"
, "frame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7178); MOZ_PretendNoReturn(); } } while (0)
;
7179 }
7180
7181 // Notify the first frame that maps the content. It will generate a reflow
7182 // command
7183 frame->CharacterDataChanged(aInfo);
7184
7185 if (haveFirstLetterStyle) {
7186 RecoverLetterFrames(block);
7187 }
7188}
7189
7190void nsCSSFrameConstructor::RecalcQuotesAndCounters() {
7191 nsAutoScriptBlocker scriptBlocker;
7192
7193 if (mQuotesDirty) {
7194 mQuotesDirty = false;
7195 mContainStyleScopeManager.RecalcAllQuotes();
7196 }
7197
7198 if (mCountersDirty) {
7199 mCountersDirty = false;
7200 mContainStyleScopeManager.RecalcAllCounters();
7201 }
7202
7203 NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost")do { if (!(!mQuotesDirty)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Quotes updates will be lost", "!mQuotesDirty", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7203); MOZ_PretendNoReturn(); } } while (0)
;
7204 NS_ASSERTION(!mCountersDirty, "Counter updates will be lost")do { if (!(!mCountersDirty)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Counter updates will be lost", "!mCountersDirty", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7204); MOZ_PretendNoReturn(); } } while (0)
;
7205}
7206
7207void nsCSSFrameConstructor::NotifyCounterStylesAreDirty() {
7208 mContainStyleScopeManager.SetAllCountersDirty();
7209 CountersDirty();
7210}
7211
7212void nsCSSFrameConstructor::WillDestroyFrameTree() {
7213#if defined(DEBUG_dbaron_off)
7214 mContainStyleScopeManager.DumpCounters();
7215#endif
7216
7217 // Prevent frame tree destruction from being O(N^2)
7218 mContainStyleScopeManager.Clear();
7219 nsFrameManager::Destroy();
7220}
7221
7222// STATIC
7223
7224// XXXbz I'd really like this method to go away. Once we have inline-block and
7225// I can just use that for sized broken images, that can happen, maybe.
7226//
7227// NOTE(emilio): This needs to match the UA sheet.
7228void nsCSSFrameConstructor::GetAlternateTextFor(const Element& aElement,
7229 nsAString& aAltText) {
7230 // The "alt" attribute specifies alternate text that is rendered
7231 // when the image can not be displayed.
7232 if (aElement.GetAttr(nsGkAtoms::alt, aAltText)) {
7233 return;
7234 }
7235
7236 if (aElement.IsHTMLElement(nsGkAtoms::input)) {
7237 // If there's no "alt" attribute, and aElement is an input element, then use
7238 // the value of the "value" attribute.
7239 if (aElement.GetAttr(nsGkAtoms::value, aAltText)) {
7240 return;
7241 }
7242
7243 // If there's no "value" attribute either, then use the localized string for
7244 // "Submit" as the alternate text.
7245 nsContentUtils::GetMaybeLocalizedString(PropertiesFile::FORMS_PROPERTIES,
7246 "Submit", aElement.OwnerDoc(),
7247 aAltText);
7248 }
7249}
7250
7251nsIFrame* nsCSSFrameConstructor::CreateContinuingOuterTableFrame(
7252 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7253 ComputedStyle* aComputedStyle) {
7254 nsTableWrapperFrame* newFrame =
7255 NS_NewTableWrapperFrame(mPresShell, aComputedStyle);
7256
7257 newFrame->Init(aContent, aParentFrame, aFrame);
7258
7259 // Create a continuing inner table frame. Note we don't replicate the
7260 // captions: a comment used to hint at that, but the code dealing with that
7261 // never worked and was removed in bug 309322.
7262 nsFrameList newChildFrames;
7263
7264 MOZ_ASSERT(aFrame->IsTableWrapperFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->IsTableWrapperFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->IsTableWrapperFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aFrame->IsTableWrapperFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 7264); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7265 if (nsTableFrame* childFrame =
7266 static_cast<nsTableWrapperFrame*>(aFrame)->InnerTableFrame()) {
7267 nsIFrame* continuingTableFrame =
7268 CreateContinuingFrame(childFrame, newFrame);
7269 newChildFrames.AppendFrame(nullptr, continuingTableFrame);
7270 }
7271
7272 // Set the table wrapper's initial child list
7273 newFrame->SetInitialChildList(FrameChildListID::Principal,
7274 std::move(newChildFrames));
7275
7276 return newFrame;
7277}
7278
7279nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
7280 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7281 ComputedStyle* aComputedStyle) {
7282 nsTableFrame* newFrame = NS_NewTableFrame(mPresShell, aComputedStyle);
7283
7284 newFrame->Init(aContent, aParentFrame, aFrame);
7285
7286 // Replicate any header/footer frames
7287 nsFrameList childFrames;
7288 for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
7289 // See if it's a header/footer, possibly wrapped in a scroll frame.
7290 nsTableRowGroupFrame* rowGroupFrame =
7291 static_cast<nsTableRowGroupFrame*>(childFrame);
7292 // If the row group was continued, then don't replicate it.
7293 nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
7294 if (rgNextInFlow) {
7295 rowGroupFrame->SetRepeatable(false);
7296 } else if (rowGroupFrame->IsRepeatable()) {
7297 // Replicate the header/footer frame.
7298 nsTableRowGroupFrame* headerFooterFrame;
7299 nsFrameList childList;
7300
7301 nsFrameConstructorState state(
7302 mPresShell, nsFrameConstructorState::ForRepeatingTableHeaders);
7303 state.mCreatingExtraFrames = true;
7304
7305 ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
7306 headerFooterFrame = static_cast<nsTableRowGroupFrame*>(
7307 NS_NewTableRowGroupFrame(mPresShell, headerFooterComputedStyle));
7308
7309 nsIContent* headerFooter = rowGroupFrame->GetContent();
7310 headerFooterFrame->Init(headerFooter, newFrame, nullptr);
7311 if (rowGroupFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT)) {
7312 headerFooterFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
7313 state.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
7314 }
7315
7316 nsFrameConstructorSaveState absoluteSaveState;
7317 MakeTablePartAbsoluteContainingBlock(state, absoluteSaveState,
7318 headerFooterFrame);
7319
7320 nsFrameConstructorSaveState floatSaveState;
7321 state.MaybePushFloatContainingBlock(headerFooterFrame, floatSaveState);
7322
7323 ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
7324 headerFooterFrame, true, childList, false, nullptr);
7325 NS_ASSERTION(state.mFloatedList.IsEmpty(), "unexpected floated element")do { if (!(state.mFloatedList.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "unexpected floated element", "state.mFloatedList.IsEmpty()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7325); MOZ_PretendNoReturn
(); } } while (0)
;
7326 headerFooterFrame->SetInitialChildList(FrameChildListID::Principal,
7327 std::move(childList));
7328 headerFooterFrame->SetRepeatable(true);
7329
7330 // Table specific initialization
7331 headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
7332
7333 // XXX Deal with absolute and fixed frames...
7334 childFrames.AppendFrame(nullptr, headerFooterFrame);
7335 }
7336 }
7337
7338 // Set the table frame's initial child list
7339 newFrame->SetInitialChildList(FrameChildListID::Principal,
7340 std::move(childFrames));
7341
7342 return newFrame;
7343}
7344
7345nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
7346 nsIFrame* aFrame, nsContainerFrame* aParentFrame, bool aIsFluid) {
7347 ComputedStyle* computedStyle = aFrame->Style();
7348 nsIFrame* newFrame = nullptr;
7349 nsIFrame* nextContinuation = aFrame->GetNextContinuation();
7350 nsIFrame* nextInFlow = aFrame->GetNextInFlow();
7351
7352 // Use the frame type to determine what type of frame to create
7353 LayoutFrameType frameType = aFrame->Type();
7354 nsIContent* content = aFrame->GetContent();
7355
7356 if (LayoutFrameType::Text == frameType) {
7357 newFrame = NS_NewContinuingTextFrame(mPresShell, computedStyle);
7358 newFrame->Init(content, aParentFrame, aFrame);
7359 } else if (LayoutFrameType::Inline == frameType) {
7360 newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
7361 newFrame->Init(content, aParentFrame, aFrame);
7362 } else if (LayoutFrameType::Block == frameType) {
7363 MOZ_ASSERT(!aFrame->IsTableCaption(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7364
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7364); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7364 "no support for fragmenting table captions yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7364
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7364); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7365 newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
7366 newFrame->Init(content, aParentFrame, aFrame);
7367 } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
7368 newFrame = NS_NewColumnSetWrapperFrame(mPresShell, computedStyle,
7369 NS_FRAME_STATE_NONE);
7370 newFrame->Init(content, aParentFrame, aFrame);
7371 } else if (LayoutFrameType::ColumnSet == frameType) {
7372 MOZ_ASSERT(!aFrame->IsTableCaption(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7373
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7373); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7373 "no support for fragmenting table captions yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7373
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7373); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7374 newFrame =
7375 NS_NewColumnSetFrame(mPresShell, computedStyle, NS_FRAME_STATE_NONE);
7376 newFrame->Init(content, aParentFrame, aFrame);
7377 } else if (LayoutFrameType::PrintedSheet == frameType) {
7378 newFrame = ConstructPrintedSheetFrame(mPresShell, aParentFrame, aFrame);
7379 } else if (LayoutFrameType::Page == frameType) {
7380 nsCanvasFrame* canvasFrame; // (unused outparam for ConstructPageFrame)
7381 newFrame =
7382 ConstructPageFrame(mPresShell, aParentFrame, aFrame, canvasFrame);
7383 } else if (LayoutFrameType::TableWrapper == frameType) {
7384 newFrame = CreateContinuingOuterTableFrame(aFrame, aParentFrame, content,
7385 computedStyle);
7386 } else if (LayoutFrameType::Table == frameType) {
7387 newFrame = CreateContinuingTableFrame(aFrame, aParentFrame, content,
7388 computedStyle);
7389 } else if (LayoutFrameType::TableRowGroup == frameType) {
7390 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
7391 newFrame->Init(content, aParentFrame, aFrame);
7392 } else if (LayoutFrameType::TableRow == frameType) {
7393 nsTableRowFrame* rowFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
7394
7395 rowFrame->Init(content, aParentFrame, aFrame);
7396
7397 // Create a continuing frame for each table cell frame
7398 nsFrameList newChildList;
7399 nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
7400 while (cellFrame) {
7401 // See if it's a table cell frame
7402 if (cellFrame->IsTableCellFrame()) {
7403 nsIFrame* continuingCellFrame =
7404 CreateContinuingFrame(cellFrame, rowFrame);
7405 newChildList.AppendFrame(nullptr, continuingCellFrame);
7406 }
7407 cellFrame = cellFrame->GetNextSibling();
7408 }
7409
7410 rowFrame->SetInitialChildList(FrameChildListID::Principal,
7411 std::move(newChildList));
7412 newFrame = rowFrame;
7413
7414 } else if (LayoutFrameType::TableCell == frameType) {
7415 // Warning: If you change this and add a wrapper frame around table cell
7416 // frames, make sure Bug 368554 doesn't regress!
7417 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
7418 nsTableFrame* tableFrame =
7419 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
7420 nsTableCellFrame* cellFrame =
7421 NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
7422
7423 cellFrame->Init(content, aParentFrame, aFrame);
7424
7425 // Create a continuing area frame
7426 nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
7427 nsIFrame* continuingBlockFrame =
7428 CreateContinuingFrame(blockFrame, cellFrame);
7429
7430 SetInitialSingleChild(cellFrame, continuingBlockFrame);
7431 newFrame = cellFrame;
7432 } else if (LayoutFrameType::Line == frameType) {
7433 newFrame = NS_NewFirstLineFrame(mPresShell, computedStyle);
7434 newFrame->Init(content, aParentFrame, aFrame);
7435 } else if (LayoutFrameType::Letter == frameType) {
7436 newFrame = NS_NewFirstLetterFrame(mPresShell, computedStyle);
7437 newFrame->Init(content, aParentFrame, aFrame);
7438 } else if (LayoutFrameType::Image == frameType) {
7439 auto* imageFrame = static_cast<nsImageFrame*>(aFrame);
7440 newFrame = imageFrame->CreateContinuingFrame(mPresShell, computedStyle);
7441 newFrame->Init(content, aParentFrame, aFrame);
7442 } else if (LayoutFrameType::ImageControl == frameType) {
7443 newFrame = NS_NewImageControlFrame(mPresShell, computedStyle);
7444 newFrame->Init(content, aParentFrame, aFrame);
7445 } else if (LayoutFrameType::FieldSet == frameType) {
7446 newFrame = NS_NewFieldSetFrame(mPresShell, computedStyle);
7447 newFrame->Init(content, aParentFrame, aFrame);
7448 } else if (LayoutFrameType::FlexContainer == frameType) {
7449 newFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
7450 newFrame->Init(content, aParentFrame, aFrame);
7451 } else if (LayoutFrameType::GridContainer == frameType) {
7452 newFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
7453 newFrame->Init(content, aParentFrame, aFrame);
7454 } else if (LayoutFrameType::Ruby == frameType) {
7455 newFrame = NS_NewRubyFrame(mPresShell, computedStyle);
7456 newFrame->Init(content, aParentFrame, aFrame);
7457 } else if (LayoutFrameType::RubyBaseContainer == frameType) {
7458 newFrame = NS_NewRubyBaseContainerFrame(mPresShell, computedStyle);
7459 newFrame->Init(content, aParentFrame, aFrame);
7460 } else if (LayoutFrameType::RubyTextContainer == frameType) {
7461 newFrame = NS_NewRubyTextContainerFrame(mPresShell, computedStyle);
7462 newFrame->Init(content, aParentFrame, aFrame);
7463 } else {
7464 MOZ_CRASH("unexpected frame type")do { do { } while (false); MOZ_ReportCrash("" "unexpected frame type"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7464); AnnotateMozCrashReason
("MOZ_CRASH(" "unexpected frame type" ")"); do { MOZ_CrashSequence
(__null, 7464); __attribute__((nomerge)) ::abort(); } while (
false); } while (false)
;
7465 }
7466
7467 // Init() set newFrame to be a fluid continuation of aFrame.
7468 // If we want a non-fluid continuation, we need to call SetPrevContinuation()
7469 // to reset NS_FRAME_IS_FLUID_CONTINUATION.
7470 if (!aIsFluid) {
7471 newFrame->SetPrevContinuation(aFrame);
7472 }
7473
7474 // If a continuing frame needs to carry frame state bits from its previous
7475 // continuation or parent, set them in nsIFrame::Init(), or in any derived
7476 // frame class's Init() if the bits are belong to specific group.
7477
7478 if (nextInFlow) {
7479 nextInFlow->SetPrevInFlow(newFrame);
7480 newFrame->SetNextInFlow(nextInFlow);
7481 } else if (nextContinuation) {
7482 nextContinuation->SetPrevContinuation(newFrame);
7483 newFrame->SetNextContinuation(nextContinuation);
7484 }
7485
7486 // aFrame cannot be a dynamic reflow root because it has a continuation now.
7487 aFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
7488
7489 MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newFrame->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newFrame->GetNextSibling
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newFrame->GetNextSibling()" " (" "unexpected sibling" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7489); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!newFrame->GetNextSibling()" ") (" "unexpected sibling"
")"); do { MOZ_CrashSequence(__null, 7489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7490 return newFrame;
7491}
7492
7493void nsCSSFrameConstructor::MaybeSetNextPageContentFramePageName(
7494 const nsIFrame* aFrame) {
7495 MOZ_ASSERT(aFrame, "Frame should not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "Frame should not be null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7495
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Frame should not be null"
")"); do { MOZ_CrashSequence(__null, 7495); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7496 // No parent means the root frame, which isn't what this funciton is for.
7497 MOZ_ASSERT(aFrame->GetParent(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7498 "Frame should be the first child placed on a new page, not the "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7499 "root frame.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
7500 if (mNextPageContentFramePageName) {
7501 return;
7502 }
7503 const nsAtom* const autoValue = aFrame->GetParent()->GetAutoPageValue();
7504 mNextPageContentFramePageName = aFrame->ComputePageValue(autoValue);
7505}
7506
7507nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
7508 nsPageContentFrame* aParentFrame) {
7509 // Now deal with fixed-pos things.... They should appear on all pages,
7510 // so we want to move over the placeholders when processing the child
7511 // of the pageContentFrame.
7512
7513 nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
7514 if (!prevPageContentFrame) {
7515 return NS_OK;
7516 }
7517 nsContainerFrame* canvasFrame =
7518 do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
7519 nsIFrame* prevCanvasFrame =
7520 prevPageContentFrame->PrincipalChildList().FirstChild();
7521 if (!canvasFrame || !prevCanvasFrame) {
7522 // document's root element frame missing
7523 return NS_ERROR_UNEXPECTED;
7524 }
7525
7526 nsFrameList fixedPlaceholders;
7527 nsIFrame* firstFixed =
7528 prevPageContentFrame->GetChildList(FrameChildListID::Absolute)
7529 .FirstChild();
7530 if (!firstFixed) {
7531 return NS_OK;
7532 }
7533
7534 // Don't allow abs-pos descendants of the fixed content to escape the content.
7535 // This should not normally be possible (because fixed-pos elements should
7536 // be absolute containers) but fixed-pos tables currently aren't abs-pos
7537 // containers.
7538 nsFrameConstructorState state(mPresShell, aParentFrame, nullptr,
7539 mRootElementFrame);
7540 state.mCreatingExtraFrames = true;
7541
7542 // We can't use an ancestor filter here, because we're not going to
7543 // be usefully recurring down the tree. This means that other
7544 // places in frame construction can't assume a filter is
7545 // initialized!
7546
7547 // Iterate across fixed frames and replicate each whose placeholder is a
7548 // descendant of aFrame. (We don't want to explicitly copy placeholders that
7549 // are within fixed frames, because that would cause duplicates on the new
7550 // page - bug 389619)
7551 for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
7552 nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
7553 if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(
7554 prevCanvasFrame, prevPlaceholder)) {
7555 // We want to use the same style as the primary style frame for
7556 // our content
7557 nsIContent* content = fixed->GetContent();
7558 ComputedStyle* computedStyle =
7559 nsLayoutUtils::GetStyleFrame(content)->Style();
7560 ItemFlags flags{ItemFlag::AllowPageBreak};
7561 if (fixed->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT)) {
7562 flags += ItemFlag::IsGeneratedContent;
7563 }
7564 AutoFrameConstructionItemList items(this);
7565 AddFrameConstructionItemsInternal(state, content, canvasFrame, true,
7566 computedStyle, flags, items);
7567 ConstructFramesFromItemList(state, items, canvasFrame,
7568 /* aParentIsWrapperAnonBox = */ false,
7569 fixedPlaceholders);
7570 }
7571 }
7572
7573 // Add the placeholders to our primary child list.
7574 // XXXbz this is a little screwed up, since the fixed frames will have
7575 // broken auto-positioning. Oh, well.
7576 NS_ASSERTION(!canvasFrame->PrincipalChildList().FirstChild(),do { if (!(!canvasFrame->PrincipalChildList().FirstChild()
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "leaking frames; doc root continuation must be empty"
, "!canvasFrame->PrincipalChildList().FirstChild()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7577); MOZ_PretendNoReturn(); } } while (0)
7577 "leaking frames; doc root continuation must be empty")do { if (!(!canvasFrame->PrincipalChildList().FirstChild()
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "leaking frames; doc root continuation must be empty"
, "!canvasFrame->PrincipalChildList().FirstChild()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7577); MOZ_PretendNoReturn(); } } while (0)
;
7578 canvasFrame->SetInitialChildList(FrameChildListID::Principal,
7579 std::move(fixedPlaceholders));
7580 return NS_OK;
7581}
7582
7583nsCSSFrameConstructor::InsertionPoint nsCSSFrameConstructor::GetInsertionPoint(
7584 nsIContent* aChild) {
7585 MOZ_ASSERT(aChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7585); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 7585); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7586 nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
7587 if (!insertionElement) {
7588 // The element doesn't belong in the flattened tree, and thus we don't want
7589 // to render it.
7590 return {};
7591 }
7592
7593 return {GetContentInsertionFrameFor(insertionElement), insertionElement};
7594}
7595
7596static bool IsWhitespaceFrame(nsIFrame* aFrame) {
7597 MOZ_ASSERT(aFrame, "invalid argument")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "invalid argument"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7597
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 7597); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7598 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
7599}
7600
7601static nsIFrame* FindNextNonWhitespaceSibling(nsIFrame* aFrame) {
7602 nsIFrame* f = aFrame;
7603 do {
7604 f = f->GetNextSibling();
7605 } while (f && IsWhitespaceFrame(f));
7606 return f;
7607}
7608
7609static nsIFrame* FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) {
7610 nsIFrame* f = aFrame;
7611 do {
7612 f = f->GetPrevSibling();
7613 } while (f && IsWhitespaceFrame(f));
7614 return f;
7615}
7616
7617// Returns the closest table fragmented across pages to aFrame, including
7618// itself. Such tables can't deal with removals or insertions properly in
7619// paginated contexts (see nsTableCellMap::Synchronize and
7620// CreateContinuingTableFrame).
7621static nsIFrame* GetNearestFragmentedTable(nsIFrame* aFrame) {
7622 for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
7623 if (f->IsTableFrame() && (f->GetPrevInFlow() || f->GetNextInFlow())) {
7624 return f;
7625 }
7626 }
7627 return nullptr;
7628}
7629
7630static nsIFrame* CheckRubyContainers(nsIFrame* aFrame, nsIFrame* aParent) {
7631 auto* ancestor = aParent;
7632 auto* ancestorChild = aFrame;
7633 while (ancestor && IsWrapperPseudo(ancestor) &&
7634 CanRemoveWrapperPseudoForChildRemoval(ancestorChild, ancestor)) {
7635 ancestorChild = ancestor;
7636 ancestor = ancestorChild->GetParent();
7637 }
7638 if (!ancestor) {
7639 return nullptr;
7640 }
7641 const auto ancestorType = ancestor->Type();
7642 if (ancestorType != LayoutFrameType::Ruby &&
7643 !RubyUtils::IsRubyContainerBox(ancestorType)) {
7644 return nullptr;
7645 }
7646 return ancestor;
7647}
7648
7649// Fragmented tables and replicated fixed-pos frames on subsequent pages
7650// can't deal with removals. Rebuild the whole document instead, which also
7651// makes sure that the new frames get reflowed, since paginated documents
7652// don't do incremental reflow (see nsPageSequenceFrame::Reflow).
7653bool nsCSSFrameConstructor::ShouldRebuildFrameTreeForReplicatedFrames(
7654 nsIFrame* aFrame) {
7655 if (!aFrame->PresContext()->IsPaginated()) {
7656 return false;
7657 }
7658 if (aFrame->GetContent() == mDocument->GetRootElement()) {
7659 return false;
7660 }
7661 nsIFrame* inFlowFrame = aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
7662 ? aFrame->GetPlaceholderFrame()
7663 : aFrame;
7664 return GetNearestFragmentedTable(inFlowFrame) ||
7665 aFrame->IsInReplicatedFixedPosTree() ||
7666 aFrame->ContainsReplicatedFixedPosPlaceholders();
7667}
7668
7669bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
7670 nsIFrame* aFrame) {
7671#define TRACE(reason) \
7672 PROFILER_MARKER("MaybeRecreateContainerForFrameRemoval: " reason, LAYOUT, \do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("MaybeRecreateContainerForFrameRemoval: " reason, ::geckoprofiler
::category::LAYOUT, {}, ::geckoprofiler::markers::Tracing{}, "Layout"
); } } while (false); } while (false)
7673 {}, Tracing, "Layout")do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("MaybeRecreateContainerForFrameRemoval: " reason, ::geckoprofiler
::category::LAYOUT, {}, ::geckoprofiler::markers::Tracing{}, "Layout"
); } } while (false); } while (false)
7674 MOZ_ASSERT(aFrame, "Must have a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "Must have a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7674
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have a frame"
")"); do { MOZ_CrashSequence(__null, 7674); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7675 MOZ_ASSERT(aFrame->GetParent(), "Frame shouldn't be root")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame shouldn't be root" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame shouldn't be root" ")"); do { MOZ_CrashSequence
(__null, 7675); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7676 MOZ_ASSERT(aFrame == aFrame->FirstContinuation(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame == aFrame->FirstContinuation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aFrame == aFrame->FirstContinuation()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aFrame == aFrame->FirstContinuation()"
" (" "aFrame not the result of GetPrimaryFrame()?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7677); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7677 "aFrame not the result of GetPrimaryFrame()?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame == aFrame->FirstContinuation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aFrame == aFrame->FirstContinuation()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aFrame == aFrame->FirstContinuation()"
" (" "aFrame not the result of GetPrimaryFrame()?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7677); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7678
7679 nsIFrame* inFlowFrame = aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
7680 ? aFrame->GetPlaceholderFrame()
7681 : aFrame;
7682 MOZ_ASSERT(inFlowFrame, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inFlowFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inFlowFrame))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("inFlowFrame" " ("
"How did that happen?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7682); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 7682); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
7683 MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inFlowFrame == inFlowFrame->FirstContinuation())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(inFlowFrame == inFlowFrame->FirstContinuation()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("inFlowFrame == inFlowFrame->FirstContinuation()"
" (" "placeholder for primary frame has previous continuations?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7684 "placeholder for primary frame has previous continuations?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inFlowFrame == inFlowFrame->FirstContinuation())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(inFlowFrame == inFlowFrame->FirstContinuation()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("inFlowFrame == inFlowFrame->FirstContinuation()"
" (" "placeholder for primary frame has previous continuations?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7685
7686 if (ShouldRebuildFrameTreeForReplicatedFrames(aFrame)) {
7687 TRACE("Paginated fragmented content");
7688 RecreateFramesForContent(mDocument->GetRootElement(), InsertionKind::Async);
7689 return true;
7690 }
7691
7692 nsIFrame* parent = inFlowFrame->GetParent();
7693 if (inFlowFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
7694 nsIFrame* grandparent = parent->GetParent();
7695 MOZ_ASSERT(grandparent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(grandparent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(grandparent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("grandparent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7695); AnnotateMozCrashReason("MOZ_ASSERT" "(" "grandparent"
")"); do { MOZ_CrashSequence(__null, 7695); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7696
7697 bool needsReframe =
7698 // 1. Removing a column-span may lead to an empty
7699 // ::-moz-column-span-wrapper.
7700 inFlowFrame->IsColumnSpan() ||
7701 // 2. Removing a frame which has any column-span siblings may also
7702 // lead to an empty ::-moz-column-span-wrapper subtree. The
7703 // column-span siblings were the frame's children, but later become
7704 // the frame's siblings after CreateColumnSpanSiblings().
7705 inFlowFrame->HasColumnSpanSiblings() ||
7706 // 3. Removing the only child of a ::-moz-column-content, whose
7707 // ColumnSet grandparent has a previous column-span sibling, requires
7708 // reframing since we might connect the ColumnSet's next column-span
7709 // sibling (if there's one). Note that this isn't actually needed if
7710 // the ColumnSet is at the end of ColumnSetWrapper since we create
7711 // empty ones at the end anyway, but we're not worried about
7712 // optimizing that case.
7713 (parent->Style()->GetPseudoType() ==
7714 PseudoStyleType::MozColumnContent &&
7715 // The only child in ::-moz-column-content (might be tall enough to
7716 // split across columns)
7717 !inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7718 // That ::-moz-column-content is the first column.
7719 !parent->GetPrevInFlow() &&
7720 // The ColumnSet grandparent has a previous sibling that is a
7721 // column-span.
7722 grandparent->GetPrevSibling());
7723
7724 if (needsReframe) {
7725 nsContainerFrame* containingBlock =
7726 GetMultiColumnContainingBlockFor(inFlowFrame);
7727
7728#ifdef DEBUG1
7729 if (IsFramePartOfIBSplit(inFlowFrame)) {
7730 nsIFrame* ibContainingBlock = GetIBContainingBlockFor(inFlowFrame);
7731 MOZ_ASSERT(containingBlock == ibContainingBlock ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
" (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
") (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")"); do { MOZ_CrashSequence
(__null, 7735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7732 nsLayoutUtils::IsProperAncestorFrame(containingBlock,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
" (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
") (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")"); do { MOZ_CrashSequence
(__null, 7735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7733 ibContainingBlock),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
" (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
") (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")"); do { MOZ_CrashSequence
(__null, 7735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7734 "Multi-column containing block should be equal to or be the "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
" (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
") (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")"); do { MOZ_CrashSequence
(__null, 7735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7735 "ancestor of the IB containing block!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(containingBlock == ibContainingBlock || nsLayoutUtils
::IsProperAncestorFrame(containingBlock, ibContainingBlock)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
" (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "containingBlock == ibContainingBlock || nsLayoutUtils::IsProperAncestorFrame(containingBlock, ibContainingBlock)"
") (" "Multi-column containing block should be equal to or be the "
"ancestor of the IB containing block!" ")"); do { MOZ_CrashSequence
(__null, 7735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7736 }
7737#endif
7738
7739 TRACE("Multi-column");
7740 RecreateFramesForContent(containingBlock->GetContent(),
7741 InsertionKind::Async);
7742 return true;
7743 }
7744 }
7745
7746 if (IsFramePartOfIBSplit(aFrame)) {
7747 // The removal functions can't handle removal of an {ib} split directly; we
7748 // need to rebuild the containing block.
7749 TRACE("IB split removal");
7750 ReframeContainingBlock(aFrame);
7751 return true;
7752 }
7753
7754 if (inFlowFrame->IsRenderedLegend()) {
7755 TRACE("Fieldset / Legend");
7756 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7757 return true;
7758 }
7759
7760 // Might need to reconstruct things if this frame's nextSibling is a table
7761 // or ruby pseudo, since removal of this frame might mean that this pseudo
7762 // needs to get merged with the frame's prevSibling if that's also a table
7763 // or ruby pseudo.
7764 nsIFrame* nextSibling =
7765 FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
7766 NS_ASSERTION(!IsWrapperPseudo(inFlowFrame),do { if (!(!IsWrapperPseudo(inFlowFrame))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Shouldn't happen here (we start removals from primary frames)"
, "!IsWrapperPseudo(inFlowFrame)", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7767); MOZ_PretendNoReturn(); } } while (0)
7767 "Shouldn't happen here (we start removals from primary frames)")do { if (!(!IsWrapperPseudo(inFlowFrame))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Shouldn't happen here (we start removals from primary frames)"
, "!IsWrapperPseudo(inFlowFrame)", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7767); MOZ_PretendNoReturn(); } } while (0)
;
7768 // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
7769 // need to be checked here, since all other types of such frames will have
7770 // a ruby container parent, and be catched by "Check ruby containers" below.
7771 if (nextSibling && IsWrapperPseudo(nextSibling)) {
7772 nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
7773 if (prevSibling && IsWrapperPseudo(prevSibling)) {
7774 TRACE("Pseudo sibling");
7775 // Good enough to recreate frames for aFrame's parent's content; even if
7776 // aFrame's parent is a pseudo, that'll be the right content node.
7777 // FIXME(emilio): Consider doing a more subtle check here like, only if
7778 // prevSibling and nextSibling share frame type. Or even consider just
7779 // moving the frames around and destroying nextSibling?
7780 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7781 return true;
7782 }
7783 }
7784
7785 // Check ruby containers
7786 if (const auto* ancestor = CheckRubyContainers(inFlowFrame, parent)) {
7787 // In ruby containers, pseudo frames may be created from
7788 // whitespaces or even nothing. There are two cases we actually
7789 // need to handle here, but hard to check exactly:
7790 // 1. Status of spaces beside the frame may vary, and related
7791 // frames may be constructed or destroyed accordingly.
7792 // 2. The type of the first child of a ruby frame determines
7793 // whether a pseudo ruby base container should exist.
7794 TRACE("Ruby container");
7795 RecreateFramesForContent(ancestor->GetContent(), InsertionKind::Async);
7796 return true;
7797 }
7798
7799 // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
7800 // a non-fluid continuation, i.e. it was split by bidi resolution
7801 if (!inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7802 ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
7803 (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
7804 TRACE("Removing last child of non-fluid split parent");
7805 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7806 return true;
7807 }
7808
7809 // We might still need to reconstruct things if the parent of inFlowFrame is
7810 // ib-split, since in that case the removal of aFrame might affect the
7811 // splitting of its parent.
7812 if (!IsFramePartOfIBSplit(parent)) {
7813 return false;
7814 }
7815
7816 // If inFlowFrame is not the only in-flow child of |parent|, then removing
7817 // it will change nothing about the {ib} split.
7818 if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
7819 inFlowFrame->LastContinuation()->GetNextSibling()) {
7820 return false;
7821 }
7822
7823 // If the parent is the first or last part of the {ib} split, then
7824 // removing one of its kids will have no effect on the splitting.
7825 // Get the first continuation up front so we don't have to do it twice.
7826 nsIFrame* parentFirstContinuation = parent->FirstContinuation();
7827 if (!GetIBSplitSibling(parentFirstContinuation) ||
7828 !GetIBSplitPrevSibling(parentFirstContinuation)) {
7829 return false;
7830 }
7831
7832 TRACE("IB split parent");
7833 ReframeContainingBlock(parent);
7834 return true;
7835#undef TRACE
7836}
7837
7838void nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent) {
7839 nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
7840
7841 // It's possible that this warning could fire if some other style change
7842 // simultaneously changes the 'display' of the element and makes it no
7843 // longer be a table cell.
7844 NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!")do { if (!(cellFrame)) { NS_DebugBreak(NS_DEBUG_WARNING, "Hint should only be posted on table cells!"
, "cellFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7844); } } while (false)
;
7845
7846 if (cellFrame) {
7847 cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
7848 }
7849}
7850
7851static nsIContent* GetTopmostMathMLElement(nsIContent* aMathMLContent) {
7852 MOZ_ASSERT(aMathMLContent->IsMathMLElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMathMLContent->IsMathMLElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMathMLContent->IsMathMLElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aMathMLContent->IsMathMLElement()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->IsMathMLElement()"
")"); do { MOZ_CrashSequence(__null, 7852); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7853 MOZ_ASSERT(aMathMLContent->GetPrimaryFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMathMLContent->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMathMLContent->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aMathMLContent->GetPrimaryFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7853); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()"
")"); do { MOZ_CrashSequence(__null, 7853); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7854 MOZ_ASSERT(aMathMLContent->GetPrimaryFrame()->IsMathMLFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMathMLContent->GetPrimaryFrame()->IsMathMLFrame
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMathMLContent->GetPrimaryFrame()->IsMathMLFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aMathMLContent->GetPrimaryFrame()->IsMathMLFrame()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()->IsMathMLFrame()"
")"); do { MOZ_CrashSequence(__null, 7854); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7855 nsIContent* root = aMathMLContent;
7856
7857 for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent(); parent;
7858 parent = parent->GetFlattenedTreeParent()) {
7859 nsIFrame* frame = parent->GetPrimaryFrame();
7860 if (!frame || !frame->IsMathMLFrame()) {
7861 break;
7862 }
7863 root = parent;
7864 }
7865
7866 return root;
7867}
7868
7869// We don't know how to re-insert an anonymous subtree root, so recreate the
7870// closest non-generated ancestor instead, except for a few special cases...
7871static bool ShouldRecreateContainerForNativeAnonymousContentRoot(
7872 nsIContent* aContent) {
7873 if (!aContent->IsRootOfNativeAnonymousSubtree()) {
7874 return false;
7875 }
7876 if (ManualNACPtr::IsManualNAC(aContent)) {
7877 // Editor NAC, would enter an infinite loop, and we sorta get away with it
7878 // because it's all abspos.
7879 return false;
7880 }
7881 if (auto* el = Element::FromNode(aContent)) {
7882 if (el->GetPseudoElementType() ==
7883 PseudoStyleType::MozSnapshotContainingBlock) {
7884 // Much like above, all abspos and on its own top layer so insertion order
7885 // wouldn't really matter anyways.
7886 return false;
7887 }
7888 if (auto* classes = el->GetClasses()) {
7889 if (classes->Contains(nsGkAtoms::mozCustomContentContainer,
7890 eCaseMatters)) {
7891 // Canvas anonymous content (like the custom content container) is also
7892 // fine, because its only sibling is a tooltip which is also abspos, so
7893 // relative insertion order doesn't really matter.
7894 //
7895 // This is important because the inspector uses it, and we don't want
7896 // inspecting the page to change behavior heavily (and reframing
7897 // unfortunately has side-effects sometimes, even though they're bugs).
7898 return false;
7899 }
7900 }
7901 }
7902
7903 return true;
7904}
7905
7906void nsCSSFrameConstructor::RecreateFramesForContent(
7907 nsIContent* aContent, InsertionKind aInsertionKind) {
7908 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { MOZ_CrashSequence(__null, 7908); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7909
7910 // If there is no document, we don't want to recreate frames for it. (You
7911 // shouldn't generally be giving this method content without a document
7912 // anyway).
7913 // Rebuilding the frame tree can have bad effects, especially if it's the
7914 // frame tree for chrome (see bug 157322).
7915 if (NS_WARN_IF(!aContent->GetComposedDoc())NS_warn_if_impl(!aContent->GetComposedDoc(), "!aContent->GetComposedDoc()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7915)
) {
7916 return;
7917 }
7918
7919 // TODO(emilio): We technically can find the right insertion point nowadays
7920 // using StyleChildrenIterator rather than FlattenedChildIterator. But we'd
7921 // need to tweak the setup to insert into replaced elements to filter which
7922 // anonymous roots can be allowed, and which can't.
7923 //
7924 // TODO(emilio, 2022): Is this true? If we have a replaced element we wouldn't
7925 // have generated e.g., a ::before/::after pseudo-element to begin with (which
7926 // is what this code is about, so maybe we can just remove this piece of code
7927 // altogether).
7928 if (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent)) {
7929 do {
7930 aContent = aContent->GetParent();
7931 } while (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent));
7932 return RecreateFramesForContent(aContent, InsertionKind::Async);
7933 }
7934
7935 nsIFrame* frame = aContent->GetPrimaryFrame();
7936 if (frame && frame->IsMathMLFrame()) {
7937 // Reframe the topmost MathML element to prevent exponential blowup
7938 // (see bug 397518).
7939 aContent = GetTopmostMathMLElement(aContent);
7940 frame = aContent->GetPrimaryFrame();
7941 }
7942
7943 if (frame) {
7944 nsIFrame* parent = frame->GetParent();
7945 nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
7946 // If the parent frame is a leaf then the subsequent insert will fail to
7947 // create a frame, so we need to recreate the parent content. This happens
7948 // with native anonymous content from the editor.
7949 if (parent && parent->IsLeaf() && parentContent &&
7950 parentContent != aContent) {
7951 return RecreateFramesForContent(parentContent, InsertionKind::Async);
7952 }
7953 }
7954
7955 if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
7956 return;
7957 }
7958
7959 MOZ_ASSERT(aContent->GetParentNode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->GetParentNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->GetParentNode()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aContent->GetParentNode()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 7959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7960 const auto removalKind = [&] {
7961 if (aInsertionKind == InsertionKind::Sync && aContent->IsElement() &&
7962 Servo_Element_IsDisplayNone(aContent->AsElement())) {
7963 // If we know we're not going to have frames after reconstructing, it's
7964 // more efficient to do some of that work (a11y notifications, fixing-up
7965 // text nodes) earlier.
7966 return RemovalKind::ForDisplayNoneChange;
7967 }
7968 return RemovalKind::ForReconstruction;
7969 }();
7970 const bool didReconstruct = ContentWillBeRemoved(aContent, removalKind);
7971 if (didReconstruct || removalKind == RemovalKind::ForDisplayNoneChange) {
7972 // If ContentWillBeRemoved triggered reconstruction, then we don't need to
7973 // do anything else because the frames will already have been built.
7974 return;
7975 }
7976 if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
7977 // FIXME(emilio, bug 1397239): There's nothing removing the frame state
7978 // for elements that go away before we come back to the frame constructor.
7979 //
7980 // Also, it'd be nice to just use the `ContentRangeInserted` path for
7981 // both elements and non-elements, but we need to make lazy frame
7982 // construction to apply to all elements first.
7983 //
7984 // TODO(emilio): I think lazy frame construction works everywhere now, so
7985 // maybe we can remove this altogether?
7986 RestyleManager()->PostRestyleEvent(aContent->AsElement(), RestyleHint{0},
7987 nsChangeHint_ReconstructFrame);
7988 return;
7989 }
7990 // Now, recreate the frames associated with this content object.
7991 ContentRangeInserted(aContent, aContent->GetNextSibling(), aInsertionKind);
7992}
7993
7994bool nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent) {
7995 MOZ_ASSERT(aContent && aContent->GetParentNode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent && aContent->GetParentNode())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent && aContent->GetParentNode()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aContent && aContent->GetParentNode()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7995); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContent && aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 7995); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7996 return ContentWillBeRemoved(aContent, RemovalKind::ForReconstruction);
7997}
7998
7999//////////////////////////////////////////////////////////////////////
8000
8001// Block frame construction code
8002
8003already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLetterStyle(
8004 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8005 if (aContent) {
8006 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
8007 *aContent->AsElement(), PseudoStyleType::FirstLetter, nullptr,
8008 aComputedStyle);
8009 }
8010 return nullptr;
8011}
8012
8013already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLineStyle(
8014 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8015 if (aContent) {
8016 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
8017 *aContent->AsElement(), PseudoStyleType::FirstLine, nullptr,
8018 aComputedStyle);
8019 }
8020 return nullptr;
8021}
8022
8023// Predicate to see if a given content (block element) has
8024// first-letter style applied to it.
8025bool nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(
8026 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8027 return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
8028 PseudoStyleType::FirstLetter,
8029 mPresShell->GetPresContext());
8030}
8031
8032bool nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) {
8033 MOZ_ASSERT(aBlockFrame, "Need a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBlockFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBlockFrame))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aBlockFrame" " ("
"Need a frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBlockFrame"
") (" "Need a frame" ")"); do { MOZ_CrashSequence(__null, 8033
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8034 NS_ASSERTION(aBlockFrame->IsBlockFrameOrSubclass(), "Not a block frame?")do { if (!(aBlockFrame->IsBlockFrameOrSubclass())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Not a block frame?", "aBlockFrame->IsBlockFrameOrSubclass()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8034); MOZ_PretendNoReturn
(); } } while (0)
;
8035 return aBlockFrame->HasAnyStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
8036}
8037
8038bool nsCSSFrameConstructor::ShouldHaveFirstLineStyle(
8039 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8040 bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(
8041 aContent, aComputedStyle, PseudoStyleType::FirstLine,
8042 mPresShell->GetPresContext());
8043 return hasFirstLine &&
8044 !aContent->IsAnyOfHTMLElements(nsGkAtoms::fieldset, nsGkAtoms::input,
8045 nsGkAtoms::textarea);
8046}
8047
8048void nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(
8049 nsIContent* aContent, ComputedStyle* aComputedStyle,
8050 bool* aHaveFirstLetterStyle, bool* aHaveFirstLineStyle) {
8051 *aHaveFirstLetterStyle = ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
8052 *aHaveFirstLineStyle = ShouldHaveFirstLineStyle(aContent, aComputedStyle);
8053}
8054
8055/* static */
8056const nsCSSFrameConstructor::PseudoParentData
8057 nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
8058 // Cell
8059 {{&nsCSSFrameConstructor::ConstructTableCell,
8060 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8061 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8062 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28)},
8063 PseudoStyleType::MozTableCell},
8064 // Row
8065 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8066 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8067 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8068 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28)},
8069 PseudoStyleType::MozTableRow},
8070 // Row group
8071 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8072 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8073 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8074 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8075 PseudoStyleType::MozTableRowGroup},
8076 // Column group
8077 {{ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
8078 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 |
8079 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_USE_CHILD_ITEMS0x10000 |
8080 FCDATA_SKIP_ABSPOS_PUSH0x200 |
8081 // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
8082 // restyle these: they have non-inheriting styles.
8083 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8084 PseudoStyleType::MozTableColumnGroup},
8085 // Table
8086 {{&nsCSSFrameConstructor::ConstructTable,
8087 FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8088 FCDATA_IS_WRAPPER_ANON_BOX0x400000},
8089 PseudoStyleType::MozTable},
8090 // Ruby
8091 {{ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
,
8092 FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_USE_CHILD_ITEMS0x10000 |
8093 FCDATA_IS_WRAPPER_ANON_BOX0x400000 | FCDATA_SKIP_FRAMESET0x1},
8094 PseudoStyleType::MozRuby},
8095 // Ruby Base
8096 {{ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
8097 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8098 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8099 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28) |
8100 FCDATA_SKIP_FRAMESET0x1},
8101 PseudoStyleType::MozRubyBase},
8102 // Ruby Base Container
8103 {{ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
8104 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8105 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8106 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8107 FCDATA_SKIP_FRAMESET0x1},
8108 PseudoStyleType::MozRubyBaseContainer},
8109 // Ruby Text
8110 {{ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
8111 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8112 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8113 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28) |
8114 FCDATA_SKIP_FRAMESET0x1},
8115 PseudoStyleType::MozRubyText},
8116 // Ruby Text Container
8117 {{ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
8118 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8119 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8120 FCDATA_SKIP_FRAMESET0x1},
8121 PseudoStyleType::MozRubyTextContainer}};
8122
8123void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
8124 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8125 nsIFrame* aParentFrame) {
8126 if (aItems.IsEmpty()) {
8127 return;
8128 }
8129
8130 if (!aParentFrame->IsFlexOrGridContainer()) {
8131 return;
8132 }
8133
8134 const bool isLegacyWebKitBox =
8135 IsFlexContainerForLegacyWebKitBox(aParentFrame);
8136 FCItemIterator iter(aItems);
8137 do {
8138 // Advance iter past children that don't want to be wrapped
8139 if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState,
8140 isLegacyWebKitBox)) {
8141 // Hit the end of the items without finding any remaining children that
8142 // need to be wrapped. We're finished!
8143 return;
8144 }
8145
8146 // If our next potentially-wrappable child is whitespace, then see if
8147 // there's anything wrappable immediately after it. If not, we just drop
8148 // the whitespace and move on. (We're not supposed to create any anonymous
8149 // flex/grid items that _only_ contain whitespace).
8150 // (BUT if this is generated content, then we don't give whitespace nodes
8151 // any special treatment, because they're probably not really whitespace --
8152 // they're just temporarily empty, waiting for their generated text.)
8153 // XXXdholbert If this node's generated text will *actually end up being
8154 // entirely whitespace*, then we technically should still skip over it, per
8155 // the CSS grid & flexbox specs. I'm not bothering with that at this point,
8156 // since it's a pretty extreme edge case.
8157 if (!aParentFrame->IsGeneratedContentFrame() &&
8158 iter.item().IsWhitespace(aState)) {
8159 FCItemIterator afterWhitespaceIter(iter);
8160 bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
8161 bool nextChildNeedsAnonItem =
8162 !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(
8163 aState, isLegacyWebKitBox);
8164
8165 if (!nextChildNeedsAnonItem) {
8166 // There's nothing after the whitespace that we need to wrap, so we
8167 // just drop this run of whitespace.
8168 iter.DeleteItemsTo(this, afterWhitespaceIter);
8169 if (hitEnd) {
8170 // Nothing left to do -- we're finished!
8171 return;
8172 }
8173 // else, we have a next child and it does not want to be wrapped. So,
8174 // we jump back to the beginning of the loop to skip over that child
8175 // (and anything else non-wrappable after it)
8176 MOZ_ASSERT(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem
( aState, isLegacyWebKitBox))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.IsDone() && !iter
.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
" (" "hitEnd and/or nextChildNeedsAnonItem lied" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8178); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8177 aState, isLegacyWebKitBox),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem
( aState, isLegacyWebKitBox))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.IsDone() && !iter
.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
" (" "hitEnd and/or nextChildNeedsAnonItem lied" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8178); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8178 "hitEnd and/or nextChildNeedsAnonItem lied")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem
( aState, isLegacyWebKitBox))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.IsDone() && !iter
.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
" (" "hitEnd and/or nextChildNeedsAnonItem lied" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8178); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8179 continue;
8180 }
8181 }
8182
8183 // Now |iter| points to the first child that needs to be wrapped in an
8184 // anonymous flex/grid item. Now we see how many children after it also want
8185 // to be wrapped in an anonymous flex/grid item.
8186 FCItemIterator endIter(iter); // iterator to find the end of the group
8187 endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox);
8188
8189 NS_ASSERTION(iter != endIter,do { if (!(iter != endIter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should've had at least one wrappable child to seek past", "iter != endIter"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8190); MOZ_PretendNoReturn
(); } } while (0)
8190 "Should've had at least one wrappable child to seek past")do { if (!(iter != endIter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should've had at least one wrappable child to seek past", "iter != endIter"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8190); MOZ_PretendNoReturn
(); } } while (0)
;
8191
8192 // Now, we create the anonymous flex or grid item to contain the children
8193 // between |iter| and |endIter|.
8194 nsIContent* parentContent = aParentFrame->GetContent();
8195 RefPtr<ComputedStyle> wrapperStyle =
8196 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8197 PseudoStyleType::MozAnonymousItem, aParentFrame->Style());
8198
8199 static constexpr FrameConstructionData sBlockFCData(
8200 ToCreationFunc(NS_NewBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewBlockFrame(aPs, aStyle); }
, FCDATA_SKIP_FRAMESET0x1 |
8201 FCDATA_USE_CHILD_ITEMS0x10000 |
8202 FCDATA_IS_WRAPPER_ANON_BOX0x400000);
8203
8204 // Use the content of our parent frame
8205 auto* newItem = new (this) FrameConstructionItem(
8206 &sBlockFCData, parentContent, wrapperStyle.forget(), true);
8207
8208 newItem->mIsAllInline =
8209 newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
8210 newItem->mIsBlock = !newItem->mIsAllInline;
8211
8212 MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newItem->mIsAllInline && newItem->mIsBlock
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!newItem->mIsAllInline && newItem->mIsBlock
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!newItem->mIsAllInline && newItem->mIsBlock" " ("
"expecting anonymous flex/grid items to be block-level " "(this will make a difference when we encounter "
"'align-items: baseline')" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newItem->mIsAllInline && newItem->mIsBlock"
") (" "expecting anonymous flex/grid items to be block-level "
"(this will make a difference when we encounter " "'align-items: baseline')"
")"); do { MOZ_CrashSequence(__null, 8215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8213 "expecting anonymous flex/grid items to be block-level "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newItem->mIsAllInline && newItem->mIsBlock
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!newItem->mIsAllInline && newItem->mIsBlock
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!newItem->mIsAllInline && newItem->mIsBlock" " ("
"expecting anonymous flex/grid items to be block-level " "(this will make a difference when we encounter "
"'align-items: baseline')" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newItem->mIsAllInline && newItem->mIsBlock"
") (" "expecting anonymous flex/grid items to be block-level "
"(this will make a difference when we encounter " "'align-items: baseline')"
")"); do { MOZ_CrashSequence(__null, 8215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8214 "(this will make a difference when we encounter "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newItem->mIsAllInline && newItem->mIsBlock
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!newItem->mIsAllInline && newItem->mIsBlock
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!newItem->mIsAllInline && newItem->mIsBlock" " ("
"expecting anonymous flex/grid items to be block-level " "(this will make a difference when we encounter "
"'align-items: baseline')" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newItem->mIsAllInline && newItem->mIsBlock"
") (" "expecting anonymous flex/grid items to be block-level "
"(this will make a difference when we encounter " "'align-items: baseline')"
")"); do { MOZ_CrashSequence(__null, 8215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8215 "'align-items: baseline')")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newItem->mIsAllInline && newItem->mIsBlock
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!newItem->mIsAllInline && newItem->mIsBlock
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!newItem->mIsAllInline && newItem->mIsBlock" " ("
"expecting anonymous flex/grid items to be block-level " "(this will make a difference when we encounter "
"'align-items: baseline')" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newItem->mIsAllInline && newItem->mIsBlock"
") (" "expecting anonymous flex/grid items to be block-level "
"(this will make a difference when we encounter " "'align-items: baseline')"
")"); do { MOZ_CrashSequence(__null, 8215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8216
8217 // Anonymous flex and grid items induce line boundaries around their
8218 // contents.
8219 newItem->mChildItems.SetLineBoundaryAtStart(true);
8220 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8221 // The parent of the items in aItems is also the parent of the items
8222 // in mChildItems
8223 newItem->mChildItems.SetParentHasNoShadowDOM(aItems.ParentHasNoShadowDOM());
8224
8225 // Eat up all items between |iter| and |endIter| and put them in our
8226 // wrapper. This advances |iter| to point to |endIter|.
8227 iter.AppendItemsToList(this, endIter, newItem->mChildItems);
8228
8229 iter.InsertItem(newItem);
8230 } while (!iter.IsDone());
8231}
8232
8233/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8234nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
8235 StyleDisplay aNextDisplay) {
8236 MOZ_ASSERT(aPrevDisplay.IsRuby() && aNextDisplay.IsRuby())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrevDisplay.IsRuby() && aNextDisplay.IsRuby
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aPrevDisplay.IsRuby() && aNextDisplay.IsRuby
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevDisplay.IsRuby() && aNextDisplay.IsRuby()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevDisplay.IsRuby() && aNextDisplay.IsRuby()"
")"); do { MOZ_CrashSequence(__null, 8236); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8237 if (aPrevDisplay == aNextDisplay &&
8238 (aPrevDisplay == StyleDisplay::RubyBase ||
8239 aPrevDisplay == StyleDisplay::RubyText)) {
8240 return eRubyInterLeafWhitespace;
8241 }
8242 if (aNextDisplay == StyleDisplay::RubyText ||
8243 aNextDisplay == StyleDisplay::RubyTextContainer) {
8244 return eRubyInterLevelWhitespace;
8245 }
8246 return eRubyInterSegmentWhitespace;
8247}
8248
8249/**
8250 * This function checks the content from |aStartIter| to |aEndIter|,
8251 * determines whether it contains only whitespace, and if yes,
8252 * interprets the type of whitespace. This method does not change
8253 * any of the iters.
8254 */
8255/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8256nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
8257 const FCItemIterator& aStartIter,
8258 const FCItemIterator& aEndIter) {
8259 if (!aStartIter.item().IsWhitespace(aState)) {
8260 return eRubyNotWhitespace;
8261 }
8262
8263 FCItemIterator spaceEndIter(aStartIter);
8264 spaceEndIter.SkipWhitespace(aState);
8265 if (spaceEndIter != aEndIter) {
8266 return eRubyNotWhitespace;
8267 }
8268
8269 // Any leading or trailing whitespace in non-pseudo ruby box
8270 // should have been trimmed, hence there should not be any
8271 // whitespace at the start or the end.
8272 MOZ_ASSERT(!aStartIter.AtStart() && !aEndIter.IsDone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aStartIter.AtStart() && !aEndIter.IsDone())
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aStartIter.AtStart() && !aEndIter.IsDone())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aStartIter.AtStart() && !aEndIter.IsDone()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8272); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aStartIter.AtStart() && !aEndIter.IsDone()"
")"); do { MOZ_CrashSequence(__null, 8272); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8273 FCItemIterator prevIter(aStartIter);
8274 prevIter.Prev();
8275 return ComputeRubyWhitespaceType(
8276 prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
8277 aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
8278}
8279
8280/**
8281 * This function eats up consecutive items which do not want the current
8282 * parent into either a ruby base box or a ruby text box. When it
8283 * returns, |aIter| points to the first item it doesn't wrap.
8284 */
8285void nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
8286 FCItemIterator& aIter, ComputedStyle* aParentStyle,
8287 nsIContent* aParentContent) {
8288 StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
8289 ParentType parentType, wrapperType;
8290 if (parentDisplay == StyleDisplay::RubyTextContainer) {
8291 parentType = eTypeRubyTextContainer;
8292 wrapperType = eTypeRubyText;
8293 } else {
8294 MOZ_ASSERT(parentDisplay == StyleDisplay::RubyBaseContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parentDisplay == StyleDisplay::RubyBaseContainer)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parentDisplay == StyleDisplay::RubyBaseContainer))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("parentDisplay == StyleDisplay::RubyBaseContainer"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8294); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentDisplay == StyleDisplay::RubyBaseContainer"
")"); do { MOZ_CrashSequence(__null, 8294); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8295 parentType = eTypeRubyBaseContainer;
8296 wrapperType = eTypeRubyBase;
8297 }
8298
8299 MOZ_ASSERT(aIter.item().DesiredParentType() != parentType,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIter.item().DesiredParentType() != parentType)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIter.item().DesiredParentType() != parentType))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aIter.item().DesiredParentType() != parentType"
" (" "Should point to something needs to be wrapped." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8300); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8300); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8300 "Should point to something needs to be wrapped.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIter.item().DesiredParentType() != parentType)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIter.item().DesiredParentType() != parentType))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aIter.item().DesiredParentType() != parentType"
" (" "Should point to something needs to be wrapped." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8300); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8300); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8301
8302 FCItemIterator endIter(aIter);
8303 endIter.SkipItemsNotWantingParentType(parentType);
8304
8305 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8306 endIter);
8307}
8308
8309/**
8310 * This function eats up consecutive items into a ruby level container.
8311 * It may create zero or one level container. When it returns, |aIter|
8312 * points to the first item it doesn't wrap.
8313 */
8314void nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
8315 nsFrameConstructorState& aState, FCItemIterator& aIter,
8316 ComputedStyle* aParentStyle, nsIContent* aParentContent) {
8317 MOZ_ASSERT(aIter.item().DesiredParentType() != eTypeRuby,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIter.item().DesiredParentType() != eTypeRuby)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIter.item().DesiredParentType() != eTypeRuby))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aIter.item().DesiredParentType() != eTypeRuby"
" (" "Pointing to a level container?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8318); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8318 "Pointing to a level container?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIter.item().DesiredParentType() != eTypeRuby)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIter.item().DesiredParentType() != eTypeRuby))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aIter.item().DesiredParentType() != eTypeRuby"
" (" "Pointing to a level container?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8318); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8319
8320 FrameConstructionItem& firstItem = aIter.item();
8321 ParentType wrapperType = firstItem.DesiredParentType();
8322 if (wrapperType != eTypeRubyTextContainer) {
8323 // If the first item is not ruby text,
8324 // it should be in a base container.
8325 wrapperType = eTypeRubyBaseContainer;
8326 }
8327
8328 FCItemIterator endIter(aIter);
8329 do {
8330 if (endIter.SkipItemsWantingParentType(wrapperType) ||
8331 // If the skipping above stops at some item which wants a
8332 // different ruby parent, then we have finished.
8333 IsRubyParentType(endIter.item().DesiredParentType())) {
8334 // No more items need to be wrapped in this level container.
8335 break;
8336 }
8337
8338 FCItemIterator contentEndIter(endIter);
8339 contentEndIter.SkipItemsNotWantingRubyParent();
8340 // endIter must be on something doesn't want a ruby parent.
8341 MOZ_ASSERT(contentEndIter != endIter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentEndIter != endIter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentEndIter != endIter)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("contentEndIter != endIter"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8341); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentEndIter != endIter" ")"); do { MOZ_CrashSequence
(__null, 8341); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8342
8343 // InterpretRubyWhitespace depends on the fact that any leading or
8344 // trailing whitespace described in the spec have been trimmed at
8345 // this point. With this precondition, it is safe not to check
8346 // whether contentEndIter has been done.
8347 RubyWhitespaceType whitespaceType =
8348 InterpretRubyWhitespace(aState, endIter, contentEndIter);
8349 if (whitespaceType == eRubyInterLevelWhitespace) {
8350 // Remove inter-level whitespace.
8351 bool atStart = (aIter == endIter);
8352 endIter.DeleteItemsTo(this, contentEndIter);
8353 if (atStart) {
8354 aIter = endIter;
8355 }
8356 } else if (whitespaceType == eRubyInterSegmentWhitespace) {
8357 // If this level container starts with inter-segment whitespaces,
8358 // wrap them. Break at contentEndIter. Otherwise, leave it here.
8359 // Break at endIter. They will be wrapped when we are here again.
8360 if (aIter == endIter) {
8361 MOZ_ASSERT(wrapperType == eTypeRubyBaseContainer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wrapperType == eTypeRubyBaseContainer)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(wrapperType == eTypeRubyBaseContainer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("wrapperType == eTypeRubyBaseContainer"
" (" "Inter-segment whitespace should be wrapped in rbc" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8362); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8362); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8362 "Inter-segment whitespace should be wrapped in rbc")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wrapperType == eTypeRubyBaseContainer)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(wrapperType == eTypeRubyBaseContainer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("wrapperType == eTypeRubyBaseContainer"
" (" "Inter-segment whitespace should be wrapped in rbc" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8362); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8362); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8363 endIter = contentEndIter;
8364 }
8365 break;
8366 } else if (wrapperType == eTypeRubyTextContainer &&
8367 whitespaceType != eRubyInterLeafWhitespace) {
8368 // Misparented inline content that's not inter-annotation
8369 // whitespace doesn't belong in a pseudo ruby text container.
8370 // Break at endIter.
8371 break;
8372 } else {
8373 endIter = contentEndIter;
8374 }
8375 } while (!endIter.IsDone());
8376
8377 // It is possible that everything our parent wants us to wrap is
8378 // simply an inter-level whitespace, which has been trimmed, or
8379 // an inter-segment whitespace, which will be wrapped later.
8380 // In those cases, don't create anything.
8381 if (aIter != endIter) {
8382 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8383 endIter);
8384 }
8385}
8386
8387/**
8388 * This function trims leading and trailing whitespaces
8389 * in the given item list.
8390 */
8391void nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
8392 nsFrameConstructorState& aState, FrameConstructionItemList& aItems) {
8393 FCItemIterator iter(aItems);
8394 if (!iter.IsDone() && iter.item().IsWhitespace(aState)) {
8395 FCItemIterator spaceEndIter(iter);
8396 spaceEndIter.SkipWhitespace(aState);
8397 iter.DeleteItemsTo(this, spaceEndIter);
8398 }
8399
8400 iter.SetToEnd();
8401 if (!iter.AtStart()) {
8402 FCItemIterator spaceEndIter(iter);
8403 do {
8404 iter.Prev();
8405 if (iter.AtStart()) {
8406 // It's fine to not check the first item, because we
8407 // should have trimmed leading whitespaces above.
8408 break;
8409 }
8410 } while (iter.item().IsWhitespace(aState));
8411 iter.Next();
8412 if (iter != spaceEndIter) {
8413 iter.DeleteItemsTo(this, spaceEndIter);
8414 }
8415 }
8416}
8417
8418/**
8419 * This function walks through the child list (aItems) and creates
8420 * needed pseudo ruby boxes to wrap misparented children.
8421 */
8422void nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
8423 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8424 nsIFrame* aParentFrame) {
8425 const ParentType ourParentType = GetParentType(aParentFrame);
8426 if (!IsRubyParentType(ourParentType) ||
8427 aItems.AllWantParentType(ourParentType)) {
8428 return;
8429 }
8430
8431 if (!IsRubyPseudo(aParentFrame) ||
8432 ourParentType == eTypeRuby /* for 'display:block ruby' */) {
8433 // Normally, ruby pseudo frames start from and end at some elements,
8434 // which means they don't have leading and trailing whitespaces at
8435 // all. But there are two cases where they do actually have leading
8436 // or trailing whitespaces:
8437 // 1. It is an inter-segment whitespace which in an individual ruby
8438 // base container.
8439 // 2. The pseudo frame starts from or ends at consecutive inline
8440 // content, which is not pure whitespace, but includes some.
8441 // In either case, the whitespaces are not the leading or trailing
8442 // whitespaces defined in the spec, and thus should not be trimmed.
8443 TrimLeadingAndTrailingWhitespaces(aState, aItems);
8444 }
8445
8446 FCItemIterator iter(aItems);
8447 nsIContent* parentContent = aParentFrame->GetContent();
8448 ComputedStyle* parentStyle = aParentFrame->Style();
8449 while (!iter.IsDone()) {
8450 if (!iter.SkipItemsWantingParentType(ourParentType)) {
8451 if (ourParentType == eTypeRuby) {
8452 WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
8453 parentContent);
8454 } else {
8455 WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
8456 }
8457 }
8458 }
8459}
8460
8461/*
8462 * This function works as follows: we walk through the child list (aItems) and
8463 * find items that cannot have aParentFrame as their parent. We wrap
8464 * continuous runs of such items into a FrameConstructionItem for a frame that
8465 * gets them closer to their desired parents. For example, a run of non-row
8466 * children of a row-group will get wrapped in a row. When we later construct
8467 * the frame for this wrapper (in this case for the row), it'll be the correct
8468 * parent for the cells in the set of items we wrapped or we'll wrap cells
8469 * around everything else. At the end of this method, aItems is guaranteed to
8470 * contain only items for frames that can be direct kids of aParentFrame.
8471 */
8472void nsCSSFrameConstructor::CreateNeededPseudoContainers(
8473 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8474 nsIFrame* aParentFrame) {
8475 ParentType ourParentType = GetParentType(aParentFrame);
8476 if (IsRubyParentType(ourParentType) ||
8477 aItems.AllWantParentType(ourParentType)) {
8478 // Nothing to do here
8479 return;
8480 }
8481
8482 FCItemIterator iter(aItems);
8483 do {
8484 if (iter.SkipItemsWantingParentType(ourParentType)) {
8485 // Nothing else to do here; we're finished
8486 return;
8487 }
8488
8489 // Now we're pointing to the first child that wants a different parent
8490 // type.
8491
8492 // Now try to figure out what kids we can group together. We can generally
8493 // group everything that has a different desired parent type from us. Two
8494 // exceptions to this:
8495 // 1) If our parent type is table, we can't group columns with anything
8496 // else other than whitespace.
8497 // 2) Whitespace that lies between two things we can group which both want
8498 // a non-block parent should be dropped, even if we can't group them
8499 // with each other and even if the whitespace wants a parent of
8500 // ourParentType. Ends of the list count as things that don't want a
8501 // block parent (so that for example we'll drop a whitespace-only list).
8502
8503 FCItemIterator endIter(iter); /* iterator to find the end of the group */
8504 ParentType groupingParentType = endIter.item().DesiredParentType();
8505 if (aItems.AllWantParentType(groupingParentType) &&
8506 groupingParentType != eTypeBlock) {
8507 // Just group them all and be done with it. We need the check for
8508 // eTypeBlock here to catch the "all the items are whitespace" case
8509 // described above.
8510 endIter.SetToEnd();
8511 } else {
8512 // Locate the end of the group.
8513
8514 // Keep track of the type the previous item wanted, in case we have to
8515 // deal with whitespace. Start it off with ourParentType, since that's
8516 // the last thing |iter| would have skipped over.
8517 ParentType prevParentType = ourParentType;
8518 do {
8519 // Walk an iterator past any whitespace that we might be able to drop
8520 // from the list
8521 FCItemIterator spaceEndIter(endIter);
8522 if (prevParentType != eTypeBlock &&
8523 !aParentFrame->IsGeneratedContentFrame() &&
8524 spaceEndIter.item().IsWhitespace(aState)) {
8525 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
8526
8527 // We drop the whitespace in the following cases:
8528 // 1) If these are not trailing spaces and the next item wants a table
8529 // or table-part parent
8530 // 2) If these are trailing spaces and aParentFrame is a
8531 // tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
8532 // (Being a tabular container pretty much means ourParentType is
8533 // not eTypeBlock besides the eTypeColGroup case, which won't
8534 // reach here.)
8535 if ((!trailingSpaces &&
8536 IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
8537 (trailingSpaces && ourParentType != eTypeBlock)) {
8538 bool updateStart = (iter == endIter);
8539 endIter.DeleteItemsTo(this, spaceEndIter);
8540 NS_ASSERTION(trailingSpaces == endIter.IsDone(),do { if (!(trailingSpaces == endIter.IsDone())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "These should match", "trailingSpaces == endIter.IsDone()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8541); MOZ_PretendNoReturn
(); } } while (0)
8541 "These should match")do { if (!(trailingSpaces == endIter.IsDone())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "These should match", "trailingSpaces == endIter.IsDone()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8541); MOZ_PretendNoReturn
(); } } while (0)
;
8542
8543 if (updateStart) {
8544 iter = endIter;
8545 }
8546
8547 if (trailingSpaces) {
8548 break; /* Found group end */
8549 }
8550
8551 if (updateStart) {
8552 // Update groupingParentType, since it might have been eTypeBlock
8553 // just because of the whitespace.
8554 groupingParentType = iter.item().DesiredParentType();
8555 }
8556 }
8557 }
8558
8559 // Now endIter points to a non-whitespace item or a non-droppable
8560 // whitespace item. In the latter case, if this is the end of the group
8561 // we'll traverse this whitespace again. But it'll all just be quick
8562 // DesiredParentType() checks which will match ourParentType (that's
8563 // what it means that this is the group end), so it's OK.
8564 // However, when we are grouping a ruby parent, and endIter points to
8565 // a non-droppable whitespace, if the next non-whitespace item also
8566 // wants a ruby parent, the whitespace should also be included into
8567 // the current ruby container.
8568 prevParentType = endIter.item().DesiredParentType();
8569 if (prevParentType == ourParentType &&
8570 (endIter == spaceEndIter || spaceEndIter.IsDone() ||
8571 !IsRubyParentType(groupingParentType) ||
8572 !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
8573 // End the group at endIter.
8574 break;
8575 }
8576
8577 if (ourParentType == eTypeTable &&
8578 (prevParentType == eTypeColGroup) !=
8579 (groupingParentType == eTypeColGroup)) {
8580 // Either we started with columns and now found something else, or
8581 // vice versa. In any case, end the grouping.
8582 break;
8583 }
8584
8585 // If we have some whitespace that we were not able to drop and there is
8586 // an item after the whitespace that is already properly parented, then
8587 // make sure to include the spaces in our group but stop the group after
8588 // that.
8589 if (spaceEndIter != endIter && !spaceEndIter.IsDone() &&
8590 ourParentType == spaceEndIter.item().DesiredParentType()) {
8591 endIter = spaceEndIter;
8592 break;
8593 }
8594
8595 // Include the whitespace we didn't drop (if any) in the group.
8596 endIter = spaceEndIter;
8597 prevParentType = endIter.item().DesiredParentType();
8598
8599 endIter.Next();
8600 } while (!endIter.IsDone());
8601 }
8602
8603 if (iter == endIter) {
8604 // Nothing to wrap here; just skipped some whitespace
8605 continue;
8606 }
8607
8608 if (ourParentType == eTypeColGroup) {
8609 // Suppress non-col items of colgroups.
8610 iter.DeleteItemsTo(this, endIter);
8611 continue;
8612 }
8613
8614 // Now group together all the items between iter and endIter. The right
8615 // parent type to use depends on ourParentType.
8616 ParentType wrapperType;
8617 switch (ourParentType) {
8618 case eTypeRow:
8619 // The parent type for a cell is eTypeBlock, since that's what a cell
8620 // looks like to its kids.
8621 wrapperType = eTypeBlock;
8622 break;
8623 case eTypeRowGroup:
8624 wrapperType = eTypeRow;
8625 break;
8626 case eTypeTable:
8627 // Either colgroup or rowgroup, depending on what we're grouping.
8628 wrapperType =
8629 groupingParentType == eTypeColGroup ? eTypeColGroup : eTypeRowGroup;
8630 break;
8631 case eTypeColGroup:
8632 MOZ_FALLTHROUGH_ASSERT("handled above")do { do { } while (false); MOZ_ReportCrash("" "MOZ_FALLTHROUGH_ASSERT: "
"handled above", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8632); AnnotateMozCrashReason("MOZ_CRASH(" "MOZ_FALLTHROUGH_ASSERT: "
"handled above" ")"); do { MOZ_CrashSequence(__null, 8632); __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
;
8633 default:
8634 NS_ASSERTION(ourParentType == eTypeBlock, "Unrecognized parent type")do { if (!(ourParentType == eTypeBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unrecognized parent type", "ourParentType == eTypeBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8634); MOZ_PretendNoReturn(); } } while (0)
;
8635 if (IsRubyParentType(groupingParentType)) {
8636 wrapperType = eTypeRuby;
8637 } else {
8638 NS_ASSERTION(IsTableParentType(groupingParentType),do { if (!(IsTableParentType(groupingParentType))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "groupingParentType should be either Ruby or table"
, "IsTableParentType(groupingParentType)", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8639); MOZ_PretendNoReturn(); } } while (0)
8639 "groupingParentType should be either Ruby or table")do { if (!(IsTableParentType(groupingParentType))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "groupingParentType should be either Ruby or table"
, "IsTableParentType(groupingParentType)", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8639); MOZ_PretendNoReturn(); } } while (0)
;
8640 wrapperType = eTypeTable;
8641 }
8642 }
8643
8644 ComputedStyle* parentStyle = aParentFrame->Style();
8645 WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
8646 wrapperType, iter, endIter);
8647
8648 // Now |iter| points to the item that was the first one we didn't wrap;
8649 // loop and see whether we need to skip it or wrap it in something
8650 // different.
8651 } while (!iter.IsDone());
8652}
8653
8654/**
8655 * This method wraps frame construction item from |aIter| to
8656 * |aEndIter|. After it returns, aIter points to the first item
8657 * after the wrapper.
8658 */
8659void nsCSSFrameConstructor::WrapItemsInPseudoParent(
8660 nsIContent* aParentContent, ComputedStyle* aParentStyle,
8661 ParentType aWrapperType, FCItemIterator& aIter,
8662 const FCItemIterator& aEndIter) {
8663 const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
8664 PseudoStyleType pseudoType = pseudoData.mPseudoType;
8665 auto& parentDisplay = *aParentStyle->StyleDisplay();
8666 auto parentDisplayInside = parentDisplay.DisplayInside();
8667
8668 // XXXmats should we use IsInlineInsideStyle() here instead? seems odd to
8669 // exclude RubyBaseContainer/RubyTextContainer...
8670 if (pseudoType == PseudoStyleType::MozTable &&
8671 (parentDisplay.IsInlineFlow() ||
8672 parentDisplayInside == StyleDisplayInside::RubyBase ||
8673 parentDisplayInside == StyleDisplayInside::RubyText)) {
8674 pseudoType = PseudoStyleType::MozInlineTable;
8675 }
8676
8677 RefPtr<ComputedStyle> wrapperStyle;
8678 if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000) {
8679 wrapperStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8680 pseudoType, aParentStyle);
8681 } else {
8682 wrapperStyle =
8683 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
8684 pseudoType);
8685 }
8686
8687 // Use the content of our parent frame
8688 auto* newItem = new (this) FrameConstructionItem(
8689 &pseudoData.mFCData, aParentContent, wrapperStyle.forget(), true);
8690
8691 const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
8692 // Here we're cheating a tad... technically, table-internal items should be
8693 // inline if aParentFrame is inline, but they'll get wrapped in an
8694 // inline-table in the end, so it'll all work out. In any case, arguably
8695 // we don't need to maintain this state at this point... but it's better
8696 // to, I guess.
8697 newItem->mIsAllInline = disp->IsInlineOutsideStyle();
8698
8699 bool isRuby = disp->IsRubyDisplayType();
8700 if (!isRuby) {
8701 // Table pseudo frames always induce line boundaries around their
8702 // contents.
8703 newItem->mChildItems.SetLineBoundaryAtStart(true);
8704 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8705 }
8706 // The parent of the items in aItems is also the parent of the items
8707 // in mChildItems
8708 newItem->mChildItems.SetParentHasNoShadowDOM(
8709 aIter.List()->ParentHasNoShadowDOM());
8710
8711 // Eat up all items between |aIter| and |aEndIter| and put them in our
8712 // wrapper Advances |aIter| to point to |aEndIter|.
8713 aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
8714
8715 aIter.InsertItem(newItem);
8716}
8717
8718void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
8719 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8720 nsIFrame* aParentFrame) {
8721 if (aItems.IsEmpty() || GetParentType(aParentFrame) != eTypeRuby) {
8722 return;
8723 }
8724
8725 FCItemIterator iter(aItems);
8726 StyleDisplay firstDisplay =
8727 iter.item().mComputedStyle->StyleDisplay()->mDisplay;
8728 if (firstDisplay == StyleDisplay::RubyBaseContainer) {
8729 return;
8730 }
8731 NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,do { if (!(firstDisplay == StyleDisplay::RubyTextContainer)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Child of ruby frame should either a rbc or a rtc"
, "firstDisplay == StyleDisplay::RubyTextContainer", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8732); MOZ_PretendNoReturn(); } } while (0)
8732 "Child of ruby frame should either a rbc or a rtc")do { if (!(firstDisplay == StyleDisplay::RubyTextContainer)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Child of ruby frame should either a rbc or a rtc"
, "firstDisplay == StyleDisplay::RubyTextContainer", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8732); MOZ_PretendNoReturn(); } } while (0)
;
8733
8734 const PseudoParentData& pseudoData =
8735 sPseudoParentData[eTypeRubyBaseContainer];
8736 RefPtr<ComputedStyle> pseudoStyle =
8737 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8738 pseudoData.mPseudoType, aParentFrame->Style());
8739 FrameConstructionItem* newItem = new (this) FrameConstructionItem(
8740 &pseudoData.mFCData,
8741 // Use the content of the parent frame
8742 aParentFrame->GetContent(), pseudoStyle.forget(), true);
8743 newItem->mIsAllInline = true;
8744 newItem->mChildItems.SetParentHasNoShadowDOM(true);
8745 iter.InsertItem(newItem);
8746}
8747
8748#ifdef DEBUG1
8749/**
8750 * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
8751 * rather than being a direct child of aContainerFrame.
8752 *
8753 * NOTE: aContainerFrame must be a flex or grid container - this function is
8754 * purely for sanity-checking the children of these container types.
8755 * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
8756 * logic (which operates a bit earlier, on FCData instead of frames).
8757 */
8758static bool FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
8759 const nsIFrame* aFrame) {
8760 MOZ_ASSERT(aContainerFrame->IsFlexOrGridContainer())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainerFrame->IsFlexOrGridContainer())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aContainerFrame->IsFlexOrGridContainer()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aContainerFrame->IsFlexOrGridContainer()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8760); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContainerFrame->IsFlexOrGridContainer()"
")"); do { MOZ_CrashSequence(__null, 8760); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8761
8762 // Any line-participant frames (e.g. text) definitely want to be wrapped in
8763 // an anonymous flex/grid item.
8764 if (aFrame->IsLineParticipant()) {
8765 return true;
8766 }
8767
8768 // If the container is a -webkit-{inline-}box container, then placeholders
8769 // also need to be wrapped, for compatibility.
8770 if (IsFlexContainerForLegacyWebKitBox(aContainerFrame) &&
8771 aFrame->IsPlaceholderFrame()) {
8772 return true;
8773 }
8774
8775 return false;
8776}
8777#endif
8778
8779static void VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
8780 const nsFrameList& aChildren) {
8781#ifdef DEBUG1
8782 if (!aParentFrame->IsFlexOrGridContainer()) {
8783 return;
8784 }
8785
8786 bool prevChildWasAnonItem = false;
8787 for (const nsIFrame* child : aChildren) {
8788 MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(aParentFrame, child),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!FrameWantsToBeInAnonymousItem(aParentFrame, child))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!FrameWantsToBeInAnonymousItem(aParentFrame, child))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
" (" "frame wants to be inside an anonymous item, but it isn't"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8789
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8789); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8789 "frame wants to be inside an anonymous item, but it isn't")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!FrameWantsToBeInAnonymousItem(aParentFrame, child))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!FrameWantsToBeInAnonymousItem(aParentFrame, child))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
" (" "frame wants to be inside an anonymous item, but it isn't"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8789
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8789); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8790 if (IsAnonymousItem(child)) {
8791 AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
8792 MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!prevChildWasAnonItem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!prevChildWasAnonItem))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!prevChildWasAnonItem"
" (" "two anon items in a row" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!prevChildWasAnonItem"
") (" "two anon items in a row" ")"); do { MOZ_CrashSequence
(__null, 8792); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8793 nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
8794 MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(firstWrappedChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(firstWrappedChild))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("firstWrappedChild"
" (" "anonymous item shouldn't be empty" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstWrappedChild"
") (" "anonymous item shouldn't be empty" ")"); do { MOZ_CrashSequence
(__null, 8794); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8795 prevChildWasAnonItem = true;
8796 } else {
8797 prevChildWasAnonItem = false;
8798 }
8799 }
8800#endif
8801}
8802
8803static bool FrameHasOnlyPlaceholderPrevSiblings(const nsIFrame* aFrame) {
8804 // Check for prev siblings, ignoring placeholder frames.
8805 MOZ_ASSERT(aFrame, "frame must not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "frame must not be null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8805
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8805); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8806 const nsIFrame* prevSibling = aFrame;
8807 do {
8808 prevSibling = prevSibling->GetPrevSibling();
8809 } while (prevSibling && prevSibling->IsPlaceholderFrame());
8810 return !prevSibling;
8811}
8812
8813static bool FrameHasOnlyPlaceholderNextSiblings(const nsIFrame* aFrame) {
8814 // Check for next siblings, ignoring placeholder frames.
8815 MOZ_ASSERT(aFrame, "frame must not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "frame must not be null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8815
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8815); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8816 const nsIFrame* nextSibling = aFrame;
8817 do {
8818 nextSibling = nextSibling->GetNextSibling();
8819 } while (nextSibling && nextSibling->IsPlaceholderFrame());
8820 return !nextSibling;
8821}
8822
8823static void SetPageValues(nsIFrame* const aFrame,
8824 const nsAtom* const aAutoValue,
8825 const nsAtom* const aStartValue,
8826 const nsAtom* const aEndValue) {
8827 MOZ_ASSERT(aAutoValue, "Auto page value should never be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAutoValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAutoValue))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aAutoValue" " (" "Auto page value should never be null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8827
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAutoValue" ") ("
"Auto page value should never be null" ")"); do { MOZ_CrashSequence
(__null, 8827); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8828 MOZ_ASSERT(aStartValue || aEndValue, "Should not have called with no values")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartValue || aEndValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartValue || aEndValue))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aStartValue || aEndValue"
" (" "Should not have called with no values" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8828); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartValue || aEndValue"
") (" "Should not have called with no values" ")"); do { MOZ_CrashSequence
(__null, 8828); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8829 nsIFrame::PageValues* pageValues =
8830 aFrame->GetProperty(nsIFrame::PageValuesProperty());
8831
8832 if (aStartValue) {
8833 if (aStartValue == aAutoValue) {
8834 // If the page value struct already exists, set the start value to null
8835 // to indicate the auto value.
8836 if (pageValues) {
8837 pageValues->mStartPageValue = nullptr;
8838 }
8839 } else {
8840 // The start value is not auto, so we need to store it, creating the
8841 // page values struct if it does not already exist.
8842 if (!pageValues) {
8843 pageValues = new nsIFrame::PageValues();
8844 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8845 }
8846 pageValues->mStartPageValue = aStartValue;
8847 }
8848 }
8849 if (aEndValue) {
8850 if (aEndValue == aAutoValue) {
8851 // If the page value struct already exists, set the end value to null
8852 // to indicate the auto value.
8853 if (pageValues) {
8854 pageValues->mEndPageValue = nullptr;
8855 }
8856 } else {
8857 // The end value is not auto, so we need to store it, creating the
8858 // page values struct if it does not already exist.
8859 if (!pageValues) {
8860 pageValues = new nsIFrame::PageValues();
8861 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8862 }
8863 pageValues->mEndPageValue = aEndValue;
8864 }
8865 }
8866}
8867
8868inline void nsCSSFrameConstructor::ConstructFramesFromItemList(
8869 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8870 nsContainerFrame* aParentFrame, bool aParentIsWrapperAnonBox,
8871 nsFrameList& aFrameList) {
8872#ifdef DEBUG1
8873 // The assertion condition should match the logic in
8874 // MaybePushFloatContainingBlock().
8875 MOZ_ASSERT(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8876 aParentFrame->IsFloatContainingBlock()) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8877 aState.mFloatCBCandidate == aParentFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8878 "Our caller or ProcessChildren()'s caller should call "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8879 "MaybePushFloatContainingBlock() to handle the float containing "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8880 "block candidate!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(ShouldSuppressFloatingOfDescendants(aParentFrame) ||
aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate
== aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(ShouldSuppressFloatingOfDescendants
(aParentFrame) || aParentFrame->IsFloatContainingBlock()) ||
aState.mFloatCBCandidate == aParentFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
" (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(ShouldSuppressFloatingOfDescendants(aParentFrame) || aParentFrame->IsFloatContainingBlock()) || aState.mFloatCBCandidate == aParentFrame"
") (" "Our caller or ProcessChildren()'s caller should call "
"MaybePushFloatContainingBlock() to handle the float containing "
"block candidate!" ")"); do { MOZ_CrashSequence(__null, 8880
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8881 aState.mFloatCBCandidate = nullptr;
8882#endif
8883
8884 // Ensure aParentIsWrapperAnonBox is correct. We _could_ compute it directly,
8885 // but it would be a bit slow, which is why we pass it from callers, who have
8886 // that information offhand in many cases.
8887 MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8887); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox"
")"); do { MOZ_CrashSequence(__null, 8887); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8888
8889 // Note: we explicitly exclude TableColGroupFrame because it doesn't
8890 // have the FCDATA_IS_WRAPPER_ANON_BOX on pseudos so aParentIsWrapperAnonBox
8891 // is false for such pseudos (see sPseudoParentData below).
8892 if (!aParentIsWrapperAnonBox && aState.mHasRenderedLegend &&
8893 aParentFrame->GetContent()->IsHTMLElement(nsGkAtoms::fieldset) &&
8894 !aParentFrame->IsTableColGroupFrame()) {
8895 DebugOnly<bool> found = false;
8896 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8897 if (iter.item().mIsRenderedLegend) {
8898 // This makes the rendered legend the first frame in the fieldset child
8899 // list which makes keyboard traversal follow the visual order.
8900 nsFieldSetFrame* fieldSetFrame = GetFieldSetFrameFor(aParentFrame);
8901 nsFrameList renderedLegend;
8902 ConstructFramesFromItem(aState, iter, fieldSetFrame, renderedLegend);
8903 MOZ_ASSERT(renderedLegend.OnlyChild(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(renderedLegend.OnlyChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(renderedLegend.OnlyChild()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("renderedLegend.OnlyChild()"
" (" "a rendered legend should have exactly one frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8904); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8904 "a rendered legend should have exactly one frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(renderedLegend.OnlyChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(renderedLegend.OnlyChild()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("renderedLegend.OnlyChild()"
" (" "a rendered legend should have exactly one frame" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8904); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8905 fieldSetFrame->InsertFrames(FrameChildListID::Principal, nullptr,
8906 nullptr, std::move(renderedLegend));
8907 FCItemIterator next = iter;
8908 next.Next();
8909 iter.DeleteItemsTo(this, next);
8910 found = true;
8911 break;
8912 }
8913 }
8914 MOZ_ASSERT(found, "should have found our rendered legend")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(found)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(found))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("found" " (" "should have found our rendered legend"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 8914
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found" ") (" "should have found our rendered legend"
")"); do { MOZ_CrashSequence(__null, 8914); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8915 }
8916
8917 CreateNeededPseudoContainers(aState, aItems, aParentFrame);
8918 CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
8919 CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
8920 CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
8921
8922 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8923 MOZ_ASSERT(!iter.item().mIsRenderedLegend,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.item().mIsRenderedLegend)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.item().mIsRenderedLegend
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!iter.item().mIsRenderedLegend" " (" "Only one item can be the rendered legend, "
"and it should've been handled above" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.item().mIsRenderedLegend"
") (" "Only one item can be the rendered legend, " "and it should've been handled above"
")"); do { MOZ_CrashSequence(__null, 8925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8924 "Only one item can be the rendered legend, "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.item().mIsRenderedLegend)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.item().mIsRenderedLegend
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!iter.item().mIsRenderedLegend" " (" "Only one item can be the rendered legend, "
"and it should've been handled above" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.item().mIsRenderedLegend"
") (" "Only one item can be the rendered legend, " "and it should've been handled above"
")"); do { MOZ_CrashSequence(__null, 8925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8925 "and it should've been handled above")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter.item().mIsRenderedLegend)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter.item().mIsRenderedLegend
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!iter.item().mIsRenderedLegend" " (" "Only one item can be the rendered legend, "
"and it should've been handled above" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.item().mIsRenderedLegend"
") (" "Only one item can be the rendered legend, " "and it should've been handled above"
")"); do { MOZ_CrashSequence(__null, 8925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8926 NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),do { if (!(iter.item().DesiredParentType() == GetParentType(aParentFrame
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Needed pseudos didn't get created; expect bad things"
, "iter.item().DesiredParentType() == GetParentType(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8927); MOZ_PretendNoReturn
(); } } while (0)
8927 "Needed pseudos didn't get created; expect bad things")do { if (!(iter.item().DesiredParentType() == GetParentType(aParentFrame
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Needed pseudos didn't get created; expect bad things"
, "iter.item().DesiredParentType() == GetParentType(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8927); MOZ_PretendNoReturn
(); } } while (0)
;
8928 ConstructFramesFromItem(aState, iter, aParentFrame, aFrameList);
8929 }
8930
8931 VerifyGridFlexContainerChildren(aParentFrame, aFrameList);
8932
8933 // Calculate and propagate page-name values for each frame in the frame list.
8934 // We do not want to compute and propagate page-name values from frames that
8935 // are children of any subclasses of block frames, but not actually a block
8936 // frame. The page-name property does not apply to frames which cannot create
8937 // class A breakpoints (currently no subclass of BlockFrame can). Because the
8938 // property does not apply, those children also cannot propagate page-name
8939 // values.
8940 // This assumption helps avoid unnecessarily handling page-names for frames
8941 // such as form controls, which also avoids bug 1819468.
8942 if (aState.mPresContext->IsPaginated() && aParentFrame->IsBlockFrame()) {
8943 // Set the start/end page values while iterating the frame list, to walk
8944 // up the frame tree only once after iterating the frame list.
8945 // This also avoids extra property lookups on these frames.
8946 MOZ_ASSERT(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
" (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
") (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")"); do { MOZ_CrashSequence
(__null, 8948); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8947 "aState.mAutoPageNameValue should have been equivalent to "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
" (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
") (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")"); do { MOZ_CrashSequence
(__null, 8948); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8948 "the auto value stored on our parent frame.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
" (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mAutoPageNameValue == aParentFrame->GetAutoPageValue()"
") (" "aState.mAutoPageNameValue should have been equivalent to "
"the auto value stored on our parent frame." ")"); do { MOZ_CrashSequence
(__null, 8948); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8949 // Even though we store null for page values that equal the "auto" resolved
8950 // value on frames, we always want startPageValue/endPageValue to be the
8951 // actual atoms reflecting the start/end values. This is because when we
8952 // propagate the values up the frame tree, we will need to compare them to
8953 // the auto value for each ancestor. This value might be different than the
8954 // auto value for this frame.
8955 const nsAtom* startPageValue = nullptr;
8956 const nsAtom* endPageValue = nullptr;
8957 for (nsIFrame* f : aFrameList) {
8958 if (f->IsPlaceholderFrame()) {
8959 continue;
8960 }
8961 // Resolve auto against the parent frame's used page name, which has been
8962 // determined and set on aState.mAutoPageNameValue. If this item is not
8963 // block-level then we use the value that auto resolves to.
8964 //
8965 // This is to achieve the propagation behavior described in the spec:
8966 //
8967 // "A start page value and end page value is determined for each box as
8968 // the value (if any) propagated from its first or last child box
8969 // (respectively), else the used value on the box itself."
8970 //
8971 // "A child propagates its own start or end page value if and only if the
8972 // page property applies to it."
8973 //
8974 // The page property only applies to "boxes that create class A break
8975 // points". When taken together, this means that non block-level children
8976 // do not propagate start/end page values, and instead we use "the used
8977 // value on the box itself", the "box itself" being aParentFrame. This
8978 // value has been determined and saved as aState.mAutoPageNameValue
8979 //
8980 // https://www.w3.org/TR/css-page-3/#using-named-pages
8981 // https://www.w3.org/TR/css-break-3/#btw-blocks
8982 const StylePageName& pageName = f->StylePage()->mPage;
8983 const nsAtom* const pageNameAtom =
8984 (pageName.IsPageName() && f->IsBlockOutside())
8985 ? pageName.AsPageName().AsAtom()
8986 : aState.mAutoPageNameValue;
8987 nsIFrame::PageValues* pageValues =
8988 f->GetProperty(nsIFrame::PageValuesProperty());
8989 // If this frame has any children, it will already have had its page
8990 // values set at this point. However, if no page values have been set,
8991 // we must ensure that the appropriate PageValuesProperty value has been
8992 // set.
8993 // If the page name is equal to the auto value, then PageValuesProperty
8994 // should remain null to indicate that the start/end values are both
8995 // equal to the auto value.
8996 if (pageNameAtom != aState.mAutoPageNameValue && !pageValues) {
8997 pageValues = new nsIFrame::PageValues{pageNameAtom, pageNameAtom};
8998 f->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8999 }
9000 // We don't want to use GetStartPageValue() or GetEndPageValue(), as each
9001 // requires a property lookup which we can avoid here.
9002 if (!startPageValue) {
9003 startPageValue = (pageValues && pageValues->mStartPageValue)
9004 ? pageValues->mStartPageValue.get()
9005 : aState.mAutoPageNameValue;
9006 }
9007 endPageValue = (pageValues && pageValues->mEndPageValue)
9008 ? pageValues->mEndPageValue.get()
9009 : aState.mAutoPageNameValue;
9010 MOZ_ASSERT(startPageValue && endPageValue,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(startPageValue && endPageValue)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(startPageValue && endPageValue))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("startPageValue && endPageValue"
" (" "Should have found start/end page value" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 9011); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9011 "Should have found start/end page value")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(startPageValue && endPageValue)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(startPageValue && endPageValue))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("startPageValue && endPageValue"
" (" "Should have found start/end page value" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 9011); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9012 }
9013 MOZ_ASSERT(!startPageValue == !endPageValue,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!startPageValue == !endPageValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!startPageValue == !endPageValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!startPageValue == !endPageValue" " (" "Should have set both or neither page values"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9014
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 9014); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9014 "Should have set both or neither page values")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!startPageValue == !endPageValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!startPageValue == !endPageValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!startPageValue == !endPageValue" " (" "Should have set both or neither page values"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9014
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 9014); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9015 if (startPageValue) {
9016 // Walk up the frame tree from our parent frame, propagating start and
9017 // end page values.
9018 // As we go, if we find that, for a frame, we are not contributing one of
9019 // the start/end page values, then our subtree will not contribute this
9020 // value from that frame onward. startPageValue/endPageValue are set to
9021 // null to indicate this.
9022 // Stop iterating when we are not contributing either start or end
9023 // values, when we hit the root frame (no parent), or when we find a
9024 // frame that is not a block frame.
9025 for (nsContainerFrame* ancestorFrame = aParentFrame;
9026 (startPageValue || endPageValue) && ancestorFrame &&
9027 ancestorFrame->IsBlockFrame();
9028 ancestorFrame = ancestorFrame->GetParent()) {
9029 MOZ_ASSERT(!ancestorFrame->GetPrevInFlow(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ancestorFrame->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!ancestorFrame->GetPrevInFlow
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ancestorFrame->GetPrevInFlow()" " (" "Should not have fragmentation yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9030
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9030); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9030 "Should not have fragmentation yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ancestorFrame->GetPrevInFlow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!ancestorFrame->GetPrevInFlow
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ancestorFrame->GetPrevInFlow()" " (" "Should not have fragmentation yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9030
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9030); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9031 MOZ_ASSERT(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
" (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9032 "Frame should have been visited by "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
" (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9033 "AutoFrameConstructionPageName")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ancestorFrame->mWasVisitedByAutoFrameConstructionPageName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
" (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9033
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9033); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9034 {
9035 // Get what the auto value is, based on this frame's parent.
9036 // For the root frame, `auto` resolves to the empty atom.
9037 const nsContainerFrame* const parent = ancestorFrame->GetParent();
9038 const nsAtom* const parentAuto = MOZ_LIKELY(parent)(__builtin_expect(!!(parent), 1))
9039 ? parent->GetAutoPageValue()
9040 : nsGkAtoms::_empty;
9041 SetPageValues(ancestorFrame, parentAuto, startPageValue,
9042 endPageValue);
9043 }
9044 // Once we stop contributing start/end values, we know there is a
9045 // sibling subtree that contributed that value to our shared parent
9046 // instead of our starting frame's subtree. This means once
9047 // startPageValue/endPageValue becomes null, indicating that we are no
9048 // longer contributing that page value, it should stay null and we no
9049 // longer need to check for siblings in that direction.
9050 if (startPageValue &&
9051 !FrameHasOnlyPlaceholderPrevSiblings(ancestorFrame)) {
9052 startPageValue = nullptr;
9053 }
9054 if (endPageValue &&
9055 !FrameHasOnlyPlaceholderNextSiblings(ancestorFrame)) {
9056 endPageValue = nullptr;
9057 }
9058 }
9059 }
9060 }
9061
9062 if (aParentIsWrapperAnonBox) {
9063 for (nsIFrame* f : aFrameList) {
9064 f->SetParentIsWrapperAnonBox();
9065 }
9066 }
9067}
9068
9069void nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
9070 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
9071 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
9072 FrameConstructionItemList& aItemsToConstruct,
9073 const AutoFrameConstructionPageName&) {
9074 for (const auto& info : aAnonymousItems) {
9075 nsIContent* content = info.mContent;
9076 // Gecko-styled nodes should have no pending restyle flags.
9077 // Assert some things about this content
9078 MOZ_ASSERT(!(content->GetFlags() &do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(content->GetFlags() &
(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
" (" "Should not be marked as needing frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9080); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9079 (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(content->GetFlags() &
(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
" (" "Should not be marked as needing frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9080); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9080 "Should not be marked as needing frames")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(content->GetFlags() &
(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
" (" "Should not be marked as needing frames" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9080); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9081 MOZ_ASSERT(!content->GetPrimaryFrame(), "Should have no existing frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!content->GetPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!content->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!content->GetPrimaryFrame()" " (" "Should have no existing frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9081
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!content->GetPrimaryFrame()"
") (" "Should have no existing frame" ")"); do { MOZ_CrashSequence
(__null, 9081); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9082 MOZ_ASSERT(!content->IsComment() && !content->IsProcessingInstruction(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!content->IsComment() && !content->IsProcessingInstruction
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!content->IsComment() && !content->IsProcessingInstruction
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!content->IsComment() && !content->IsProcessingInstruction()"
" (" "Why is someone creating garbage anonymous content" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9083); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9083); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9083 "Why is someone creating garbage anonymous content")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!content->IsComment() && !content->IsProcessingInstruction
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!content->IsComment() && !content->IsProcessingInstruction
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!content->IsComment() && !content->IsProcessingInstruction()"
" (" "Why is someone creating garbage anonymous content" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9083); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9083); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9084
9085 // Make sure we eagerly performed the servo cascade when the anonymous
9086 // nodes were created.
9087 MOZ_ASSERT(!content->IsElement() || content->AsElement()->HasServoData())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!content->IsElement() || content->AsElement()->
HasServoData())>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(!content->IsElement() || content
->AsElement()->HasServoData()))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!content->IsElement() || content->AsElement()->HasServoData()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9087); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsElement() || content->AsElement()->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 9087); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9088
9089 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
9090
9091 AddFrameConstructionItemsInternal(aState, content, aFrame, true,
9092 computedStyle, {ItemFlag::AllowPageBreak},
9093 aItemsToConstruct);
9094 }
9095}
9096
9097void nsCSSFrameConstructor::ProcessChildren(
9098 nsFrameConstructorState& aState, nsIContent* aContent,
9099 ComputedStyle* aComputedStyle, nsContainerFrame* aFrame,
9100 const bool aCanHaveGeneratedContent, nsFrameList& aFrameList,
9101 const bool aAllowBlockStyles, nsIFrame* aPossiblyLeafFrame) {
9102 MOZ_ASSERT(aFrame, "Must have parent frame here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "Must have parent frame here"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9102
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have parent frame here"
")"); do { MOZ_CrashSequence(__null, 9102); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9103 MOZ_ASSERT(aFrame->GetContentInsertionFrame() == aFrame,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetContentInsertionFrame() == aFrame)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aFrame->GetContentInsertionFrame() == aFrame))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetContentInsertionFrame() == aFrame"
" (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9105
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9104 "Parent frame in ProcessChildren should be its own "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetContentInsertionFrame() == aFrame)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aFrame->GetContentInsertionFrame() == aFrame))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetContentInsertionFrame() == aFrame"
" (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9105
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9105 "content insertion frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetContentInsertionFrame() == aFrame)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aFrame->GetContentInsertionFrame() == aFrame))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetContentInsertionFrame() == aFrame"
" (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9105
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9106
9107 const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH1026;
9108 static_assert(kMaxDepth <= UINT16_MAX(65535), "mCurrentDepth type is too narrow");
9109 AutoRestore<uint16_t> savedDepth(mCurrentDepth);
9110 if (mCurrentDepth != UINT16_MAX(65535)) {
9111 ++mCurrentDepth;
9112 }
9113
9114 if (!aPossiblyLeafFrame) {
9115 aPossiblyLeafFrame = aFrame;
9116 }
9117
9118 // XXXbz ideally, this would do all the pushing of various
9119 // containing blocks as needed, so callers don't have to do it...
9120
9121 // Check that our parent frame is a block before allowing ::first-letter/line.
9122 // E.g. <button style="display:grid"> should not allow it.
9123 const bool allowFirstPseudos =
9124 aAllowBlockStyles && aFrame->IsBlockFrameOrSubclass();
9125 bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
9126 if (allowFirstPseudos) {
9127 ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
9128 &haveFirstLineStyle);
9129 }
9130
9131 AutoFrameConstructionItemList itemsToConstruct(this);
9132 AutoFrameConstructionPageName pageNameTracker(aState, aFrame);
9133
9134 // If we have first-letter or first-line style then frames can get
9135 // moved around so don't set these flags.
9136 if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
9137 itemsToConstruct.SetLineBoundaryAtStart(true);
9138 itemsToConstruct.SetLineBoundaryAtEnd(true);
9139 }
9140
9141 // Create any anonymous frames we need here.
9142 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
9143 GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
9144#ifdef DEBUG1
9145 for (auto& item : anonymousItems) {
9146 MOZ_ASSERT(item.mContent->IsRootOfNativeAnonymousSubtree(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item.mContent->IsRootOfNativeAnonymousSubtree())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(item.mContent->IsRootOfNativeAnonymousSubtree()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("item.mContent->IsRootOfNativeAnonymousSubtree()"
" (" "Content should know it's an anonymous subtree" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9147); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9147 "Content should know it's an anonymous subtree")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item.mContent->IsRootOfNativeAnonymousSubtree())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(item.mContent->IsRootOfNativeAnonymousSubtree()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("item.mContent->IsRootOfNativeAnonymousSubtree()"
" (" "Content should know it's an anonymous subtree" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9147); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9148 }
9149#endif
9150 AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
9151 itemsToConstruct, pageNameTracker);
9152
9153 // Generated content should have the same style parent as normal kids.
9154 //
9155 // Note that we don't use this style for looking up things like special
9156 // block styles because in some cases involving table pseudo-frames it has
9157 // nothing to do with the parent frame's desired behavior.
9158 auto* styleParentFrame =
9159 nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo);
9160 ComputedStyle* parentStyle = styleParentFrame->Style();
9161 if (parentStyle->StyleDisplay()->mTopLayer == StyleTopLayer::Auto &&
9162 !aContent->IsInNativeAnonymousSubtree()) {
9163 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9164 *parentStyle, PseudoStyleType::Backdrop,
9165 itemsToConstruct);
9166 }
9167
9168 nsBlockFrame* listItem = nullptr;
9169 bool isOutsideMarker = false;
9170 if (!aPossiblyLeafFrame->IsLeaf()) {
9171 if (aCanHaveGeneratedContent) {
9172 if (parentStyle->StyleDisplay()->IsListItem() &&
9173 (listItem = do_QueryFrame(aFrame)) &&
9174 !styleParentFrame->IsFieldSetFrame()) {
9175 isOutsideMarker = parentStyle->StyleList()->mListStylePosition ==
9176 StyleListStylePosition::Outside;
9177 ItemFlags extraFlags;
9178 if (isOutsideMarker) {
9179 extraFlags += ItemFlag::IsForOutsideMarker;
9180 }
9181 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9182 *parentStyle, PseudoStyleType::Marker,
9183 itemsToConstruct, extraFlags);
9184 }
9185 if (aContent->IsHTMLElement(nsGkAtoms::option)) {
9186 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9187 *parentStyle, PseudoStyleType::Checkmark,
9188 itemsToConstruct);
9189 }
9190 // Probe for generated content before
9191 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9192 *parentStyle, PseudoStyleType::Before,
9193 itemsToConstruct);
9194 }
9195
9196 const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth)(__builtin_expect(!!(mCurrentDepth < kMaxDepth), 1));
9197 if (!addChildItems) {
9198 NS_WARNING("ProcessChildren max depth exceeded")NS_DebugBreak(NS_DEBUG_WARNING, "ProcessChildren max depth exceeded"
, nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9198)
;
9199 }
9200
9201 FlattenedChildIterator iter(aContent);
9202 const InsertionPoint insertion(aFrame, aContent);
9203 for (nsIContent* child = iter.GetNextChild(); child;
9204 child = iter.GetNextChild()) {
9205 MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(child).mContainer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertion.mContainer == GetInsertionPoint(child).mContainer
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(insertion.mContainer == GetInsertionPoint(child).mContainer
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"insertion.mContainer == GetInsertionPoint(child).mContainer"
" (" "GetInsertionPoint should agree with us" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9206); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9206); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9206 "GetInsertionPoint should agree with us")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertion.mContainer == GetInsertionPoint(child).mContainer
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(insertion.mContainer == GetInsertionPoint(child).mContainer
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"insertion.mContainer == GetInsertionPoint(child).mContainer"
" (" "GetInsertionPoint should agree with us" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9206); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9206); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9207 if (addChildItems) {
9208 AddFrameConstructionItems(aState, child, iter.ShadowDOMInvolved(),
9209 *parentStyle, insertion, itemsToConstruct);
9210 } else {
9211 ClearLazyBits(child, child->GetNextSibling());
9212 }
9213 }
9214 itemsToConstruct.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
9215
9216 if (aCanHaveGeneratedContent) {
9217 // Probe for generated content after
9218 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9219 *parentStyle, PseudoStyleType::After,
9220 itemsToConstruct);
9221 if (aContent->IsHTMLElement(nsGkAtoms::select)) {
9222 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9223 *parentStyle, PseudoStyleType::PickerIcon,
9224 itemsToConstruct);
9225 }
9226 }
9227 } else {
9228 ClearLazyBits(aContent->GetFirstChild(), nullptr);
9229 }
9230
9231 ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
9232 /* aParentIsWrapperAnonBox = */ false,
9233 aFrameList);
9234
9235 if (listItem) {
9236 if (auto* markerFrame = nsLayoutUtils::GetMarkerFrame(aContent)) {
9237 for (auto* childFrame : aFrameList) {
9238 if (markerFrame == childFrame) {
9239 if (isOutsideMarker) {
9240 // SetMarkerFrameForListItem will add childFrame to the marker list.
9241 aFrameList.RemoveFrame(childFrame);
9242 auto* grandParent = listItem->GetParent()->GetParent();
9243 if (listItem->Style()->GetPseudoType() ==
9244 PseudoStyleType::MozColumnContent &&
9245 grandParent && grandParent->IsColumnSetWrapperFrame()) {
9246 listItem = do_QueryFrame(grandParent);
9247 MOZ_ASSERT(listItem,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listItem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(listItem))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("listItem" " (" "ColumnSetWrapperFrame is expected to be "
"a nsBlockFrame subclass" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9248 "ColumnSetWrapperFrame is expected to be "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listItem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(listItem))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("listItem" " (" "ColumnSetWrapperFrame is expected to be "
"a nsBlockFrame subclass" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9249 "a nsBlockFrame subclass")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listItem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(listItem))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("listItem" " (" "ColumnSetWrapperFrame is expected to be "
"a nsBlockFrame subclass" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9250 childFrame->SetParent(listItem);
9251 }
9252 }
9253 listItem->SetMarkerFrameForListItem(childFrame);
9254 MOZ_ASSERT(listItem->HasOutsideMarker() == isOutsideMarker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(listItem->HasOutsideMarker() == isOutsideMarker)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(listItem->HasOutsideMarker() == isOutsideMarker))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("listItem->HasOutsideMarker() == isOutsideMarker"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9254); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "listItem->HasOutsideMarker() == isOutsideMarker"
")"); do { MOZ_CrashSequence(__null, 9254); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9255#ifdef ACCESSIBILITY1
9256 if (nsAccessibilityService* accService = GetAccService()) {
9257 auto* marker = markerFrame->GetContent();
9258 accService->ContentRangeInserted(mPresShell, marker, nullptr);
9259 }
9260#endif
9261 break;
9262 }
9263 }
9264 }
9265 }
9266
9267 if (haveFirstLetterStyle) {
9268 WrapFramesInFirstLetterFrame(aFrame, aFrameList);
9269 }
9270 if (haveFirstLineStyle) {
9271 WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, aFrameList);
9272 }
9273}
9274
9275//----------------------------------------------------------------------
9276
9277// Support for :first-line style
9278
9279// Special routine to handle placing a list of frames into a block
9280// frame that has first-line style. The routine ensures that the first
9281// collection of inline frames end up in a first-line frame.
9282// NOTE: aState may have containing block information related to a
9283// different part of the frame tree than where the first line occurs.
9284// In particular aState may be set up for where ContentInserted or
9285// ContentAppended is inserting content, which may be some
9286// non-first-in-flow continuation of the block to which the first-line
9287// belongs. So this function needs to be careful about how it uses
9288// aState.
9289void nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9290 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9291 nsContainerFrame* aBlockFrame, nsFirstLineFrame* aLineFrame,
9292 nsFrameList& aFrameList) {
9293 // Extract any initial inline frames from aFrameList so we can put them
9294 // in the first-line.
9295 nsFrameList firstLineChildren =
9296 aFrameList.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
9297
9298 if (firstLineChildren.IsEmpty()) {
9299 // Nothing is supposed to go into the first-line; nothing to do
9300 return;
9301 }
9302
9303 if (!aLineFrame) {
9304 // Create line frame
9305 ComputedStyle* parentStyle = nsIFrame::CorrectStyleParentFrame(
9306 aBlockFrame, PseudoStyleType::FirstLine)
9307 ->Style();
9308 RefPtr<ComputedStyle> firstLineStyle =
9309 GetFirstLineStyle(aBlockContent, parentStyle);
9310
9311 aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
9312
9313 // Initialize the line frame
9314 InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
9315
9316 // The lineFrame will be the block's first child; the rest of the
9317 // frame list (after lastInlineFrame) will be the second and
9318 // subsequent children; insert lineFrame into aFrameList.
9319 aFrameList.InsertFrame(nullptr, nullptr, aLineFrame);
9320
9321 NS_ASSERTION(aLineFrame->Style() == firstLineStyle,do { if (!(aLineFrame->Style() == firstLineStyle)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Bogus style on line frame", "aLineFrame->Style() == firstLineStyle"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9322); MOZ_PretendNoReturn
(); } } while (0)
9322 "Bogus style on line frame")do { if (!(aLineFrame->Style() == firstLineStyle)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Bogus style on line frame", "aLineFrame->Style() == firstLineStyle"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9322); MOZ_PretendNoReturn
(); } } while (0)
;
9323 }
9324
9325 // Give the inline frames to the lineFrame <b>after</b> reparenting them
9326 ReparentFrames(this, aLineFrame, firstLineChildren, true);
9327 if (aLineFrame->PrincipalChildList().IsEmpty() &&
9328 aLineFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
9329 aLineFrame->SetInitialChildList(FrameChildListID::Principal,
9330 std::move(firstLineChildren));
9331 } else {
9332 AppendFrames(aLineFrame, FrameChildListID::Principal,
9333 std::move(firstLineChildren));
9334 }
9335}
9336
9337// Special routine to handle appending a new frame to a block frame's
9338// child list. Takes care of placing the new frame into the right
9339// place when first-line style is present.
9340void nsCSSFrameConstructor::AppendFirstLineFrames(
9341 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9342 nsContainerFrame* aBlockFrame, nsFrameList& aFrameList) {
9343 // It's possible that aBlockFrame needs to have a first-line frame
9344 // created because it doesn't currently have any children.
9345 const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
9346 if (blockKids.IsEmpty()) {
9347 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, nullptr,
9348 aFrameList);
9349 return;
9350 }
9351
9352 // Examine the last block child - if it's a first-line frame then
9353 // appended frames need special treatment.
9354 nsIFrame* lastBlockKid = blockKids.LastChild();
9355 if (!lastBlockKid->IsLineFrame()) {
9356 // No first-line frame at the end of the list, therefore there is
9357 // an intervening block between any first-line frame the frames
9358 // we are appending. Therefore, we don't need any special
9359 // treatment of the appended frames.
9360 return;
9361 }
9362
9363 nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
9364 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, lineFrame,
9365 aFrameList);
9366}
9367
9368void nsCSSFrameConstructor::CheckForFirstLineInsertion(
9369 nsIFrame* aParentFrame, nsFrameList& aFrameList) {
9370 MOZ_ASSERT(aParentFrame->Style()->IsInFirstLineSubtree(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParentFrame->Style()->IsInFirstLineSubtree())
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aParentFrame->Style()->IsInFirstLineSubtree())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aParentFrame->Style()->IsInFirstLineSubtree()"
" (" "Why were we called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9371); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
9371 "Why were we called?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParentFrame->Style()->IsInFirstLineSubtree())
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aParentFrame->Style()->IsInFirstLineSubtree())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aParentFrame->Style()->IsInFirstLineSubtree()"
" (" "Why were we called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9371); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
9372
9373 if (aFrameList.IsEmpty()) {
9374 // Happens often enough, with the caption stuff. No need to do the ancestor
9375 // walk here.
9376 return;
9377 }
9378
9379 class RestyleManager* restyleManager = RestyleManager();
9380
9381 // Check whether there's a ::first-line on the path up from aParentFrame.
9382 // Note that we can't stop until we've run out of ancestors with
9383 // pseudo-element data, because the first-letter might be somewhere way up the
9384 // tree; in particular it might be past our containing block.
9385 nsIFrame* ancestor = aParentFrame;
9386 while (ancestor) {
9387 if (!ancestor->Style()->IsInFirstLineSubtree()) {
9388 // We know we won't find a ::first-line now.
9389 return;
9390 }
9391
9392 if (!ancestor->IsLineFrame()) {
9393 ancestor = ancestor->GetParent();
9394 continue;
9395 }
9396
9397 if (!ancestor->Style()->IsPseudoElement()) {
9398 // This is a continuation lineframe, not the first line; no need to do
9399 // anything to the styles.
9400 return;
9401 }
9402
9403 // Fix up the styles of aFrameList for ::first-line.
9404 for (nsIFrame* f : aFrameList) {
9405 restyleManager->ReparentComputedStyleForFirstLine(f);
9406 }
9407 return;
9408 }
9409}
9410
9411//----------------------------------------------------------------------
9412
9413// First-letter support
9414
9415// Determine how many characters in the text fragment apply to the
9416// first letter
9417static int32_t FirstLetterCount(
9418 const CharacterDataBuffer* aCharacterDataBuffer) {
9419 int32_t count = 0;
9420 int32_t firstLetterLength = 0;
9421
9422 const uint32_t n = aCharacterDataBuffer->GetLength();
9423 for (uint32_t i = 0; i < n; i++) {
9424 const char16_t ch = aCharacterDataBuffer->CharAt(i);
9425 // FIXME: take content language into account when deciding whitespace.
9426 if (dom::IsSpaceCharacter(ch)) {
9427 if (firstLetterLength) {
9428 break;
9429 }
9430 count++;
9431 continue;
9432 }
9433 // XXX I18n
9434 if ((ch == '\'') || (ch == '\"')) {
9435 if (firstLetterLength) {
9436 break;
9437 }
9438 // keep looping
9439 firstLetterLength = 1;
9440 } else {
9441 count++;
9442 break;
9443 }
9444 }
9445
9446 return count;
9447}
9448
9449static bool NeedFirstLetterContinuation(Text* aText) {
9450 MOZ_ASSERT(aText, "null ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aText)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aText))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aText" " (" "null ptr" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9450); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aText" ") (" "null ptr" ")"); do { MOZ_CrashSequence
(__null, 9450); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9451 int32_t flc = FirstLetterCount(&aText->DataBuffer());
9452 int32_t tl = aText->TextDataLength();
9453 return flc < tl;
9454}
9455
9456static bool IsFirstLetterContent(Text* aText) {
9457 return aText->TextDataLength() && !aText->TextIsOnlyWhitespace();
9458}
9459
9460/**
9461 * Create a letter frame, only make it a floating frame.
9462 */
9463nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
9464 nsFrameConstructorState& aState, Text* aTextContent, nsIFrame* aTextFrame,
9465 nsContainerFrame* aParentFrame, ComputedStyle* aParentStyle,
9466 ComputedStyle* aComputedStyle, nsFrameList& aResult) {
9467 MOZ_ASSERT(aParentStyle)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParentStyle)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParentStyle))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aParentStyle", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentStyle"
")"); do { MOZ_CrashSequence(__null, 9467); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9468
9469 nsFirstLetterFrame* letterFrame =
9470 NS_NewFloatingFirstLetterFrame(mPresShell, aComputedStyle);
9471 // We don't want to use a text content for a non-text frame (because we want
9472 // its primary frame to be a text frame).
9473 nsIContent* letterContent = aParentFrame->GetContent();
9474 nsContainerFrame* containingBlock =
9475 aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
9476 InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
9477
9478 // Init the text frame to refer to the letter frame.
9479 //
9480 // Make sure we get a proper style for it (the one passed in is for the letter
9481 // frame and will have the float property set on it; the text frame shouldn't
9482 // have that set).
9483 ServoStyleSet* styleSet = mPresShell->StyleSet();
9484 RefPtr<ComputedStyle> textSC =
9485 styleSet->ResolveStyleForText(aTextContent, aComputedStyle);
9486 aTextFrame->SetComputedStyleWithoutNotification(textSC);
9487 InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
9488
9489 // And then give the text frame to the letter frame
9490 SetInitialSingleChild(letterFrame, aTextFrame);
9491
9492 // See if we will need to continue the text frame (does it contain
9493 // more than just the first-letter text or not?) If it does, then we
9494 // create (in advance) a continuation frame for it.
9495 nsIFrame* nextTextFrame = nullptr;
9496 if (NeedFirstLetterContinuation(aTextContent)) {
9497 // Create continuation
9498 nextTextFrame = CreateContinuingFrame(aTextFrame, aParentFrame);
9499 RefPtr<ComputedStyle> newSC =
9500 styleSet->ResolveStyleForText(aTextContent, aParentStyle);
9501 nextTextFrame->SetComputedStyle(newSC);
9502 }
9503
9504 NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameList!")do { if (!(aResult.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "aResult should be an empty nsFrameList!", "aResult.IsEmpty()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9504); MOZ_PretendNoReturn
(); } } while (0)
;
9505 // Put the new float before any of the floats in the block we're doing
9506 // first-letter for, that is, before any floats whose parent is
9507 // containingBlock.
9508 nsIFrame* prevSibling = nullptr;
9509 for (nsIFrame* f : aState.mFloatedList) {
9510 if (f->GetParent() == containingBlock) {
9511 break;
9512 }
9513 prevSibling = f;
9514 }
9515
9516 aState.AddChild(letterFrame, aResult, letterContent, aParentFrame, false,
9517 true, true, prevSibling);
9518
9519 if (nextTextFrame) {
9520 aResult.AppendFrame(nullptr, nextTextFrame);
9521 }
9522
9523 return letterFrame;
9524}
9525
9526/**
9527 * Create a new letter frame for aTextFrame. The letter frame will be
9528 * a child of aParentFrame.
9529 */
9530void nsCSSFrameConstructor::CreateLetterFrame(
9531 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9532 Text* aTextContent, nsContainerFrame* aParentFrame, nsFrameList& aResult) {
9533 NS_ASSERTION(aBlockFrame->IsBlockFrameOrSubclass(), "Not a block frame?")do { if (!(aBlockFrame->IsBlockFrameOrSubclass())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Not a block frame?", "aBlockFrame->IsBlockFrameOrSubclass()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9533); MOZ_PretendNoReturn
(); } } while (0)
;
9534
9535 // Get a ComputedStyle for the first-letter-frame.
9536 //
9537 // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
9538 nsIFrame* parentFrame = nsIFrame::CorrectStyleParentFrame(
9539 aParentFrame, PseudoStyleType::FirstLetter);
9540
9541 ComputedStyle* parentComputedStyle = parentFrame->Style();
9542 ComputedStyle* parentComputedStyleIgnoringFirstLine = parentComputedStyle;
9543 if (parentFrame->IsLineFrame()) {
9544 parentComputedStyleIgnoringFirstLine =
9545 nsIFrame::CorrectStyleParentFrame(aBlockFrame,
9546 PseudoStyleType::FirstLetter)
9547 ->Style();
9548 }
9549
9550 // Use content from containing block so that we can actually
9551 // find a matching style rule.
9552 nsIContent* blockContent = aBlockFrame->GetContent();
9553
9554 // Create first-letter style rule, ignoring first line. If we already have a
9555 // first-line we'll reparent the style below.
9556 RefPtr<ComputedStyle> sc =
9557 GetFirstLetterStyle(blockContent, parentComputedStyleIgnoringFirstLine);
9558
9559 if (sc) {
9560 if (parentComputedStyleIgnoringFirstLine != parentComputedStyle) {
9561 sc = mPresShell->StyleSet()->ReparentComputedStyle(
9562 sc, parentComputedStyle, parentComputedStyle,
9563 blockContent->AsElement());
9564 }
9565
9566 RefPtr<ComputedStyle> textSC =
9567 mPresShell->StyleSet()->ResolveStyleForText(aTextContent, sc);
9568
9569 // Create a new text frame (the original one will be discarded)
9570 // pass a temporary stylecontext, the correct one will be set
9571 // later. Start off by unsetting the primary frame for
9572 // aTextContent, so it's no longer pointing to the to-be-destroyed
9573 // frame.
9574 // XXXbz it would be really nice to destroy the old frame _first_,
9575 // then create the new one, so we could avoid this hack.
9576 aTextContent->SetPrimaryFrame(nullptr);
9577 nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
9578
9579 NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),do { if (!(aBlockContinuation == GetFloatContainingBlock(aParentFrame
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Containing block is confused"
, "aBlockContinuation == GetFloatContainingBlock(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9580); MOZ_PretendNoReturn
(); } } while (0)
9580 "Containing block is confused")do { if (!(aBlockContinuation == GetFloatContainingBlock(aParentFrame
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Containing block is confused"
, "aBlockContinuation == GetFloatContainingBlock(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 9580); MOZ_PretendNoReturn
(); } } while (0)
;
9581 nsFrameConstructorState state(
9582 mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
9583 GetAbsoluteContainingBlock(aParentFrame, ABS_POS), aBlockContinuation);
9584
9585 // Create the right type of first-letter frame
9586 const nsStyleDisplay* display = sc->StyleDisplay();
9587 nsFirstLetterFrame* letterFrame;
9588 if (display->IsFloatingStyle() && !aParentFrame->IsInSVGTextSubtree()) {
9589 // Make a floating first-letter frame
9590 letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
9591 aParentFrame, parentComputedStyle,
9592 sc, aResult);
9593 } else {
9594 // Make an inflow first-letter frame
9595 letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
9596
9597 // Initialize the first-letter-frame. We don't want to use a text
9598 // content for a non-text frame (because we want its primary frame to
9599 // be a text frame).
9600 nsIContent* letterContent = aParentFrame->GetContent();
9601 letterFrame->Init(letterContent, aParentFrame, nullptr);
9602
9603 InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
9604
9605 SetInitialSingleChild(letterFrame, textFrame);
9606 aResult.Clear();
9607 aResult.AppendFrame(nullptr, letterFrame);
9608 NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),do { if (!(!aBlockFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "should have the first continuation here"
, "!aBlockFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9609); MOZ_PretendNoReturn(); } } while (0)
9609 "should have the first continuation here")do { if (!(!aBlockFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "should have the first continuation here"
, "!aBlockFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9609); MOZ_PretendNoReturn(); } } while (0)
;
9610 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9611 }
9612 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBlockFrame->GetPrevContinuation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aBlockFrame->GetPrevContinuation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aBlockFrame->GetPrevContinuation()"
" (" "Setting up a first-letter frame on a non-first block continuation?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9613 !aBlockFrame->GetPrevContinuation(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBlockFrame->GetPrevContinuation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aBlockFrame->GetPrevContinuation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aBlockFrame->GetPrevContinuation()"
" (" "Setting up a first-letter frame on a non-first block continuation?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9614 "Setting up a first-letter frame on a non-first block continuation?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBlockFrame->GetPrevContinuation())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aBlockFrame->GetPrevContinuation()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aBlockFrame->GetPrevContinuation()"
" (" "Setting up a first-letter frame on a non-first block continuation?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 9614
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9615 auto parent =
9616 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9617 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9618 parent = static_cast<nsContainerFrame*>(
9619 parent->GetParent()->FirstContinuation());
9620 }
9621 parent->SetHasFirstLetterChild();
9622 aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
9623 letterFrame);
9624 aTextContent->SetPrimaryFrame(textFrame);
9625 }
9626}
9627
9628void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9629 nsContainerFrame* aBlockFrame, nsFrameList& aBlockFrames) {
9630 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9631
9632 nsContainerFrame* parentFrame = nullptr;
9633 nsIFrame* textFrame = nullptr;
9634 nsIFrame* prevFrame = nullptr;
9635 nsFrameList letterFrames;
9636 bool stopLooking = false;
9637 WrapFramesInFirstLetterFrame(
9638 aBlockFrame, aBlockFrame, aBlockFrame, aBlockFrames.FirstChild(),
9639 &parentFrame, &textFrame, &prevFrame, letterFrames, &stopLooking);
9640 if (!parentFrame) {
9641 return;
9642 }
9643 DestroyContext context(mPresShell);
9644 if (parentFrame == aBlockFrame) {
9645 // Take textFrame out of the block's frame list and substitute the
9646 // letter frame(s) instead.
9647 aBlockFrames.DestroyFrame(context, textFrame);
9648 aBlockFrames.InsertFrames(nullptr, prevFrame, std::move(letterFrames));
9649 } else {
9650 // Take the old textFrame out of the inline parent's child list
9651 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9652
9653 // Insert in the letter frame(s)
9654 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9655 std::move(letterFrames));
9656 }
9657}
9658
9659void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9660 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9661 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
9662 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
9663 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking) {
9664 nsIFrame* prevFrame = nullptr;
9665 nsIFrame* frame = aParentFrameList;
9666
9667 // This loop attempts to implement "Finding the First Letter":
9668 // https://drafts.csswg.org/css-pseudo-4/#application-in-css
9669 // FIXME: we don't handle nested blocks correctly yet though (bug 214004)
9670 while (frame) {
9671 nsIFrame* nextFrame = frame->GetNextSibling();
9672
9673 // Skip all ::markers and placeholders.
9674 if (frame->Style()->GetPseudoType() == PseudoStyleType::Marker ||
9675 frame->IsPlaceholderFrame()) {
9676 prevFrame = frame;
9677 frame = nextFrame;
9678 continue;
9679 }
9680 LayoutFrameType frameType = frame->Type();
9681 if (LayoutFrameType::Text == frameType) {
9682 // Wrap up first-letter content in a letter frame
9683 Text* textContent = frame->GetContent()->AsText();
9684 if (IsFirstLetterContent(textContent)) {
9685 // Create letter frame to wrap up the text
9686 CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
9687 aParentFrame, aLetterFrames);
9688
9689 // Provide adjustment information for parent
9690 *aModifiedParent = aParentFrame;
9691 *aTextFrame = frame;
9692 *aPrevFrame = prevFrame;
9693 *aStopLooking = true;
9694 return;
9695 }
9696 } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
9697 nsIFrame* kids = frame->PrincipalChildList().FirstChild();
9698 WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
9699 static_cast<nsContainerFrame*>(frame), kids,
9700 aModifiedParent, aTextFrame, aPrevFrame,
9701 aLetterFrames, aStopLooking);
9702 if (*aStopLooking) {
9703 return;
9704 }
9705 } else {
9706 // This will stop us looking to create more letter frames. For
9707 // example, maybe the frame-type is "letterFrame" or
9708 // "placeholderFrame". This keeps us from creating extra letter
9709 // frames, and also prevents us from creating letter frames when
9710 // the first real content child of a block is not text (e.g. an
9711 // image, hr, etc.)
9712 *aStopLooking = true;
9713 break;
9714 }
9715
9716 prevFrame = frame;
9717 frame = nextFrame;
9718 }
9719}
9720
9721static nsIFrame* FindFirstLetterFrame(nsIFrame* aFrame,
9722 FrameChildListID aListID) {
9723 for (nsIFrame* f : aFrame->GetChildList(aListID)) {
9724 if (f->IsLetterFrame()) {
9725 return f;
9726 }
9727 }
9728 return nullptr;
9729}
9730
9731static void ClearHasFirstLetterChildFrom(nsContainerFrame* aParentFrame) {
9732 MOZ_ASSERT(aParentFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParentFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParentFrame))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aParentFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 9732); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9733 auto* parent =
9734 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9735 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9736 MOZ_ASSERT(!parent->HasFirstLetterChild())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parent->HasFirstLetterChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!parent->HasFirstLetterChild
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!parent->HasFirstLetterChild()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9736); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9737 parent = static_cast<nsContainerFrame*>(
9738 parent->GetParent()->FirstContinuation());
9739 }
9740 MOZ_ASSERT(parent->HasFirstLetterChild())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parent->HasFirstLetterChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parent->HasFirstLetterChild
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parent->HasFirstLetterChild()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9741 parent->ClearHasFirstLetterChild();
9742}
9743
9744void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
9745 PresShell* aPresShell, nsIFrame* aBlockFrame) {
9746 // Look for the first letter frame on the FrameChildListID::Float, then
9747 // FrameChildListID::PushedFloats.
9748 nsIFrame* floatFrame =
9749 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::Float);
9750 if (!floatFrame) {
9751 floatFrame =
9752 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::PushedFloats);
9753 if (!floatFrame) {
9754 return;
9755 }
9756 }
9757
9758 // Take the text frame away from the letter frame (so it isn't
9759 // destroyed when we destroy the letter frame).
9760 nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
9761 if (!textFrame) {
9762 return;
9763 }
9764
9765 // Discover the placeholder frame for the letter frame
9766 nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
9767 if (!placeholderFrame) {
9768 // Somethings really wrong
9769 return;
9770 }
9771 nsContainerFrame* parentFrame = placeholderFrame->GetParent();
9772 if (!parentFrame) {
9773 // Somethings really wrong
9774 return;
9775 }
9776
9777 ClearHasFirstLetterChildFrom(parentFrame);
9778
9779 // Create a new text frame with the right style that maps all of the content
9780 // that was previously part of the letter frame (and probably continued
9781 // elsewhere).
9782 ComputedStyle* parentSC = parentFrame->Style();
9783 nsIContent* textContent = textFrame->GetContent();
9784 if (!textContent) {
9785 return;
9786 }
9787 RefPtr<ComputedStyle> newSC =
9788 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9789 nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
9790 newTextFrame->Init(textContent, parentFrame, nullptr);
9791
9792 // Destroy the old text frame's continuations (the old text frame
9793 // will be destroyed when its letter frame is destroyed).
9794 nsIFrame* frameToDelete = textFrame->LastContinuation();
9795 DestroyContext context(mPresShell);
9796 while (frameToDelete != textFrame) {
9797 nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
9798 RemoveFrame(context, FrameChildListID::Principal, frameToDelete);
9799 frameToDelete = nextFrameToDelete;
9800 }
9801
9802 nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
9803
9804 // Now that everything is set...
9805#ifdef NOISY_FIRST_LETTER
9806 printf(
9807 "RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p "
9808 "newTextFrame=%p\n",
9809 textContent.get(), textFrame, newTextFrame);
9810#endif
9811
9812 // Remove placeholder frame and the float
9813 RemoveFrame(context, FrameChildListID::Principal, placeholderFrame);
9814
9815 // Now that the old frames are gone, we can start pointing to our
9816 // new primary frame.
9817 textContent->SetPrimaryFrame(newTextFrame);
9818
9819 // Wallpaper bug 822910.
9820 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9821 if (offsetsNeedFixing) {
9822 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9823 }
9824
9825 // Insert text frame in its place
9826 InsertFrames(parentFrame, FrameChildListID::Principal, prevSibling,
9827 nsFrameList(newTextFrame, newTextFrame));
9828
9829 if (offsetsNeedFixing) {
9830 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9831 }
9832}
9833
9834void nsCSSFrameConstructor::RemoveFirstLetterFrames(
9835 PresShell* aPresShell, nsContainerFrame* aFrame,
9836 nsContainerFrame* aBlockFrame, bool* aStopLooking) {
9837 nsIFrame* prevSibling = nullptr;
9838 nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
9839
9840 while (kid) {
9841 if (kid->IsLetterFrame()) {
9842 ClearHasFirstLetterChildFrom(aFrame);
9843 nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
9844 if (!textFrame) {
9845 break;
9846 }
9847
9848 // Create a new textframe
9849 ComputedStyle* parentSC = aFrame->Style();
9850 if (!parentSC) {
9851 break;
9852 }
9853 nsIContent* textContent = textFrame->GetContent();
9854 if (!textContent) {
9855 break;
9856 }
9857 RefPtr<ComputedStyle> newSC =
9858 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9859 textFrame = NS_NewTextFrame(aPresShell, newSC);
9860 textFrame->Init(textContent, aFrame, nullptr);
9861
9862 DestroyContext context(mPresShell);
9863
9864 // Next rip out the kid and replace it with the text frame
9865 RemoveFrame(context, FrameChildListID::Principal, kid);
9866
9867 // Now that the old frames are gone, we can start pointing to our
9868 // new primary frame.
9869 textContent->SetPrimaryFrame(textFrame);
9870
9871 // Wallpaper bug 822910.
9872 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9873 if (offsetsNeedFixing) {
9874 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9875 }
9876
9877 // Insert text frame in its place
9878 InsertFrames(aFrame, FrameChildListID::Principal, prevSibling,
9879 nsFrameList(textFrame, textFrame));
9880
9881 if (offsetsNeedFixing) {
9882 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9883 }
9884
9885 *aStopLooking = true;
9886 NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),do { if (!(!aBlockFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "should have the first continuation here"
, "!aBlockFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9887); MOZ_PretendNoReturn(); } } while (0)
9887 "should have the first continuation here")do { if (!(!aBlockFrame->GetPrevContinuation())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "should have the first continuation here"
, "!aBlockFrame->GetPrevContinuation()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9887); MOZ_PretendNoReturn(); } } while (0)
;
9888 aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9889 break;
9890 }
9891 if (IsInlineFrame(kid)) {
9892 nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
9893 if (kidAsContainerFrame) {
9894 // Look inside child inline frame for the letter frame.
9895 RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame, aBlockFrame,
9896 aStopLooking);
9897 if (*aStopLooking) {
9898 break;
9899 }
9900 }
9901 }
9902 prevSibling = kid;
9903 kid = kid->GetNextSibling();
9904 }
9905}
9906
9907void nsCSSFrameConstructor::RemoveLetterFrames(PresShell* aPresShell,
9908 nsContainerFrame* aBlockFrame) {
9909 aBlockFrame =
9910 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9911 aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
9912 nsContainerFrame* continuation = aBlockFrame;
9913
9914 bool stopLooking = false;
9915 do {
9916 RemoveFloatingFirstLetterFrames(aPresShell, continuation);
9917 RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
9918 &stopLooking);
9919 if (stopLooking) {
9920 break;
9921 }
9922 continuation =
9923 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9924 } while (continuation);
9925}
9926
9927// Fixup the letter frame situation for the given block
9928void nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) {
9929 aBlockFrame =
9930 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9931 nsContainerFrame* continuation = aBlockFrame;
9932
9933 nsContainerFrame* parentFrame = nullptr;
9934 nsIFrame* textFrame = nullptr;
9935 nsIFrame* prevFrame = nullptr;
9936 nsFrameList letterFrames;
9937 bool stopLooking = false;
9938 do {
9939 // XXX shouldn't this bit be set already (bug 408493), assert instead?
9940 continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9941 WrapFramesInFirstLetterFrame(
9942 aBlockFrame, continuation, continuation,
9943 continuation->PrincipalChildList().FirstChild(), &parentFrame,
9944 &textFrame, &prevFrame, letterFrames, &stopLooking);
9945 if (stopLooking) {
9946 break;
9947 }
9948 continuation =
9949 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9950 } while (continuation);
9951
9952 if (!parentFrame) {
9953 return;
9954 }
9955 // Take the old textFrame out of the parent's child list
9956 DestroyContext context(mPresShell);
9957 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9958
9959 // Insert in the letter frame(s)
9960 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9961 std::move(letterFrames));
9962}
9963
9964//----------------------------------------------------------------------
9965
9966void nsCSSFrameConstructor::ConstructBlock(
9967 nsFrameConstructorState& aState, nsIContent* aContent,
9968 nsContainerFrame* aParentFrame, nsContainerFrame* aContentParentFrame,
9969 ComputedStyle* aComputedStyle, nsContainerFrame** aNewFrame,
9970 nsFrameList& aFrameList, nsIFrame* aPositionedFrameForAbsPosContainer) {
9971 // clang-format off
9972 //
9973 // If a block frame is in a multi-column subtree, its children may need to
9974 // be chopped into runs of blocks containing column-spans and runs of
9975 // blocks containing no column-spans. Each run containing column-spans
9976 // will be wrapped by an anonymous block. See CreateColumnSpanSiblings() for
9977 // the implementation.
9978 //
9979 // If a block frame is a multi-column container, its children will need to
9980 // be processed as above. Moreover, it creates a ColumnSetWrapperFrame as
9981 // its outermost frame, and its children which have no
9982 // -moz-column-span-wrapper pseudo will be wrapped in ColumnSetFrames. See
9983 // FinishBuildingColumns() for the implementation.
9984 //
9985 // The multi-column subtree maintains the following invariants:
9986 //
9987 // 1) All the frames have the frame state bit
9988 // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR set, except for top-level
9989 // ColumnSetWrapperFrame and those children in the column-span subtrees.
9990 //
9991 // 2) The first and last frame under ColumnSetWrapperFrame are always
9992 // ColumnSetFrame.
9993 //
9994 // 3) ColumnSetFrames are linked together as continuations.
9995 //
9996 // 4) Those column-span wrappers are *not* linked together with themselves nor
9997 // with the original block frame. The continuation chain consists of the
9998 // original block frame and the original block's continuations wrapping
9999 // non-column-spans.
10000 //
10001 // For example, this HTML
10002 // <div id="x" style="column-count: 2;">
10003 // <div style="column-span: all">a</div>
10004 // <div id="y">
10005 // b
10006 // <div style="column-span: all">c</div>
10007 // <div style="column-span: all">d</div>
10008 // e
10009 // </div>
10010 // </div>
10011 // <div style="column-span: all">f</div>
10012 //
10013 // yields the following frame tree.
10014 //
10015 // A) ColumnSetWrapper (original style)
10016 // B) ColumnSet (-moz-column-set) <-- always created by BeginBuildingColumns
10017 // C) Block (-moz-column-content)
10018 // D) Block (-moz-column-span-wrapper, created by x)
10019 // E) Block (div)
10020 // F) Text ("a")
10021 // G) ColumnSet (-moz-column-set)
10022 // H) Block (-moz-column-content, created by x)
10023 // I) Block (div, y)
10024 // J) Text ("b")
10025 // K) Block (-moz-column-span-wrapper, created by x)
10026 // L) Block (-moz-column-span-wrapper, created by y)
10027 // M) Block (div, new BFC)
10028 // N) Text ("c")
10029 // O) Block (div, new BFC)
10030 // P) Text ("d")
10031 // Q) ColumnSet (-moz-column-set)
10032 // R) Block (-moz-column-content, created by x)
10033 // S) Block (div, y)
10034 // T) Text ("e")
10035 // U) Block (div, new BFC) <-- not in multi-column hierarchy
10036 // V) Text ("f")
10037 //
10038 // ColumnSet linkage described in 3): B -> G -> Q
10039 //
10040 // Block linkage described in 4): C -> H -> R and I -> S
10041 //
10042 // clang-format on
10043
10044 nsBlockFrame* blockFrame = do_QueryFrame(*aNewFrame);
10045 MOZ_ASSERT(blockFrame && blockFrame->IsBlockFrame(), "not a block frame?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(blockFrame && blockFrame->IsBlockFrame())
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(blockFrame && blockFrame->IsBlockFrame())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("blockFrame && blockFrame->IsBlockFrame()"
" (" "not a block frame?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockFrame && blockFrame->IsBlockFrame()"
") (" "not a block frame?" ")"); do { MOZ_CrashSequence(__null
, 10045); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10046
10047 // Create column hierarchy if necessary.
10048 const bool needsColumn =
10049 aComputedStyle->StyleColumn()->IsColumnContainerStyle() &&
10050 !aParentFrame->IsTextInputFrame();
10051 if (needsColumn) {
10052 *aNewFrame = BeginBuildingColumns(aState, aContent, aParentFrame,
10053 blockFrame, aComputedStyle);
10054
10055 if (aPositionedFrameForAbsPosContainer == blockFrame) {
10056 aPositionedFrameForAbsPosContainer = *aNewFrame;
10057 }
10058 } else {
10059 // No need to create column hierarchy. Initialize block frame.
10060 blockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
10061 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
10062 }
10063
10064 aState.AddChild(*aNewFrame, aFrameList, aContent,
10065 aContentParentFrame ? aContentParentFrame : aParentFrame);
10066 if (!mRootElementFrame) {
10067 mRootElementFrame = *aNewFrame;
10068 }
10069
10070 // We should make the outer frame be the absolute containing block,
10071 // if one is required. We have to do this because absolute
10072 // positioning must be computed with respect to the CSS dimensions
10073 // of the element, which are the dimensions of the outer block. But
10074 // we can't really do that because only blocks can have absolute
10075 // children. So use the block and try to compensate with hacks
10076 // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10077 nsFrameConstructorSaveState absoluteSaveState;
10078 (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10079 if (aPositionedFrameForAbsPosContainer) {
10080 aState.PushAbsoluteContainingBlock(
10081 *aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
10082 }
10083
10084 nsFrameConstructorSaveState floatSaveState;
10085 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
10086
10087 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10088 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10089 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10090 }
10091
10092 // Process the child content
10093 nsFrameList childList;
10094 ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true, childList,
10095 true);
10096
10097 if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childList)) {
10098 // No need to create column-span siblings.
10099 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10100 std::move(childList));
10101 return;
10102 }
10103
10104 // Extract any initial non-column-span kids, and put them in block frame's
10105 // child list.
10106 nsFrameList initialNonColumnSpanKids =
10107 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10108 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10109 std::move(initialNonColumnSpanKids));
10110
10111 if (childList.IsEmpty()) {
10112 // No more kids to process (there weren't any column-span kids).
10113 return;
10114 }
10115
10116 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
10117 aState, blockFrame, childList,
10118 // If we're constructing a column container, pass nullptr as
10119 // aPositionedFrame to forbid reparenting absolute/fixed positioned frames
10120 // to column contents or column-span wrappers.
10121 needsColumn ? nullptr : aPositionedFrameForAbsPosContainer);
10122
10123 if (needsColumn) {
10124 // We're constructing a column container; need to finish building it.
10125 FinishBuildingColumns(aState, *aNewFrame, blockFrame, columnSpanSiblings);
10126 } else {
10127 // We're constructing a normal block which has column-span children in a
10128 // column hierarchy such as "x" in the following example.
10129 //
10130 // <div style="column-count: 2">
10131 // <div id="x">
10132 // <div>normal child</div>
10133 // <div style="column-span">spanner</div>
10134 // </div>
10135 // </div>
10136 aFrameList.AppendFrames(nullptr, std::move(columnSpanSiblings));
10137 }
10138
10139 MOZ_ASSERT(columnSpanSiblings.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSpanSiblings.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSpanSiblings.IsEmpty()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"columnSpanSiblings.IsEmpty()" " (" "The column-span siblings should be moved to the proper place!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 10140
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10140); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10140 "The column-span siblings should be moved to the proper place!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(columnSpanSiblings.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(columnSpanSiblings.IsEmpty()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"columnSpanSiblings.IsEmpty()" " (" "The column-span siblings should be moved to the proper place!"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 10140
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10140); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10141}
10142
10143nsBlockFrame* nsCSSFrameConstructor::BeginBuildingColumns(
10144 nsFrameConstructorState& aState, nsIContent* aContent,
10145 nsContainerFrame* aParentFrame, nsContainerFrame* aColumnContent,
10146 ComputedStyle* aComputedStyle) {
10147 MOZ_ASSERT(aColumnContent->IsBlockFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aColumnContent->IsBlockFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aColumnContent->IsBlockFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aColumnContent->IsBlockFrame()" " (" "aColumnContent should be a block frame."
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 10148
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10148); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10148 "aColumnContent should be a block frame.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aColumnContent->IsBlockFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aColumnContent->IsBlockFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aColumnContent->IsBlockFrame()" " (" "aColumnContent should be a block frame."
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 10148
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10148); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10149 MOZ_ASSERT(aComputedStyle->StyleColumn()->IsColumnContainerStyle(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedStyle->StyleColumn()->IsColumnContainerStyle
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aComputedStyle->StyleColumn()->IsColumnContainerStyle
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
" (" "No need to build a column hierarchy!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10150); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10150 "No need to build a column hierarchy!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aComputedStyle->StyleColumn()->IsColumnContainerStyle
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aComputedStyle->StyleColumn()->IsColumnContainerStyle
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
" (" "No need to build a column hierarchy!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10150); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10151
10152 // The initial column hierarchy looks like this:
10153 //
10154 // ColumnSetWrapper (original style)
10155 // ColumnSet (-moz-column-set)
10156 // Block (-moz-column-content)
10157 //
10158 nsBlockFrame* columnSetWrapper = NS_NewColumnSetWrapperFrame(
10159 mPresShell, aComputedStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10160 InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);
10161 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10162 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10163 columnSetWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10164 }
10165
10166 AutoFrameConstructionPageName pageNameTracker(aState, columnSetWrapper);
10167 RefPtr<ComputedStyle> columnSetStyle =
10168 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10169 PseudoStyleType::MozColumnSet, aComputedStyle);
10170 nsContainerFrame* columnSet = NS_NewColumnSetFrame(
10171 mPresShell, columnSetStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10172 InitAndRestoreFrame(aState, aContent, columnSetWrapper, columnSet);
10173 columnSet->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10174
10175 RefPtr<ComputedStyle> blockStyle =
10176 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10177 PseudoStyleType::MozColumnContent, columnSetStyle);
10178 aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
10179 InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
10180 aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10181
10182 // Set up the parent-child chain.
10183 SetInitialSingleChild(columnSetWrapper, columnSet);
10184 SetInitialSingleChild(columnSet, aColumnContent);
10185
10186 return columnSetWrapper;
10187}
10188
10189void nsCSSFrameConstructor::FinishBuildingColumns(
10190 nsFrameConstructorState& aState, nsContainerFrame* aColumnSetWrapper,
10191 nsContainerFrame* aColumnContent, nsFrameList& aColumnContentSiblings) {
10192 nsContainerFrame* prevColumnSet = aColumnContent->GetParent();
10193
10194 MOZ_ASSERT(prevColumnSet->IsColumnSetFrame() &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevColumnSet->IsColumnSetFrame() && prevColumnSet
->GetParent() == aColumnSetWrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevColumnSet->IsColumnSetFrame
() && prevColumnSet->GetParent() == aColumnSetWrapper
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
" (" "Should have established column hierarchy!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10196); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10196); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10195 prevColumnSet->GetParent() == aColumnSetWrapper,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevColumnSet->IsColumnSetFrame() && prevColumnSet
->GetParent() == aColumnSetWrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevColumnSet->IsColumnSetFrame
() && prevColumnSet->GetParent() == aColumnSetWrapper
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
" (" "Should have established column hierarchy!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10196); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10196); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10196 "Should have established column hierarchy!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prevColumnSet->IsColumnSetFrame() && prevColumnSet
->GetParent() == aColumnSetWrapper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prevColumnSet->IsColumnSetFrame
() && prevColumnSet->GetParent() == aColumnSetWrapper
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
" (" "Should have established column hierarchy!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10196); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10196); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
10197
10198 // Tag the first ColumnSet to have column-span siblings so that the bit can
10199 // propagate to all the continuations. We don't want the last ColumnSet to
10200 // have this bit, so we will unset the bit for it at the end of this function.
10201 prevColumnSet->SetHasColumnSpanSiblings(true);
10202
10203 nsFrameList finalList;
10204 while (aColumnContentSiblings.NotEmpty()) {
10205 nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
10206 if (f->IsColumnSpan()) {
10207 // Do nothing for column-span wrappers. Just move it to the final
10208 // items.
10209 finalList.AppendFrame(aColumnSetWrapper, f);
10210 } else {
10211 auto* continuingColumnSet = static_cast<nsContainerFrame*>(
10212 CreateContinuingFrame(prevColumnSet, aColumnSetWrapper, false));
10213 MOZ_ASSERT(continuingColumnSet->HasColumnSpanSiblings(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(continuingColumnSet->HasColumnSpanSiblings())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(continuingColumnSet->HasColumnSpanSiblings()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("continuingColumnSet->HasColumnSpanSiblings()"
" (" "The bit should propagate to the next continuation!" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10214);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10214); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10214 "The bit should propagate to the next continuation!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(continuingColumnSet->HasColumnSpanSiblings())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(continuingColumnSet->HasColumnSpanSiblings()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("continuingColumnSet->HasColumnSpanSiblings()"
" (" "The bit should propagate to the next continuation!" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10214);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10214); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10215
10216 f->SetParent(continuingColumnSet);
10217 SetInitialSingleChild(continuingColumnSet, f);
10218 finalList.AppendFrame(aColumnSetWrapper, continuingColumnSet);
10219 prevColumnSet = continuingColumnSet;
10220 }
10221 }
10222
10223 // Unset the bit because the last ColumnSet has no column-span siblings.
10224 prevColumnSet->SetHasColumnSpanSiblings(false);
10225
10226 aColumnSetWrapper->AppendFrames(FrameChildListID::Principal,
10227 std::move(finalList));
10228}
10229
10230bool nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
10231 nsContainerFrame* aBlockFrame, const nsFrameList& aChildList) {
10232 if (!aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10233 // The block frame isn't in a multi-column block formatting context.
10234 return false;
10235 }
10236
10237 if (ShouldSuppressColumnSpanDescendants(aBlockFrame)) {
10238 // No need to create column-span siblings for a frame that suppresses them.
10239 return false;
10240 }
10241
10242 if (aChildList.IsEmpty()) {
10243 // No child needs to be processed.
10244 return false;
10245 }
10246
10247 // Need to actually look into the child list.
10248 return true;
10249}
10250
10251nsFrameList nsCSSFrameConstructor::CreateColumnSpanSiblings(
10252 nsFrameConstructorState& aState, nsContainerFrame* aInitialBlock,
10253 nsFrameList& aChildList, nsIFrame* aPositionedFrame) {
10254 MOZ_ASSERT(aInitialBlock->IsBlockFrameOrSubclass())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInitialBlock->IsBlockFrameOrSubclass())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aInitialBlock->IsBlockFrameOrSubclass()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aInitialBlock->IsBlockFrameOrSubclass()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10254);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitialBlock->IsBlockFrameOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 10254); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10255 MOZ_ASSERT(!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10255);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10255); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10256
10257 nsIContent* const content = aInitialBlock->GetContent();
10258 nsContainerFrame* const parentFrame = aInitialBlock->GetParent();
10259 const bool isInitialBlockFloatCB = aInitialBlock->IsFloatContainingBlock();
10260
10261 nsFrameList siblings;
10262 nsContainerFrame* lastNonColumnSpanWrapper = aInitialBlock;
10263
10264 // Tag the first non-column-span wrapper to have column-span siblings so that
10265 // the bit can propagate to all the continuations. We don't want the last
10266 // wrapper to have this bit, so we will unset the bit for it at the end of
10267 // this function.
10268 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(true);
10269 do {
10270 MOZ_ASSERT(aChildList.NotEmpty(), "Why call this if child list is empty?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.NotEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildList.NotEmpty()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aChildList.NotEmpty()"
" (" "Why call this if child list is empty?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10270); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Why call this if child list is empty?" ")"); do { MOZ_CrashSequence
(__null, 10270); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10271 MOZ_ASSERT(aChildList.FirstChild()->IsColumnSpan(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.FirstChild()->IsColumnSpan())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aChildList.FirstChild()->IsColumnSpan()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aChildList.FirstChild()->IsColumnSpan()"
" (" "Must have the child starting with column-span!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10272); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10272); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10272 "Must have the child starting with column-span!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.FirstChild()->IsColumnSpan())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aChildList.FirstChild()->IsColumnSpan()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aChildList.FirstChild()->IsColumnSpan()"
" (" "Must have the child starting with column-span!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10272); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10272); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10273
10274 // Grab the consecutive column-span kids, and reparent them into a
10275 // block frame.
10276 RefPtr<ComputedStyle> columnSpanWrapperStyle =
10277 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
10278 PseudoStyleType::MozColumnSpanWrapper);
10279 nsBlockFrame* columnSpanWrapper =
10280 NS_NewBlockFrame(mPresShell, columnSpanWrapperStyle);
10281 InitAndRestoreFrame(aState, content, parentFrame, columnSpanWrapper,
10282 AllowCounters::No);
10283 columnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10284 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10285
10286 nsFrameList columnSpanKids =
10287 aChildList.Split([](nsIFrame* f) { return !f->IsColumnSpan(); });
10288 columnSpanKids.ApplySetParent(columnSpanWrapper);
10289 columnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10290 std::move(columnSpanKids));
10291 if (aPositionedFrame) {
10292 aState.ReparentAbsoluteItems(columnSpanWrapper);
10293 }
10294
10295 siblings.AppendFrame(nullptr, columnSpanWrapper);
10296
10297 // Grab the consecutive non-column-span kids, and reparent them into a new
10298 // continuation of the last non-column-span wrapper frame.
10299 auto* nonColumnSpanWrapper = static_cast<nsContainerFrame*>(
10300 CreateContinuingFrame(lastNonColumnSpanWrapper, parentFrame, false));
10301 nonColumnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10302 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10303 MOZ_ASSERT(nonColumnSpanWrapper->HasColumnSpanSiblings(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nonColumnSpanWrapper->HasColumnSpanSiblings())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nonColumnSpanWrapper->HasColumnSpanSiblings()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("nonColumnSpanWrapper->HasColumnSpanSiblings()"
" (" "The bit should propagate to the next continuation!" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10304);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10304); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10304 "The bit should propagate to the next continuation!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nonColumnSpanWrapper->HasColumnSpanSiblings())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nonColumnSpanWrapper->HasColumnSpanSiblings()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("nonColumnSpanWrapper->HasColumnSpanSiblings()"
" (" "The bit should propagate to the next continuation!" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10304);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10304); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10305
10306 if (aChildList.NotEmpty()) {
10307 nsFrameList nonColumnSpanKids =
10308 aChildList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10309
10310 nonColumnSpanKids.ApplySetParent(nonColumnSpanWrapper);
10311 nonColumnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10312 std::move(nonColumnSpanKids));
10313 if (aPositionedFrame) {
10314 aState.ReparentAbsoluteItems(nonColumnSpanWrapper);
10315 }
10316 if (isInitialBlockFloatCB) {
10317 aState.ReparentFloats(nonColumnSpanWrapper);
10318 }
10319 }
10320
10321 siblings.AppendFrame(nullptr, nonColumnSpanWrapper);
10322
10323 lastNonColumnSpanWrapper = nonColumnSpanWrapper;
10324 } while (aChildList.NotEmpty());
10325
10326 // Unset the bit because the last non-column-span wrapper has no column-span
10327 // siblings.
10328 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(false);
10329
10330 return siblings;
10331}
10332
10333bool nsCSSFrameConstructor::MaybeRecreateForColumnSpan(
10334 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
10335 nsFrameList& aFrameList, nsIFrame* aPrevSibling) {
10336 if (!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10337 return false;
10338 }
10339
10340 if (aFrameList.IsEmpty()) {
10341 return false;
10342 }
10343
10344 MOZ_ASSERT(!IsFramePartOfIBSplit(aParentFrame),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsFramePartOfIBSplit(aParentFrame)" " (" "We should have wiped aParentFrame in "
"WipeContainingBlock if it's part of IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10346); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10345 "We should have wiped aParentFrame in "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsFramePartOfIBSplit(aParentFrame)" " (" "We should have wiped aParentFrame in "
"WipeContainingBlock if it's part of IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10346); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10346 "WipeContainingBlock if it's part of IB split!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFramePartOfIBSplit(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsFramePartOfIBSplit(aParentFrame
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsFramePartOfIBSplit(aParentFrame)" " (" "We should have wiped aParentFrame in "
"WipeContainingBlock if it's part of IB split!" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10346); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10347
10348 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
10349 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
10350 // We are appending a list of frames to the last continuation of a
10351 // ::-moz-column-content. This is the case where we can fix the frame tree
10352 // instead of reframing the containing block. Return false and let
10353 // AppendFramesToParent() deal with this.
10354 return false;
10355 }
10356
10357 auto HasColumnSpan = [](const nsFrameList& aList) {
10358 for (nsIFrame* f : aList) {
10359 if (f->IsColumnSpan()) {
10360 return true;
10361 }
10362 }
10363 return false;
10364 };
10365
10366 if (HasColumnSpan(aFrameList)) {
10367 // If any frame in the frame list has "column-span:all" style, i.e. a
10368 // -moz-column-span-wrapper frame, we need to reframe the multi-column
10369 // containing block.
10370 //
10371 // We can only be here if none of the new inserted nsIContent* nodes (via
10372 // ContentAppended or ContentRangeInserted) have column-span:all style, yet
10373 // some of them have column-span:all descendants. Sadly, there's no way to
10374 // detect this by checking FrameConstructionItems in WipeContainingBlock().
10375 // Otherwise, we would have already wiped the multi-column containing block.
10376 PROFILER_MARKER("Reframe multi-column after constructing frame list",do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Reframe multi-column after constructing frame list", ::geckoprofiler
::category::LAYOUT, {}, ::geckoprofiler::markers::Tracing{}, "Layout"
); } } while (false); } while (false)
10377 LAYOUT, {}, Tracing, "Layout")do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Reframe multi-column after constructing frame list", ::geckoprofiler
::category::LAYOUT, {}, ::geckoprofiler::markers::Tracing{}, "Layout"
); } } while (false); } while (false)
;
10378
10379 // aFrameList can contain placeholder frames. In order to destroy their
10380 // associated out-of-flow frames properly, we need to manually flush all the
10381 // out-of-flow frames in aState to their container frames.
10382 aState.ProcessFrameInsertionsForAllLists();
10383 DestroyContext context(mPresShell);
10384 aFrameList.DestroyFrames(context);
10385 RecreateFramesForContent(
10386 GetMultiColumnContainingBlockFor(aParentFrame)->GetContent(),
10387 InsertionKind::Async);
10388 return true;
10389 }
10390
10391 return false;
10392}
10393
10394nsIFrame* nsCSSFrameConstructor::ConstructInline(
10395 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
10396 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
10397 nsFrameList& aFrameList) {
10398 // If an inline frame has non-inline kids, then we chop up the child list
10399 // into runs of blocks and runs of inlines, create anonymous block frames to
10400 // contain the runs of blocks, inline frames with our style for the runs of
10401 // inlines, and put all these frames, in order, into aFrameList.
10402 //
10403 // When there are column-span blocks in a run of blocks, instead of creating
10404 // an anonymous block to wrap them, we create multiple anonymous blocks,
10405 // wrapping runs of non-column-spans and runs of column-spans.
10406 //
10407 // We return the the first one. The whole setup is called an {ib}
10408 // split; in what follows "frames in the split" refers to the anonymous blocks
10409 // and inlines that contain our children.
10410 //
10411 // {ib} splits maintain the following invariants:
10412 // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
10413 // set.
10414 //
10415 // 2) Each frame in the split has the nsIFrame::IBSplitSibling
10416 // property pointing to the next frame in the split, except for the last
10417 // one, which does not have it set.
10418 //
10419 // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
10420 // property pointing to the previous frame in the split, except for the
10421 // first one, which does not have it set.
10422 //
10423 // 4) The first and last frame in the split are always inlines.
10424 //
10425 // 5) The frames wrapping runs of non-column-spans are linked together as
10426 // continuations. The frames wrapping runs of column-spans are *not*
10427 // linked with each other nor with other non-column-span wrappers.
10428 //
10429 // 6) The first and last frame in the chains of blocks are always wrapping
10430 // non-column-spans. Both of them are created even if they're empty.
10431 //
10432 // An invariant that is NOT maintained is that the wrappers are actually
10433 // linked via GetNextSibling linkage. A simple example is an inline
10434 // containing an inline that contains a block. The three parts of the inner
10435 // inline end up with three different parents.
10436 //
10437 // For example, this HTML:
10438 // <span>
10439 // <div>a</div>
10440 // <span>
10441 // b
10442 // <div>c</div>
10443 // </span>
10444 // d
10445 // <div>e</div>
10446 // f
10447 // </span>
10448 // Gives the following frame tree:
10449 //
10450 // Inline (outer span)
10451 // Block (anonymous, outer span)
10452 // Block (div)
10453 // Text("a")
10454 // Inline (outer span)
10455 // Inline (inner span)
10456 // Text("b")
10457 // Block (anonymous, outer span)
10458 // Block (anonymous, inner span)
10459 // Block (div)
10460 // Text("c")
10461 // Inline (outer span)
10462 // Inline (inner span)
10463 // Text("d")
10464 // Block (anonymous, outer span)
10465 // Block (div)
10466 // Text("e")
10467 // Inline (outer span)
10468 // Text("f")
10469
10470 nsIContent* const content = aItem.mContent;
10471 ComputedStyle* const computedStyle = aItem.mComputedStyle;
10472
10473 nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10474
10475 // Initialize the frame
10476 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
10477
10478 // definition cannot be inside next block because the object's destructor is
10479 // significant. this is part of the fix for bug 42372
10480 nsFrameConstructorSaveState absoluteSaveState;
10481
10482 bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
10483 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10484 if (isAbsPosCB) {
10485 // Relatively positioned frames becomes a container for child
10486 // frames that are positioned
10487 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
10488 }
10489
10490 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10491 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10492 newFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10493 }
10494
10495 // Process the child content
10496 nsFrameList childList;
10497 ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
10498 /* aParentIsWrapperAnonBox = */ false, childList);
10499
10500 nsIFrame* firstBlock = nullptr;
10501 if (!aItem.mIsAllInline) {
10502 for (nsIFrame* f : childList) {
10503 if (f->IsBlockOutside()) {
10504 firstBlock = f;
10505 break;
10506 }
10507 }
10508 }
10509
10510 if (aItem.mIsAllInline || !firstBlock) {
10511 // This part is easy. We either already know we have no non-inline kids,
10512 // or haven't found any when constructing actual frames (the latter can
10513 // happen only if out-of-flows that we thought had no containing block
10514 // acquired one when ancestor inline frames and {ib} splits got
10515 // constructed). Just put all the kids into the single inline frame and
10516 // bail.
10517 newFrame->SetInitialChildList(FrameChildListID::Principal,
10518 std::move(childList));
10519 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
10520 return newFrame;
10521 }
10522
10523 // This inline frame contains several types of children. Therefore this frame
10524 // has to be chopped into several pieces, as described above.
10525
10526 // Grab the first inline's kids
10527 nsFrameList firstInlineKids = childList.TakeFramesBefore(firstBlock);
10528 newFrame->SetInitialChildList(FrameChildListID::Principal,
10529 std::move(firstInlineKids));
10530
10531 aFrameList.AppendFrame(nullptr, newFrame);
10532
10533 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10534 CreateIBSiblings(aState, newFrame, isAbsPosCB, childList, aFrameList);
10535
10536 return newFrame;
10537}
10538
10539void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
10540 nsContainerFrame* aInitialInline,
10541 bool aIsAbsPosCB,
10542 nsFrameList& aChildList,
10543 nsFrameList& aSiblings) {
10544 MOZ_ASSERT(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10544);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10544); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10545
10546 nsIContent* content = aInitialInline->GetContent();
10547 ComputedStyle* computedStyle = aInitialInline->Style();
10548 nsContainerFrame* parentFrame = aInitialInline->GetParent();
10549
10550 // Resolve the right style for our anonymous blocks.
10551 //
10552 // The distinction in styles is needed because of CSS 2.1, section
10553 // 9.2.1.1, which says:
10554 //
10555 // When such an inline box is affected by relative positioning, any
10556 // resulting translation also affects the block-level box contained
10557 // in the inline box.
10558 RefPtr<ComputedStyle> blockSC =
10559 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10560 PseudoStyleType::MozBlockInsideInlineWrapper, computedStyle);
10561
10562 nsContainerFrame* lastNewInline =
10563 static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
10564 do {
10565 // On entry to this loop aChildList is not empty and the first frame in it
10566 // is block-level.
10567 MOZ_ASSERT(aChildList.NotEmpty(), "Should have child items")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.NotEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aChildList.NotEmpty()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aChildList.NotEmpty()"
" (" "Should have child items" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Should have child items" ")"); do { MOZ_CrashSequence
(__null, 10567); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10568 MOZ_ASSERT(aChildList.FirstChild()->IsBlockOutside(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.FirstChild()->IsBlockOutside())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aChildList.FirstChild()->IsBlockOutside()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aChildList.FirstChild()->IsBlockOutside()"
" (" "Must have list starting with block" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10569); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10569 "Must have list starting with block")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChildList.FirstChild()->IsBlockOutside())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aChildList.FirstChild()->IsBlockOutside()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aChildList.FirstChild()->IsBlockOutside()"
" (" "Must have list starting with block" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10569); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10570
10571 // The initial run of blocks belongs to an anonymous block that we create
10572 // right now. The anonymous block will be the parent of these block
10573 // children of the inline.
10574 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10575 InitAndRestoreFrame(aState, content, parentFrame, blockFrame,
10576 AllowCounters::No);
10577 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10578 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10579 }
10580
10581 // Find the first non-block child which defines the end of our block kids
10582 // and the start of our next inline's kids
10583 nsFrameList blockKids =
10584 aChildList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
10585
10586 if (!aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10587 MoveChildrenTo(aInitialInline, blockFrame, blockKids);
10588
10589 SetFrameIsIBSplit(lastNewInline, blockFrame);
10590 aSiblings.AppendFrame(nullptr, blockFrame);
10591 } else {
10592 // Extract any initial non-column-span frames, and put them in
10593 // blockFrame's child list.
10594 nsFrameList initialNonColumnSpanKids =
10595 blockKids.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10596 MoveChildrenTo(aInitialInline, blockFrame, initialNonColumnSpanKids);
10597
10598 SetFrameIsIBSplit(lastNewInline, blockFrame);
10599 aSiblings.AppendFrame(nullptr, blockFrame);
10600
10601 if (blockKids.NotEmpty()) {
10602 // Although SetFrameIsIBSplit() will add NS_FRAME_PART_OF_IBSPLIT for
10603 // blockFrame later, we manually add the bit earlier here to make all
10604 // the continuations of blockFrame created in
10605 // CreateColumnSpanSiblings(), i.e. non-column-span wrappers, have the
10606 // bit via nsIFrame::Init().
10607 blockFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
10608
10609 nsFrameList columnSpanSiblings =
10610 CreateColumnSpanSiblings(aState, blockFrame, blockKids,
10611 aIsAbsPosCB ? aInitialInline : nullptr);
10612 aSiblings.AppendFrames(nullptr, std::move(columnSpanSiblings));
10613 }
10614 }
10615
10616 // Now grab the initial inlines in aChildList and put them into an inline
10617 // frame.
10618 nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10619 InitAndRestoreFrame(aState, content, parentFrame, inlineFrame,
10620 AllowCounters::No);
10621 inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10622 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10623 inlineFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10624 }
10625
10626 if (aIsAbsPosCB) {
10627 inlineFrame->MarkAsAbsoluteContainingBlock();
10628 }
10629
10630 if (aChildList.NotEmpty()) {
10631 nsFrameList inlineKids =
10632 aChildList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
10633 MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
10634 }
10635
10636 SetFrameIsIBSplit(blockFrame, inlineFrame);
10637 aSiblings.AppendFrame(nullptr, inlineFrame);
10638 lastNewInline = inlineFrame;
10639 } while (aChildList.NotEmpty());
10640
10641 SetFrameIsIBSplit(lastNewInline, nullptr);
10642}
10643
10644void nsCSSFrameConstructor::BuildInlineChildItems(
10645 nsFrameConstructorState& aState, FrameConstructionItem& aParentItem,
10646 bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) {
10647 ComputedStyle* const parentStyle = aParentItem.mComputedStyle;
10648 nsIContent* const parentContent = aParentItem.mContent;
10649
10650 if (!aItemIsWithinSVGText) {
10651 if (parentStyle->StyleDisplay()->IsListItem()) {
10652 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10653 *parentStyle, PseudoStyleType::Marker,
10654 aParentItem.mChildItems);
10655 }
10656 // Probe for generated content before
10657 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10658 *parentStyle, PseudoStyleType::Before,
10659 aParentItem.mChildItems);
10660 }
10661
10662 ItemFlags flags;
10663 if (aItemIsWithinSVGText) {
10664 flags += ItemFlag::IsWithinSVGText;
10665 }
10666 if (aItemAllowsTextPathChild &&
10667 aParentItem.mContent->IsSVGElement(nsGkAtoms::a)) {
10668 flags += ItemFlag::AllowTextPathChild;
10669 }
10670
10671 FlattenedChildIterator iter(parentContent);
10672 for (nsIContent* content = iter.GetNextChild(); content;
10673 content = iter.GetNextChild()) {
10674 AddFrameConstructionItems(aState, content, iter.ShadowDOMInvolved(),
10675 *parentStyle, InsertionPoint(),
10676 aParentItem.mChildItems, flags);
10677 }
10678
10679 if (!aItemIsWithinSVGText) {
10680 // Probe for generated content after
10681 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10682 *parentStyle, PseudoStyleType::After,
10683 aParentItem.mChildItems);
10684 }
10685
10686 aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
10687}
10688
10689// return whether it's ok to append (in the AppendFrames sense) to
10690// aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10691// be an ib-split inline.
10692static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
10693 nsIFrame* aNextSibling) {
10694 MOZ_ASSERT(IsInlineFrame(aParentFrame), "Must have an inline parent here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsInlineFrame(aParentFrame))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsInlineFrame(aParentFrame))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsInlineFrame(aParentFrame)"
" (" "Must have an inline parent here" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInlineFrame(aParentFrame)"
") (" "Must have an inline parent here" ")"); do { MOZ_CrashSequence
(__null, 10694); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10695
10696 do {
10697 NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame),do { if (!(IsFramePartOfIBSplit(aParentFrame))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "How is this not part of an ib-split?", "IsFramePartOfIBSplit(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10698);
MOZ_PretendNoReturn(); } } while (0)
10698 "How is this not part of an ib-split?")do { if (!(IsFramePartOfIBSplit(aParentFrame))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "How is this not part of an ib-split?", "IsFramePartOfIBSplit(aParentFrame)"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 10698);
MOZ_PretendNoReturn(); } } while (0)
;
10699 if (aNextSibling || aParentFrame->GetNextContinuation() ||
10700 GetIBSplitSibling(aParentFrame)) {
10701 return false;
10702 }
10703
10704 aNextSibling = aParentFrame->GetNextSibling();
10705 aParentFrame = aParentFrame->GetParent();
10706 } while (IsInlineFrame(aParentFrame));
10707
10708 return true;
10709}
10710
10711bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame) {
10712#define TRACE(reason) \
10713 PROFILER_MARKER("WipeInsertionParent: " reason, LAYOUT, {}, Tracing, \do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("WipeInsertionParent: " reason, ::geckoprofiler::category::LAYOUT
, {}, ::geckoprofiler::markers::Tracing{}, "Layout"); } } while
(false); } while (false)
10714 "Layout")do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("WipeInsertionParent: " reason, ::geckoprofiler::category::LAYOUT
, {}, ::geckoprofiler::markers::Tracing{}, "Layout"); } } while
(false); } while (false)
;
10715
10716 const LayoutFrameType frameType = aFrame->Type();
10717
10718 if (aFrame->PresContext()->IsPaginated()) {
10719 if (auto* table = GetNearestFragmentedTable(aFrame)) {
10720 TRACE("Paginated fragmented table");
10721 RecreateFramesForContent(table->GetContent(), InsertionKind::Async);
10722 return true;
10723 }
10724 }
10725
10726 // FIXME(emilio): This looks terribly inefficient if you insert elements deep
10727 // in a MathML subtree.
10728 if (aFrame->IsMathMLFrame()) {
10729 TRACE("MathML");
10730 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10731 return true;
10732 }
10733
10734 // A ruby-related frame that's getting new children.
10735 // The situation for ruby is complex, especially when interacting with
10736 // spaces. It contains these two special cases apart from tables:
10737 // 1) There are effectively three types of white spaces in ruby frames
10738 // we handle differently: leading/tailing/inter-level space,
10739 // inter-base/inter-annotation space, and inter-segment space.
10740 // These three types of spaces can be converted to each other when
10741 // their sibling changes.
10742 // 2) The first effective child of a ruby frame must always be a ruby
10743 // base container. It should be created or destroyed accordingly.
10744 if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
10745 RubyUtils::IsRubyContainerBox(frameType)) {
10746 // We want to optimize it better, and avoid reframing as much as
10747 // possible. But given the cases above, and the fact that a ruby
10748 // usually won't be very large, it should be fine to reframe it.
10749 TRACE("Ruby");
10750 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10751 return true;
10752 }
10753
10754 // Reframe the multi-column container whenever elements insert/append
10755 // into it because we need to reconstruct column-span split.
10756 if (aFrame->IsColumnSetWrapperFrame()) {
10757 TRACE("Multi-column");
10758 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10759 return true;
10760 }
10761
10762 return false;
10763
10764#undef TRACE
10765}
10766
10767bool nsCSSFrameConstructor::WipeContainingBlock(
10768 nsFrameConstructorState& aState, nsIFrame* aContainingBlock,
10769 nsIFrame* aFrame, FrameConstructionItemList& aItems, bool aIsAppend,
10770 nsIFrame* aPrevSibling) {
10771#define TRACE(reason) \
10772 PROFILER_MARKER("WipeContainingBlock: " reason, LAYOUT, {}, Tracing, \do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("WipeContainingBlock: " reason, ::geckoprofiler::category::LAYOUT
, {}, ::geckoprofiler::markers::Tracing{}, "Layout"); } } while
(false); } while (false)
10773 "Layout")do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("WipeContainingBlock: " reason, ::geckoprofiler::category::LAYOUT
, {}, ::geckoprofiler::markers::Tracing{}, "Layout"); } } while
(false); } while (false)
;
10774
10775 if (aItems.IsEmpty()) {
10776 return false;
10777 }
10778
10779 // Before we go and append the frames, we must check for several
10780 // special situations.
10781
10782 if (aFrame->GetContent() == mDocument->GetRootElement()) {
10783 // Situation #1 is when we insert content that becomes the canonical body
10784 // element, and its used WritingMode is different from the root element's
10785 // used WritingMode.
10786 // We need to reframe the root element so that the root element's frames has
10787 // the correct writing-mode propagated from body element. (See
10788 // nsCSSFrameConstructor::ConstructDocElementFrame.)
10789 //
10790 // Bug 1594297: When inserting a new <body>, we may need to reframe the old
10791 // <body> which has a "overflow" value other than simple "visible". But it's
10792 // tricky, see bug 1593752.
10793 nsIContent* bodyElement = mDocument->GetBodyElement();
10794 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10795 const WritingMode bodyWM(iter.item().mComputedStyle);
10796 if (iter.item().mContent == bodyElement &&
10797 bodyWM != aFrame->GetWritingMode()) {
10798 TRACE("Root");
10799 RecreateFramesForContent(mDocument->GetRootElement(),
10800 InsertionKind::Async);
10801 return true;
10802 }
10803 }
10804 }
10805
10806 nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
10807
10808 // Situation #2 is a flex / grid container frame into which we're inserting
10809 // new inline non-replaced children, adjacent to an existing anonymous flex or
10810 // grid item.
10811 if (aFrame->IsFlexOrGridContainer()) {
10812 FCItemIterator iter(aItems);
10813
10814 // Check if we're adding to-be-wrapped content right *after* an existing
10815 // anonymous flex or grid item (which would need to absorb this content).
10816 const bool isLegacyWebKitBox = IsFlexContainerForLegacyWebKitBox(aFrame);
10817 if (aPrevSibling && IsAnonymousItem(aPrevSibling) &&
10818 iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10819 TRACE("Inserting inline after anon flex or grid item");
10820 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10821 return true;
10822 }
10823
10824 // Check if we're adding to-be-wrapped content right *before* an existing
10825 // anonymous flex or grid item (which would need to absorb this content).
10826 if (nextSibling && IsAnonymousItem(nextSibling)) {
10827 // Jump to the last entry in the list
10828 iter.SetToEnd();
10829 iter.Prev();
10830 if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10831 TRACE("Inserting inline before anon flex or grid item");
10832 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10833 return true;
10834 }
10835 }
10836 }
10837
10838 // Situation #3 is an anonymous flex or grid item that's getting new children
10839 // who don't want to be wrapped.
10840 if (IsAnonymousItem(aFrame)) {
10841 AssertAnonymousFlexOrGridItemParent(aFrame);
10842
10843 // We need to push a null float containing block to be sure that
10844 // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
10845 // inserted content. (In particular, this is necessary in order for
10846 // its "GetGeometricParent" call to return the correct result.)
10847 // We're not honoring floats on this content because it has the
10848 // _flex/grid container_ as its parent in the content tree.
10849 nsFrameConstructorSaveState floatSaveState;
10850 aState.PushFloatContainingBlock(nullptr, floatSaveState);
10851
10852 FCItemIterator iter(aItems);
10853 // Skip over things that _do_ need an anonymous flex item, because
10854 // they're perfectly happy to go here -- they won't cause a reframe.
10855 nsIFrame* containerFrame = aFrame->GetParent();
10856 const bool isLegacyWebKitBox =
10857 IsFlexContainerForLegacyWebKitBox(containerFrame);
10858 if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10859 // We hit something that _doesn't_ need an anonymous flex item!
10860 // Rebuild the flex container to bust it out.
10861 TRACE("Inserting non-inlines inside anon flex or grid item");
10862 RecreateFramesForContent(containerFrame->GetContent(),
10863 InsertionKind::Async);
10864 return true;
10865 }
10866
10867 // If we get here, then everything in |aItems| needs to be wrapped in
10868 // an anonymous flex or grid item. That's where it's already going - good!
10869 }
10870
10871 // Situation #4 is a case when table pseudo-frames don't work out right
10872 ParentType parentType = GetParentType(aFrame);
10873 // If all the kids want a parent of the type that aFrame is, then we're all
10874 // set to go. Indeed, there won't be any table pseudo-frames created between
10875 // aFrame and the kids, so those won't need to be merged with any table
10876 // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10877 // table pseudo-frame, then all the kids in this list would have wanted a
10878 // frame of that type wrapping them anyway, so putting them inside it is ok.
10879 if (!aItems.AllWantParentType(parentType)) {
10880 // Don't give up yet. If parentType is not eTypeBlock and the parent is
10881 // not a generated content frame, then try filtering whitespace out of the
10882 // list.
10883 if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
10884 // For leading whitespace followed by a kid that wants our parent type,
10885 // there are four cases:
10886 // 1) We have a previous sibling which is not a table pseudo. That means
10887 // that previous sibling wanted a (non-block) parent of the type we're
10888 // looking at. Then the whitespace comes between two table-internal
10889 // elements, so should be collapsed out.
10890 // 2) We have a previous sibling which is a table pseudo. It might have
10891 // kids who want this whitespace, so we need to reframe.
10892 // 3) We have no previous sibling and our parent frame is not a table
10893 // pseudo. That means that we'll be at the beginning of our actual
10894 // non-block-type parent, and the whitespace is OK to collapse out.
10895 // If something is ever inserted before us, it'll find our own parent
10896 // as its parent and if it's something that would care about the
10897 // whitespace it'll want a block parent, so it'll trigger a reframe at
10898 // that point.
10899 // 4) We have no previous sibling and our parent frame is a table pseudo.
10900 // Need to reframe.
10901 // All that is predicated on finding the correct previous sibling. We
10902 // might have to walk backwards along continuations from aFrame to do so.
10903 //
10904 // It's always OK to drop whitespace between any two items that want a
10905 // parent of type parentType.
10906 //
10907 // For trailing whitespace preceded by a kid that wants our parent type,
10908 // there are four cases:
10909 // 1) We have a next sibling which is not a table pseudo. That means
10910 // that next sibling wanted a (non-block) parent of the type we're
10911 // looking at. Then the whitespace comes between two table-internal
10912 // elements, so should be collapsed out.
10913 // 2) We have a next sibling which is a table pseudo. It might have
10914 // kids who want this whitespace, so we need to reframe.
10915 // 3) We have no next sibling and our parent frame is not a table
10916 // pseudo. That means that we'll be at the end of our actual
10917 // non-block-type parent, and the whitespace is OK to collapse out.
10918 // If something is ever inserted after us, it'll find our own parent
10919 // as its parent and if it's something that would care about the
10920 // whitespace it'll want a block parent, so it'll trigger a reframe at
10921 // that point.
10922 // 4) We have no next sibling and our parent frame is a table pseudo.
10923 // Need to reframe.
10924 // All that is predicated on finding the correct next sibling. We might
10925 // have to walk forward along continuations from aFrame to do so. That
10926 // said, in the case when nextSibling is null at this point and aIsAppend
10927 // is true, we know we're in case 3. Furthermore, in that case we don't
10928 // even have to worry about the table pseudo situation; we know our
10929 // parent is not a table pseudo there.
10930 FCItemIterator iter(aItems);
10931 FCItemIterator start(iter);
10932 do {
10933 if (iter.SkipItemsWantingParentType(parentType)) {
10934 break;
10935 }
10936
10937 // iter points to an item that wants a different parent. If it's not
10938 // whitespace, we're done; no more point scanning the list.
10939 if (!iter.item().IsWhitespace(aState)) {
10940 break;
10941 }
10942
10943 if (iter == start) {
10944 // Leading whitespace. How to handle this depends on our
10945 // previous sibling and aFrame. See the long comment above.
10946 nsIFrame* prevSibling = aPrevSibling;
10947 if (!prevSibling) {
10948 // Try to find one after all
10949 nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
10950 while (parentPrevCont) {
10951 prevSibling = parentPrevCont->PrincipalChildList().LastChild();
10952 if (prevSibling) {
10953 break;
10954 }
10955 parentPrevCont = parentPrevCont->GetPrevContinuation();
10956 }
10957 };
10958 if (prevSibling) {
10959 if (IsTablePseudo(prevSibling)) {
10960 // need to reframe
10961 break;
10962 }
10963 } else if (IsTablePseudo(aFrame)) {
10964 // need to reframe
10965 break;
10966 }
10967 }
10968
10969 FCItemIterator spaceEndIter(iter);
10970 // Advance spaceEndIter past any whitespace
10971 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
10972
10973 bool okToDrop;
10974 if (trailingSpaces) {
10975 // Trailing whitespace. How to handle this depeds on aIsAppend, our
10976 // next sibling and aFrame. See the long comment above.
10977 okToDrop = aIsAppend && !nextSibling;
10978 if (!okToDrop) {
10979 if (!nextSibling) {
10980 // Try to find one after all
10981 nsIFrame* parentNextCont = aFrame->GetNextContinuation();
10982 while (parentNextCont) {
10983 nextSibling = parentNextCont->PrincipalChildList().FirstChild();
10984 if (nextSibling) {
10985 break;
10986 }
10987 parentNextCont = parentNextCont->GetNextContinuation();
10988 }
10989 }
10990
10991 okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
10992 (!nextSibling && !IsTablePseudo(aFrame));
10993 } else {
10994 NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?")do { if (!(!IsTablePseudo(aFrame))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "!IsTablePseudo(aFrame)", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 10994); MOZ_PretendNoReturn(); } } while (0)
;
10995 }
10996 } else {
10997 okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
10998 }
10999
11000 if (okToDrop) {
11001 iter.DeleteItemsTo(this, spaceEndIter);
11002 } else {
11003 // We're done: we don't want to drop the whitespace, and it has the
11004 // wrong parent type.
11005 break;
11006 }
11007
11008 // Now loop, since |iter| points to item right after the whitespace we
11009 // removed.
11010 } while (!iter.IsDone());
11011 }
11012
11013 // We might be able to figure out some sort of optimizations here, but they
11014 // would have to depend on having a correct aPrevSibling and a correct next
11015 // sibling. For example, we can probably avoid reframing if none of
11016 // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11017 // doesn't seem worth it to worry about that for now, especially since we
11018 // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11019 // this method.
11020
11021 // aItems might have changed, so recheck the parent type thing. In fact,
11022 // it might be empty, so recheck that too.
11023 if (aItems.IsEmpty()) {
11024 return false;
11025 }
11026
11027 // If aFrame is empty, the insertion process will be able to take care of
11028 // creating any needed pseudo-parents.
11029 if (!aItems.AllWantParentType(parentType) &&
11030 !SafeToInsertPseudoNeedingChildren(aFrame)) {
11031 // Reframing aFrame->GetContent() is good enough, since the content of
11032 // table pseudo-frames is the ancestor content.
11033 TRACE("Pseudo-frames going wrong");
11034 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11035 return true;
11036 }
11037 }
11038
11039 // Situation #5 is a frame in multicol subtree that's getting new children.
11040 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
11041 bool anyColumnSpanItems = false;
11042 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11043 if (iter.item().mComputedStyle->StyleColumn()->IsColumnSpanStyle()) {
11044 anyColumnSpanItems = true;
11045 break;
11046 }
11047 }
11048
11049 bool needsReframe =
11050 // 1. Insert / append any column-span children.
11051 anyColumnSpanItems ||
11052 // 2. GetInsertionPrevSibling() modifies insertion parent. If the prev
11053 // sibling is a column-span, aFrame ends up being the
11054 // column-span-wrapper.
11055 aFrame->Style()->GetPseudoType() ==
11056 PseudoStyleType::MozColumnSpanWrapper ||
11057 // 3. Append into {ib} split container. There might be room for
11058 // optimization, but let's reframe for correctness...
11059 IsFramePartOfIBSplit(aFrame);
11060
11061 if (needsReframe) {
11062 TRACE("Multi-column");
11063 RecreateFramesForContent(
11064 GetMultiColumnContainingBlockFor(aFrame)->GetContent(),
11065 InsertionKind::Async);
11066 return true;
11067 }
11068
11069 // If we get here, then we need further check for {ib} split to decide
11070 // whether to reframe. For example, appending a block into an empty inline
11071 // that is not part of an {ib} split, but should become an {ib} split.
11072 }
11073
11074 // A <fieldset> may need to pick up a new rendered legend from aItems.
11075 // We currently can't handle this case without recreating frames for
11076 // the fieldset.
11077 // XXXmats we should be able to optimize this when the fieldset doesn't
11078 // currently have a rendered legend. ContentRangeInserted needs to be fixed
11079 // to use the inner frame as the content insertion frame in that case.
11080 if (const auto* fieldset = GetFieldSetFrameFor(aFrame)) {
11081 // Check if any item is eligible to be a rendered legend.
11082 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11083 const auto& item = iter.item();
11084 if (!item.mContent->IsHTMLElement(nsGkAtoms::legend)) {
11085 continue;
11086 }
11087 const auto* display = item.mComputedStyle->StyleDisplay();
11088 if (display->IsFloatingStyle() ||
11089 display->IsAbsolutelyPositionedStyle()) {
11090 continue;
11091 }
11092 TRACE("Fieldset with rendered legend");
11093 RecreateFramesForContent(fieldset->GetContent(), InsertionKind::Async);
11094 return true;
11095 }
11096 }
11097
11098 // Now we have several cases involving {ib} splits. Put them all in a
11099 // do/while with breaks to take us to the "go and reconstruct" code.
11100 do {
11101 if (IsInlineFrame(aFrame)) {
11102 if (aItems.AreAllItemsInline()) {
11103 // We can just put the kids in.
11104 return false;
11105 }
11106
11107 if (!IsFramePartOfIBSplit(aFrame)) {
11108 // Need to go ahead and reconstruct.
11109 break;
11110 }
11111
11112 // Now we're adding kids including some blocks to an inline part of an
11113 // {ib} split. If we plan to call AppendFrames, and don't have a next
11114 // sibling for the new frames, and our parent is the last continuation of
11115 // the last part of the {ib} split, and the same is true of all our
11116 // ancestor inlines (they have no following continuations and they're the
11117 // last part of their {ib} splits and we'd be adding to the end for all
11118 // of them), then AppendFrames will handle things for us. Bail out in
11119 // that case.
11120 if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
11121 return false;
11122 }
11123
11124 // Need to reconstruct.
11125 break;
11126 }
11127
11128 // Now we know we have a block parent. If it's not part of an
11129 // ib-split, we're all set.
11130 if (!IsFramePartOfIBSplit(aFrame)) {
11131 return false;
11132 }
11133
11134 // We're adding some kids to a block part of an {ib} split. If all the
11135 // kids are blocks, we don't need to reconstruct.
11136 if (aItems.AreAllItemsBlock()) {
11137 return false;
11138 }
11139
11140 // We might have some inline kids for this block. Just fall out of the
11141 // loop and reconstruct.
11142 } while (false);
11143
11144 // If we don't have a containing block, start with aFrame and look for one.
11145 if (!aContainingBlock) {
11146 aContainingBlock = aFrame;
11147 }
11148
11149 // To find the right block to reframe, just walk up the tree until we find a
11150 // frame that is:
11151 // 1) Not part of an IB split
11152 // 2) Not a pseudo-frame
11153 // 3) Not an inline frame
11154 // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
11155 // enforces that the root is display:none, display:table, or display:block.
11156 // Note that walking up "too far" is OK in terms of correctness, even if it
11157 // might be a little inefficient. This is why we walk out of all
11158 // pseudo-frames -- telling which ones are or are not OK to walk out of is
11159 // too hard (and I suspect that we do in fact need to walk out of all of
11160 // them).
11161 while (IsFramePartOfIBSplit(aContainingBlock) ||
11162 aContainingBlock->IsInlineOutside() ||
11163 aContainingBlock->Style()->IsPseudoOrAnonBox()) {
11164 aContainingBlock = aContainingBlock->GetParent();
11165 NS_ASSERTION(aContainingBlock,do { if (!(aContainingBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Must have non-inline, non-ib-split, non-pseudo frame as " "root (or child of root, for a table root)!"
, "aContainingBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11167); MOZ_PretendNoReturn(); } } while (0)
11166 "Must have non-inline, non-ib-split, non-pseudo frame as "do { if (!(aContainingBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Must have non-inline, non-ib-split, non-pseudo frame as " "root (or child of root, for a table root)!"
, "aContainingBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11167); MOZ_PretendNoReturn(); } } while (0)
11167 "root (or child of root, for a table root)!")do { if (!(aContainingBlock)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Must have non-inline, non-ib-split, non-pseudo frame as " "root (or child of root, for a table root)!"
, "aContainingBlock", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11167); MOZ_PretendNoReturn(); } } while (0)
;
11168 }
11169
11170 // Tell parent of the containing block to reformulate the
11171 // entire block. This is painful and definitely not optimal
11172 // but it will *always* get the right answer.
11173
11174 nsIContent* blockContent = aContainingBlock->GetContent();
11175 TRACE("IB splits");
11176 RecreateFramesForContent(blockContent, InsertionKind::Async);
11177 return true;
11178#undef TRACE
11179}
11180
11181void nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) {
11182 // XXXbz how exactly would we get here while isReflowing anyway? Should this
11183 // whole test be ifdef DEBUG?
11184 if (mPresShell->IsReflowLocked()) {
11185 // don't ReframeContainingBlock, this will result in a crash
11186 // if we remove a tree that's in reflow - see bug 121368 for testcase
11187 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11189); MOZ_PretendNoReturn(); } while (0)
11188 "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11189); MOZ_PretendNoReturn(); } while (0)
11189 "Reflow!!!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11189); MOZ_PretendNoReturn(); } while (0)
;
11190 return;
11191 }
11192
11193 // Get the first "normal" ancestor of the target frame.
11194 nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11195 if (containingBlock) {
11196 // From here we look for the containing block in case the target
11197 // frame is already a block (which can happen when an inline frame
11198 // wraps some of its content in an anonymous block; see
11199 // ConstructInline)
11200
11201 // NOTE: We used to get the FloatContainingBlock here, but it was often
11202 // wrong. GetIBContainingBlock works much better and provides the correct
11203 // container in all cases so GetFloatContainingBlock(aFrame) has been
11204 // removed
11205
11206 // And get the containingBlock's content
11207 if (nsIContent* blockContent = containingBlock->GetContent()) {
11208#ifdef DEBUG1
11209 if (gNoisyContentUpdates) {
11210 printf(" ==> blockContent=%p\n", blockContent);
11211 }
11212#endif
11213 RecreateFramesForContent(blockContent, InsertionKind::Async);
11214 return;
11215 }
11216 }
11217
11218 // If we get here, we're screwed!
11219 RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11220 InsertionKind::Async);
11221}
11222
11223//////////////////////////////////////////////////////////
11224// nsCSSFrameConstructor::FrameConstructionItem methods //
11225//////////////////////////////////////////////////////////
11226bool nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace(
11227 nsFrameConstructorState& aState) const {
11228 MOZ_ASSERT(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
" (" "How did that happen?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11229); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
11229 "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
" (" "How did that happen?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11229); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11230 if (!mIsText) {
11231 return false;
11232 }
11233 // Set content whitespace flags, but not for generated content, where we
11234 // never expect to see these.
11235 if (!(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT)) {
11236 mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11237 NS_REFRAME_IF_WHITESPACE);
11238 }
11239 return mContent->TextIsOnlyWhitespace();
11240}
11241
11242//////////////////////////////////////////////////////////////
11243// nsCSSFrameConstructor::FrameConstructionItemList methods //
11244//////////////////////////////////////////////////////////////
11245void nsCSSFrameConstructor::FrameConstructionItemList::AdjustCountsForItem(
11246 FrameConstructionItem* aItem, int32_t aDelta) {
11247 MOZ_ASSERT(aDelta == 1 || aDelta == -1, "Unexpected delta")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDelta == 1 || aDelta == -1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDelta == 1 || aDelta == -1)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDelta == 1 || aDelta == -1"
" (" "Unexpected delta" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11247); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDelta == 1 || aDelta == -1"
") (" "Unexpected delta" ")"); do { MOZ_CrashSequence(__null
, 11247); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11248 mItemCount += aDelta;
11249 if (aItem->mIsAllInline) {
11250 mInlineCount += aDelta;
11251 }
11252 if (aItem->mIsBlock) {
11253 mBlockCount += aDelta;
11254 }
11255 mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
11256}
11257
11258////////////////////////////////////////////////////////////////////////
11259// nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11260////////////////////////////////////////////////////////////////////////
11261inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11262 SkipItemsWantingParentType(ParentType aParentType) {
11263 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11263
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11263); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11264 while (item().DesiredParentType() == aParentType) {
11265 Next();
11266 if (IsDone()) {
11267 return true;
11268 }
11269 }
11270 return false;
11271}
11272
11273inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11274 SkipItemsNotWantingParentType(ParentType aParentType) {
11275 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11275
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11275); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11276 while (item().DesiredParentType() != aParentType) {
11277 Next();
11278 if (IsDone()) {
11279 return true;
11280 }
11281 }
11282 return false;
11283}
11284
11285// Note: we implement -webkit-{inline-}box using nsFlexContainerFrame, but we
11286// use different rules for what gets wrapped in an anonymous flex item.
11287bool nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem(
11288 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11289 if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) {
11290 // This will be an inline non-replaced box.
11291 return true;
11292 }
11293
11294 if (aIsLegacyWebKitBox) {
11295 if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
11296 // In an emulated legacy box, all inline-level content gets wrapped in an
11297 // anonymous flex item.
11298 return true;
11299 }
11300 if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
11301 aState.GetGeometricParent(*mComputedStyle->StyleDisplay(), nullptr)) {
11302 // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
11303 // placeholder which (because our container is an emulated legacy box)
11304 // we'll need to wrap in an anonymous flex item. So, we just treat
11305 // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
11306 // and then when we spawn the placeholder, it'll end up in the right
11307 // spot.
11308 return true;
11309 }
11310 }
11311
11312 return false;
11313}
11314
11315inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11316 SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState& aState,
11317 bool aIsLegacyWebKitBox) {
11318 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11318
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11318); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11319 while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox)) {
11320 Next();
11321 if (IsDone()) {
11322 return true;
11323 }
11324 }
11325 return false;
11326}
11327
11328inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11329 SkipItemsThatDontNeedAnonFlexOrGridItem(
11330 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11331 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11331
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11331); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11332 while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox))) {
11333 Next();
11334 if (IsDone()) {
11335 return true;
11336 }
11337 }
11338 return false;
11339}
11340
11341inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11342 SkipItemsNotWantingRubyParent() {
11343 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11343
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11343); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11344 while (!IsRubyParentType(item().DesiredParentType())) {
11345 Next();
11346 if (IsDone()) {
11347 return true;
11348 }
11349 }
11350 return false;
11351}
11352
11353inline bool
11354nsCSSFrameConstructor::FrameConstructionItemList::Iterator::SkipWhitespace(
11355 nsFrameConstructorState& aState) {
11356 MOZ_ASSERT(!IsDone(), "Shouldn't be done yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "Shouldn't be done yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11356
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11356); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11357 MOZ_ASSERT(item().IsWhitespace(aState), "Not pointing to whitespace?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(item().IsWhitespace(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(item().IsWhitespace(aState))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("item().IsWhitespace(aState)"
" (" "Not pointing to whitespace?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item().IsWhitespace(aState)"
") (" "Not pointing to whitespace?" ")"); do { MOZ_CrashSequence
(__null, 11357); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11358 do {
11359 Next();
11360 if (IsDone()) {
11361 return true;
11362 }
11363 } while (item().IsWhitespace(aState));
11364
11365 return false;
11366}
11367
11368void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11369 AppendItemToList(FrameConstructionItemList& aTargetList) {
11370 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11370); MOZ_PretendNoReturn(); } } while (0)
;
11371 MOZ_ASSERT(!IsDone(), "should not be done")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDone()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsDone()" " (" "should not be done"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11371
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "should not be done"
")"); do { MOZ_CrashSequence(__null, 11371); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11372
11373 FrameConstructionItem* item = mCurrent;
11374 Next();
11375 item->remove();
11376 aTargetList.mItems.insertBack(item);
11377
11378 mList.AdjustCountsForItem(item, -1);
11379 aTargetList.AdjustCountsForItem(item, 1);
11380}
11381
11382void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11383 AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
11384 FrameConstructionItemList& aTargetList) {
11385 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11385); MOZ_PretendNoReturn(); } } while (0)
;
11386 MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&mList == &aEnd.mList)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(&mList == &aEnd.mList
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"&mList == &aEnd.mList" " (" "End iterator for some other list?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11386
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11386); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11387
11388 // We can't just move our guts to the other list if it already has
11389 // some information or if we're not moving our entire list.
11390 if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
11391 do {
11392 AppendItemToList(aTargetList);
11393 } while (*this != aEnd);
11394 return;
11395 }
11396
11397 // Move our entire list of items into the empty target list.
11398 aTargetList.mItems = std::move(mList.mItems);
11399
11400 // Copy over the various counters
11401 aTargetList.mInlineCount = mList.mInlineCount;
11402 aTargetList.mBlockCount = mList.mBlockCount;
11403 aTargetList.mItemCount = mList.mItemCount;
11404 memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
11405 sizeof(aTargetList.mDesiredParentCounts));
11406
11407 // reset mList
11408 mList.Reset(aFCtor);
11409
11410 // Point ourselves to aEnd, as advertised
11411 SetToEnd();
11412 MOZ_ASSERT(*this == aEnd, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*this == aEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*this == aEnd))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*this == aEnd" " ("
"How did that happen?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11412); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this == aEnd"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11412); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11413}
11414
11415void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::InsertItem(
11416 FrameConstructionItem* aItem) {
11417 if (IsDone()) {
11418 mList.mItems.insertBack(aItem);
11419 } else {
11420 // Just insert the item before us. There's no magic here.
11421 mCurrent->setPrevious(aItem);
11422 }
11423 mList.AdjustCountsForItem(aItem, 1);
11424
11425 MOZ_ASSERT(aItem->getNext() == mCurrent, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aItem->getNext() == mCurrent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aItem->getNext() == mCurrent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aItem->getNext() == mCurrent" " (" "How did that happen?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11425
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem->getNext() == mCurrent"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11425); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11426}
11427
11428void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::DeleteItemsTo(
11429 nsCSSFrameConstructor* aFCtor, const Iterator& aEnd) {
11430 MOZ_ASSERT(&mList == &aEnd.mList, "End iterator for some other list?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(&mList == &aEnd.mList)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(&mList == &aEnd.mList
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"&mList == &aEnd.mList" " (" "End iterator for some other list?"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 11430
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11430); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11431 MOZ_ASSERT(*this != aEnd, "Shouldn't be at aEnd yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*this != aEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*this != aEnd))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*this != aEnd" " ("
"Shouldn't be at aEnd yet" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11431); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this != aEnd"
") (" "Shouldn't be at aEnd yet" ")"); do { MOZ_CrashSequence
(__null, 11431); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11432
11433 do {
11434 NS_ASSERTION(!IsDone(), "Ran off end of list?")do { if (!(!IsDone())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Ran off end of list?"
, "!IsDone()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11434); MOZ_PretendNoReturn(); } } while (0)
;
11435 FrameConstructionItem* item = mCurrent;
11436 Next();
11437 item->remove();
11438 mList.AdjustCountsForItem(item, -1);
11439 item->Delete(aFCtor);
11440 } while (*this != aEnd);
11441}
11442
11443void nsCSSFrameConstructor::QuotesDirty() {
11444 mQuotesDirty = true;
11445 mPresShell->SetNeedLayoutFlush();
11446}
11447
11448void nsCSSFrameConstructor::CountersDirty() {
11449 mCountersDirty = true;
11450 mPresShell->SetNeedLayoutFlush();
11451}
11452
11453void* nsCSSFrameConstructor::AllocateFCItem() {
11454 void* item;
11455 if (mFirstFreeFCItem) {
11456 item = mFirstFreeFCItem;
11457 mFirstFreeFCItem = mFirstFreeFCItem->mNext;
11458 } else {
11459 item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
11460 }
11461 ++mFCItemsInUse;
11462 return item;
11463}
11464
11465void nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem) {
11466 MOZ_ASSERT(mFCItemsInUse != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFCItemsInUse != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFCItemsInUse != 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mFCItemsInUse != 0"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 11466);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFCItemsInUse != 0"
")"); do { MOZ_CrashSequence(__null, 11466); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11467 if (--mFCItemsInUse == 0) {
11468 // The arena is now unused - clear it but retain one chunk.
11469 mFirstFreeFCItem = nullptr;
11470 mFCItemPool.Clear();
11471 } else {
11472 // Prepend it to the list of free items.
11473 FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
11474 item->mNext = mFirstFreeFCItem;
11475 mFirstFreeFCItem = item;
11476 }
11477}
11478
11479void nsCSSFrameConstructor::AddSizeOfIncludingThis(
11480 nsWindowSizes& aSizes) const {
11481 if (nsIFrame* rootFrame = GetRootFrame()) {
11482 rootFrame->AddSizeOfExcludingThisForTree(aSizes);
11483 if (RetainedDisplayListBuilder* builder =
11484 rootFrame->GetProperty(RetainedDisplayListBuilder::Cached())) {
11485 builder->AddSizeOfIncludingThis(aSizes);
11486 }
11487 }
11488
11489 // This must be done after measuring from the frame tree, since frame
11490 // manager will measure sizes of staled computed values and style
11491 // structs, which only make sense after we know what are being used.
11492 nsFrameManager::AddSizeOfIncludingThis(aSizes);
11493
11494 // Measurement of the following members may be added later if DMD finds it
11495 // is worthwhile:
11496 // - mFCItemPool
11497 // - mContainStyleScopeManager
11498}