Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/base/./../../../layout/base/nsCSSFrameConstructor.cpp
Warning:line 6944, 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-10-17-231001-351276-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/intl/LocaleService.h"
55#include "nsAtom.h"
56#include "nsAutoLayoutPhase.h"
57#include "nsBlockFrame.h"
58#include "nsCRT.h"
59#include "nsCanvasFrame.h"
60#include "nsCheckboxRadioFrame.h"
61#include "nsComboboxControlFrame.h"
62#include "nsContainerFrame.h"
63#include "nsContentUtils.h"
64#include "nsError.h"
65#include "nsFieldSetFrame.h"
66#include "nsFirstLetterFrame.h"
67#include "nsFlexContainerFrame.h"
68#include "nsGkAtoms.h"
69#include "nsGridContainerFrame.h"
70#include "nsHTMLParts.h"
71#include "nsIAnonymousContentCreator.h"
72#include "nsIFormControl.h"
73#include "nsIFrameInlines.h"
74#include "nsIObjectLoadingContent.h"
75#include "nsIPopupContainer.h"
76#include "nsIScriptError.h"
77#include "nsImageFrame.h"
78#include "nsInlineFrame.h"
79#include "nsLayoutUtils.h"
80#include "nsListControlFrame.h"
81#include "nsMathMLParts.h"
82#include "nsNameSpaceManager.h"
83#include "nsPageContentFrame.h"
84#include "nsPageFrame.h"
85#include "nsPageSequenceFrame.h"
86#include "nsPlaceholderFrame.h"
87#include "nsPresContext.h"
88#include "nsRefreshDriver.h"
89#include "nsRubyBaseContainerFrame.h"
90#include "nsRubyBaseFrame.h"
91#include "nsRubyFrame.h"
92#include "nsRubyTextContainerFrame.h"
93#include "nsRubyTextFrame.h"
94#include "nsStyleConsts.h"
95#include "nsStyleStructInlines.h"
96#include "nsTArray.h"
97#include "nsTableCellFrame.h"
98#include "nsTableColFrame.h"
99#include "nsTableFrame.h"
100#include "nsTableRowFrame.h"
101#include "nsTableRowGroupFrame.h"
102#include "nsTableWrapperFrame.h"
103#include "nsTextControlFrame.h"
104#include "nsTextNode.h"
105#include "nsTransitionManager.h"
106#include "nsUnicharUtils.h"
107#include "nsXULElement.h"
108
109#ifdef XP_MACOSX
110# include "nsIDocShell.h"
111#endif
112
113#ifdef ACCESSIBILITY1
114# include "nsAccessibilityService.h"
115#endif
116
117#undef NOISY_FIRST_LETTER
118
119using namespace mozilla;
120using namespace mozilla::dom;
121
122nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell, ComputedStyle* aStyle);
123
124nsIFrame* NS_NewHTMLVideoFrame(PresShell* aPresShell, ComputedStyle* aStyle);
125nsIFrame* NS_NewHTMLAudioFrame(PresShell* aPresShell, ComputedStyle* aStyle);
126
127nsContainerFrame* NS_NewSVGOuterSVGFrame(PresShell* aPresShell,
128 ComputedStyle* aStyle);
129nsContainerFrame* NS_NewSVGOuterSVGAnonChildFrame(PresShell* aPresShell,
130 ComputedStyle* aStyle);
131nsIFrame* NS_NewSVGInnerSVGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
132nsIFrame* NS_NewSVGGeometryFrame(PresShell* aPresShell, ComputedStyle* aStyle);
133nsIFrame* NS_NewSVGGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
134nsContainerFrame* NS_NewSVGForeignObjectFrame(PresShell* aPresShell,
135 ComputedStyle* aStyle);
136nsIFrame* NS_NewSVGAFrame(PresShell* aPresShell, ComputedStyle* aStyle);
137nsIFrame* NS_NewSVGSwitchFrame(PresShell* aPresShell, ComputedStyle* aStyle);
138nsIFrame* NS_NewSVGSymbolFrame(PresShell* aPresShell, ComputedStyle* aStyle);
139nsIFrame* NS_NewSVGTextFrame(PresShell* aPresShell, ComputedStyle* aStyle);
140nsIFrame* NS_NewSVGContainerFrame(PresShell* aPresShell, ComputedStyle* aStyle);
141nsIFrame* NS_NewSVGUseFrame(PresShell* aPresShell, ComputedStyle* aStyle);
142nsIFrame* NS_NewSVGViewFrame(PresShell* aPresShell, ComputedStyle* aStyle);
143extern nsIFrame* NS_NewSVGLinearGradientFrame(PresShell* aPresShell,
144 ComputedStyle* aStyle);
145extern nsIFrame* NS_NewSVGRadialGradientFrame(PresShell* aPresShell,
146 ComputedStyle* aStyle);
147extern nsIFrame* NS_NewSVGStopFrame(PresShell* aPresShell,
148 ComputedStyle* aStyle);
149nsContainerFrame* NS_NewSVGMarkerFrame(PresShell* aPresShell,
150 ComputedStyle* aStyle);
151nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(PresShell* aPresShell,
152 ComputedStyle* aStyle);
153extern nsIFrame* NS_NewSVGImageFrame(PresShell* aPresShell,
154 ComputedStyle* aStyle);
155nsIFrame* NS_NewSVGClipPathFrame(PresShell* aPresShell, ComputedStyle* aStyle);
156nsIFrame* NS_NewSVGFilterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
157nsIFrame* NS_NewSVGPatternFrame(PresShell* aPresShell, ComputedStyle* aStyle);
158nsIFrame* NS_NewSVGMaskFrame(PresShell* aPresShell, ComputedStyle* aStyle);
159nsIFrame* NS_NewSVGFEContainerFrame(PresShell* aPresShell,
160 ComputedStyle* aStyle);
161nsIFrame* NS_NewSVGFELeafFrame(PresShell* aPresShell, ComputedStyle* aStyle);
162nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
163nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
164 ComputedStyle* aStyle);
165nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
166nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
167nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);
168nsIFrame* NS_NewInputButtonControlFrame(PresShell*, ComputedStyle*);
169
170#include "mozilla/dom/NodeInfo.h"
171#include "nsContentCreatorFunctions.h"
172#include "nsNodeInfoManager.h"
173#include "prenv.h"
174
175#ifdef DEBUG1
176// Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
177// more of the following flags (comma separated) for handy debug
178// output.
179static bool gNoisyContentUpdates = false;
180static bool gReallyNoisyContentUpdates = false;
181static bool gNoisyInlineConstruction = false;
182
183struct FrameCtorDebugFlags {
184 const char* name;
185 bool* on;
186};
187
188static FrameCtorDebugFlags gFrameCtorDebugFlags[] = {
189 {"content-updates", &gNoisyContentUpdates},
190 {"really-noisy-content-updates", &gReallyNoisyContentUpdates},
191 {"noisy-inline", &gNoisyInlineConstruction}};
192
193# define NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags)) (std::size(gFrameCtorDebugFlags))
194#endif
195
196//------------------------------------------------------------------
197
198nsIFrame* NS_NewLeafBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
199
200nsIFrame* NS_NewRangeFrame(PresShell* aPresShell, ComputedStyle* aStyle);
201
202nsIFrame* NS_NewTextBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
203
204nsIFrame* NS_NewSplitterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
205
206nsIFrame* NS_NewMenuPopupFrame(PresShell* aPresShell, ComputedStyle* aStyle);
207
208nsIFrame* NS_NewTreeBodyFrame(PresShell* aPresShell, ComputedStyle* aStyle);
209
210nsIFrame* NS_NewSliderFrame(PresShell* aPresShell, ComputedStyle* aStyle);
211
212nsIFrame* NS_NewScrollbarFrame(PresShell* aPresShell, ComputedStyle* aStyle);
213
214nsIFrame* NS_NewScrollbarButtonFrame(PresShell*, ComputedStyle*);
215nsIFrame* NS_NewSimpleXULLeafFrame(PresShell*, ComputedStyle*);
216
217nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
218nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
219nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
220nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
221nsIFrame* NS_NewImageFrameForViewTransition(PresShell*, ComputedStyle*);
222
223// Returns true if aFrame is an anonymous flex/grid item.
224static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
225 return aFrame->Style()->GetPseudoType() == PseudoStyleType::MozAnonymousItem;
226}
227
228// Returns true IFF the given nsIFrame is a nsFlexContainerFrame and represents
229// a -webkit-{inline-}box container.
230static inline bool IsFlexContainerForLegacyWebKitBox(const nsIFrame* aFrame) {
231 return aFrame->IsFlexContainerFrame() && aFrame->IsLegacyWebkitBox();
232}
233
234static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
235 const nsIFrame* aChild, const nsIFrame* aParent) {
236 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"
, 236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsAnonymousItem(aChild)"
") (" "expected an anonymous item child frame" ")"); do { MOZ_CrashSequence
(__null, 236); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
237 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", 237
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ") (" "expected a parent frame"
")"); do { MOZ_CrashSequence(__null, 237); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
238 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"
, 240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 240)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
239 "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"
, 240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 240)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
240 "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"
, 240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 240)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
241}
242
243static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
244 const nsIFrame* aChild) {
245 AssertAnonymousFlexOrGridItemParent(aChild, aChild->GetParent());
246}
247
248#define ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
\
249 [](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { \
250 return _func(aPs, aStyle); \
251 }
252
253/**
254 * True if aFrame is an actual inline frame in the sense of non-replaced
255 * display:inline CSS boxes. In other words, it can be affected by {ib}
256 * splitting and can contain first-letter frames. Basically, this is either an
257 * inline frame (positioned or otherwise) or an line frame (this last because
258 * it can contain first-letter and because inserting blocks in the middle of it
259 * needs to terminate it).
260 */
261static bool IsInlineFrame(const nsIFrame* aFrame) {
262 return aFrame->IsLineParticipant();
263}
264
265/**
266 * True for display: contents elements.
267 */
268static inline bool IsDisplayContents(const Element* aElement) {
269 return aElement->IsDisplayContents();
270}
271
272static inline bool IsDisplayContents(const nsIContent* aContent) {
273 return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
274}
275
276/**
277 * True if aFrame is an instance of an SVG frame class or is an inline/block
278 * frame being used for SVG text.
279 */
280static bool IsFrameForSVG(const nsIFrame* aFrame) {
281 return aFrame->IsSVGFrame() || aFrame->IsInSVGTextSubtree();
282}
283
284static bool IsLastContinuationForColumnContent(const nsIFrame* aFrame) {
285 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"
, 285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ")")
; do { MOZ_CrashSequence(__null, 285); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
286 return aFrame->Style()->GetPseudoType() ==
287 PseudoStyleType::MozColumnContent &&
288 !aFrame->GetNextContinuation();
289}
290
291/**
292 * Returns true iff aFrame explicitly prevents its descendants from floating
293 * (at least, down to the level of descendants which themselves are
294 * float-containing blocks -- those will manage the floating status of any
295 * lower-level descendents inside them, of course).
296 */
297static bool ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) {
298 return aFrame->IsFlexOrGridContainer() || aFrame->IsMathMLFrame();
299}
300
301// Return true if column-span descendants should be suppressed under aFrame's
302// subtree (until a multi-column container re-establishing a block formatting
303// context). Basically, this is testing whether aFrame establishes a new block
304// formatting context or not.
305static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
306 if (aFrame->Style()->GetPseudoType() == PseudoStyleType::MozColumnContent) {
307 // Never suppress column-span under ::-moz-column-content frames.
308 return false;
309 }
310
311 if (aFrame->IsInlineFrame()) {
312 // Allow inline frames to have column-span block children.
313 return false;
314 }
315
316 if (!aFrame->IsBlockFrameOrSubclass() ||
317 aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) ||
318 aFrame->IsFixedPosContainingBlock()) {
319 // Need to suppress column-span if we:
320 // - Are a different block formatting context,
321 // - Are an out-of-flow frame, OR
322 // - Establish a containing block for fixed-position descendants
323 //
324 // For example, the children of a column-span never need to be further
325 // processed even if there is a nested column-span child. Because a
326 // column-span always creates its own block formatting context, a nested
327 // column-span child won't be in the same block formatting context with the
328 // nearest multi-column ancestor. This is the same case as if the
329 // column-span is outside of a multi-column hierarchy.
330 return true;
331 }
332
333 return false;
334}
335
336// Reparent a frame into a wrapper frame that is a child of its old parent.
337static void ReparentFrame(RestyleManager* aRestyleManager,
338 nsContainerFrame* aNewParentFrame, nsIFrame* aFrame,
339 bool aForceStyleReparent) {
340 aFrame->SetParent(aNewParentFrame);
341 // We reparent frames for two reasons: to put them inside ::first-line, and to
342 // put them inside some wrapper anonymous boxes.
343 if (aForceStyleReparent) {
344 aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
345 }
346}
347
348static void ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
349 nsContainerFrame* aNewParentFrame,
350 const nsFrameList& aFrameList,
351 bool aForceStyleReparent) {
352 RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
353 for (nsIFrame* f : aFrameList) {
354 ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
355 }
356}
357
358//----------------------------------------------------------------------
359//
360// When inline frames get weird and have block frames in them, we
361// annotate them to help us respond to incremental content changes
362// more easily.
363
364static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) {
365 bool result = aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT);
366 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", 368
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 368); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
367 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", 368
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 368); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
368 "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", 368
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 368); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
369 return result;
370}
371
372static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) {
373 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", 373); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 373); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
374
375 // We only store the "ib-split sibling" annotation with the first
376 // frame in the continuation chain. Walk back to find that frame now.
377 return aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
378}
379
380static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) {
381 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", 381); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 381); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
382
383 // We only store the ib-split sibling annotation with the first
384 // frame in the continuation chain. Walk back to find that frame now.
385 return aFrame->FirstContinuation()->GetProperty(
386 nsIFrame::IBSplitPrevSibling());
387}
388
389static nsContainerFrame* GetLastIBSplitSibling(nsIFrame* aFrame) {
390 for (nsIFrame *frame = aFrame, *next;; frame = next) {
391 next = GetIBSplitSibling(frame);
392 if (!next) {
393 return static_cast<nsContainerFrame*>(frame);
394 }
395 }
396 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"
, 396); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unreachable code" ")"); do { MOZ_CrashSequence
(__null, 396); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
397 return nullptr;
398}
399
400static void SetFrameIsIBSplit(nsContainerFrame* aFrame,
401 nsContainerFrame* aIBSplitSibling) {
402 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", 402
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "bad args!"
")"); do { MOZ_CrashSequence(__null, 402); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
403
404 // We should be the only continuation
405 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"
, 406); MOZ_PretendNoReturn(); } } while (0)
406 "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"
, 406); MOZ_PretendNoReturn(); } } while (0)
;
407 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", 409); MOZ_PretendNoReturn
(); } } while (0)
408 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", 409); MOZ_PretendNoReturn
(); } } while (0)
409 "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", 409); MOZ_PretendNoReturn
(); } } while (0)
;
410
411 // Mark the frame as ib-split.
412 aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
413
414 if (aIBSplitSibling) {
415 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", 417); MOZ_PretendNoReturn
(); } } while (0)
416 "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", 417); MOZ_PretendNoReturn
(); } } while (0)
417 "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", 417); MOZ_PretendNoReturn
(); } } while (0)
;
418
419 // Store the ib-split sibling (if we were given one) with the
420 // first frame in the flow.
421 aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
422 aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
423 }
424}
425
426static nsIFrame* GetIBContainingBlockFor(nsIFrame* aFrame) {
427 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", 429
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 429); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
428 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", 429
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 429); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
429 "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", 429
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 429); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
430
431 // Get the first "normal" ancestor of the target frame.
432 nsIFrame* parentFrame;
433 do {
434 parentFrame = aFrame->GetParent();
435
436 if (!parentFrame) {
437 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"
, 437); MOZ_PretendNoReturn(); } while (0)
;
438 return aFrame;
439 }
440
441 // Note that we ignore non-ib-split frames which have a pseudo on their
442 // ComputedStyle -- they're not the frames we're looking for! In
443 // particular, they may be hiding a real parent that _is_ in an ib-split.
444 if (!IsFramePartOfIBSplit(parentFrame) &&
445 !parentFrame->Style()->IsPseudoOrAnonBox()) {
446 break;
447 }
448
449 aFrame = parentFrame;
450 } while (true);
451
452 // post-conditions
453 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"
, 455); MOZ_PretendNoReturn(); } } while (0)
454 "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"
, 455); MOZ_PretendNoReturn(); } } while (0)
455 "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"
, 455); MOZ_PretendNoReturn(); } } while (0)
;
456 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", 457); MOZ_PretendNoReturn
(); } } while (0)
457 "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", 457); MOZ_PretendNoReturn
(); } } while (0)
;
458
459 return parentFrame;
460}
461
462// Find the multicol containing block suitable for reframing.
463//
464// Note: this function may not return a ColumnSetWrapperFrame. For example, if
465// the multicol containing block has "overflow:scroll" style,
466// ScrollContainerFrame is returned because ColumnSetWrapperFrame is the
467// scrolled frame which has the -moz-scrolled-content pseudo style. We may walk
468// up "too far", but in terms of correctness of reframing, it's OK.
469static nsContainerFrame* GetMultiColumnContainingBlockFor(nsIFrame* aFrame) {
470 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", 471
); 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, 471); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
471 "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", 471
); 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, 471); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
472
473 nsContainerFrame* current = aFrame->GetParent();
474 while (current &&
475 (current->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
476 current->Style()->IsPseudoOrAnonBox())) {
477 current = current->GetParent();
478 }
479
480 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", 481
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 481); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
481 "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", 481
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 481); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
482
483 return current;
484}
485
486static bool InsertSeparatorBeforeAccessKey() {
487 static bool sInitialized = false;
488 static bool sValue = false;
489 if (!sInitialized) {
490 sInitialized = true;
491 sValue =
492 intl::LocaleService::GetInstance()->InsertSeparatorBeforeAccesskeys();
493 }
494 return sValue;
495}
496
497static bool AlwaysAppendAccessKey() {
498 static bool sInitialized = false;
499 static bool sValue = false;
500 if (!sInitialized) {
501 sInitialized = true;
502 sValue = intl::LocaleService::GetInstance()->AlwaysAppendAccesskeys();
503 }
504 return sValue;
505}
506
507//----------------------------------------------------------------------
508
509// Block/inline frame construction logic. We maintain a few invariants here:
510//
511// 1. Block frames contain block and inline frames.
512//
513// 2. Inline frames only contain inline frames. If an inline parent has a block
514// child then the block child is migrated upward until it lands in a block
515// parent (the inline frames containing block is where it will end up).
516
517inline void SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame) {
518 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", 518
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->GetNextSibling()"
") (" "Should be using a frame list" ")"); do { MOZ_CrashSequence
(__null, 518); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
519 aParent->SetInitialChildList(FrameChildListID::Principal,
520 nsFrameList(aFrame, aFrame));
521}
522
523// -----------------------------------------------------------
524
525// Structure used when constructing formatting object trees. Contains
526// state information needed for absolutely positioned elements
527namespace mozilla {
528struct AbsoluteFrameList final : public nsFrameList {
529 // Containing block for absolutely positioned elements.
530 nsContainerFrame* mContainingBlock;
531
532 explicit AbsoluteFrameList(nsContainerFrame* aContainingBlock = nullptr)
533 : mContainingBlock(aContainingBlock) {}
534
535 // Transfer frames in aOther to this list. aOther becomes empty after this
536 // operation.
537 AbsoluteFrameList(AbsoluteFrameList&& aOther) = default;
538 AbsoluteFrameList& operator=(AbsoluteFrameList&& aOther) = default;
539
540#ifdef DEBUG1
541 // XXXbz Does this need a debug-only assignment operator that nulls out the
542 // childList in the AbsoluteFrameList we're copying? Introducing a difference
543 // between debug and non-debug behavior seems bad, so I guess not...
544 ~AbsoluteFrameList() {
545 NS_ASSERTION(!FirstChild(),do { if (!(!FirstChild())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Dangling child list. Someone forgot to insert it?", "!FirstChild()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 546); MOZ_PretendNoReturn
(); } } while (0)
546 "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", 546); MOZ_PretendNoReturn
(); } } while (0)
;
547 }
548#endif
549};
550} // namespace mozilla
551
552// -----------------------------------------------------------
553
554// Structure for saving the existing state when pushing/poping containing
555// blocks. The destructor restores the state to its previous state
556class MOZ_STACK_CLASS nsFrameConstructorSaveState {
557 public:
558 ~nsFrameConstructorSaveState();
559
560 private:
561 // Pointer to struct whose data we save/restore.
562 AbsoluteFrameList* mList = nullptr;
563
564 // The saved pointer to the fixed list.
565 AbsoluteFrameList* mSavedFixedList = nullptr;
566
567 // Copy of original frame list. This can be the original absolute list or a
568 // float list.
569 AbsoluteFrameList mSavedList;
570
571 // The name of the child list in which our frames would belong.
572 mozilla::FrameChildListID mChildListID = FrameChildListID::Principal;
573 nsFrameConstructorState* mState = nullptr;
574
575 friend class nsFrameConstructorState;
576};
577
578// Structure used for maintaining state information during the
579// frame construction process
580class MOZ_STACK_CLASS nsFrameConstructorState {
581 public:
582 nsPresContext* mPresContext;
583 PresShell* mPresShell;
584 nsCSSFrameConstructor* mFrameConstructor;
585
586 // Containing block information for out-of-flow frames.
587 //
588 // Floats are easy. Whatever is our float CB.
589 //
590 // Regular abspos elements are easy too. Its containing block can be the
591 // nearest abspos element, or the ICB (the canvas frame).
592 //
593 // Top layer abspos elements are always children of the ICB, but we can get
594 // away with having two different lists (mAbsoluteList and
595 // mTopLayerAbsoluteList), because because top layer frames cause
596 // non-top-layer frames to be contained inside (so any descendants of a top
597 // layer abspos can never share containing block with it, unless they're also
598 // in the top layer).
599 //
600 // Regular fixed elements however are trickier. Fixed elements can be
601 // contained in one of three lists:
602 //
603 // * mAbsoluteList, if our abspos cb is also a fixpos cb (e.g., is
604 // transformed or has a filter).
605 //
606 // * mAncestorFixedList, if the fixpos cb is an ancestor element other than
607 // the viewport frame, (so, a transformed / filtered
608 // ancestor).
609 //
610 // * mRealFixedList, which is also the fixed list used for the top layer
611 // fixed items, which is the fixed list of the viewport
612 // frame.
613 //
614 // It is important that mRealFixedList is shared between regular and top layer
615 // fixpos elements, since no-top-layer descendants of top layer fixed elements
616 // could share ICB and vice versa, so without that there would be no guarantee
617 // of layout ordering between them.
618 AbsoluteFrameList mFloatedList;
619 AbsoluteFrameList mAbsoluteList;
620 AbsoluteFrameList mTopLayerAbsoluteList;
621 AbsoluteFrameList mAncestorFixedList;
622 AbsoluteFrameList mRealFixedList;
623
624 // Never null, always pointing to one of the lists documented above.
625 AbsoluteFrameList* mFixedList;
626
627 // What `page: auto` resolves to. This is the used page-name of the parent
628 // frame. Updated by AutoFrameConstructionPageName.
629 const nsAtom* mAutoPageNameValue = nullptr;
630
631 nsCOMPtr<nsILayoutHistoryState> mFrameState;
632 // These bits will be added to the state bits of any frame we construct
633 // using this state.
634 nsFrameState mAdditionalStateBits = NS_FRAME_STATE_NONE;
635
636 // If false (which is the default) then call SetPrimaryFrame() as needed
637 // during frame construction. If true, don't make any SetPrimaryFrame()
638 // calls, except for generated content which doesn't have a primary frame
639 // yet. The mCreatingExtraFrames == true mode is meant to be used for
640 // construction of random "extra" frames for elements via normal frame
641 // construction APIs (e.g. replication of things across pages in paginated
642 // mode).
643 bool mCreatingExtraFrames;
644
645 // This keeps track of whether we have found a "rendered legend" for
646 // the current FieldSetFrame.
647 bool mHasRenderedLegend;
648
649 nsTArray<RefPtr<nsIContent>> mGeneratedContentWithInitializer;
650
651#ifdef DEBUG1
652 // Record the float containing block candidate passed into
653 // MaybePushFloatContainingBlock() to keep track that we've call the method to
654 // handle the float CB scope before processing the CB's children. It is reset
655 // in ConstructFramesFromItemList().
656 nsContainerFrame* mFloatCBCandidate = nullptr;
657#endif
658
659 // Constructor
660 // Use the passed-in history state.
661 nsFrameConstructorState(
662 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
663 nsContainerFrame* aAbsoluteContainingBlock,
664 nsContainerFrame* aFloatContainingBlock,
665 already_AddRefed<nsILayoutHistoryState> aHistoryState);
666 // Get the history state from the pres context's pres shell.
667 nsFrameConstructorState(PresShell* aPresShell,
668 nsContainerFrame* aFixedContainingBlock,
669 nsContainerFrame* aAbsoluteContainingBlock,
670 nsContainerFrame* aFloatContainingBlock);
671
672 ~nsFrameConstructorState();
673
674 // Process the frame insertions for all the out-of-flow nsAbsoluteItems.
675 void ProcessFrameInsertionsForAllLists();
676
677 // Function to push the existing absolute containing block state and
678 // create a new scope. Code that uses this function should get matching
679 // logic in GetAbsoluteContainingBlock.
680 // Also makes aNewAbsoluteContainingBlock the containing block for
681 // fixed-pos elements if necessary.
682 // aPositionedFrame is the frame whose style actually makes
683 // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable
684 // element aPositionedFrame is the element's primary frame and
685 // aNewAbsoluteContainingBlock is the scrolled frame.
686 void PushAbsoluteContainingBlock(
687 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
688 nsFrameConstructorSaveState& aSaveState);
689
690 // Function to forbid floats descendants under aFloatCBCandidate, or open a
691 // new float containing block scope for aFloatCBCandidate. The current
692 // state is saved in aSaveState if a new scope is pushed.
693 void MaybePushFloatContainingBlock(nsContainerFrame* aFloatCBCandidate,
694 nsFrameConstructorSaveState& aSaveState);
695
696 // Helper function for MaybePushFloatContainingBlock().
697 void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
698 nsFrameConstructorSaveState& aSaveState);
699
700 // Function to return the proper geometric parent for a frame with display
701 // struct given by aStyleDisplay and parent's frame given by
702 // aContentParentFrame.
703 nsContainerFrame* GetGeometricParent(
704 const nsStyleDisplay& aStyleDisplay,
705 nsContainerFrame* aContentParentFrame) const;
706
707 // Collect absolute frames in mAbsoluteList which are proper descendants
708 // of aNewParent, and reparent them to aNewParent.
709 //
710 // Note: This function does something unusual that moves absolute items
711 // after their frames are constructed under a column hierarchy which has
712 // column-span elements. Do not use this if you're not dealing with
713 // columns.
714 void ReparentAbsoluteItems(nsContainerFrame* aNewParent);
715
716 // Collect floats in mFloatedList which are proper descendants of aNewParent,
717 // and reparent them to aNewParent.
718 //
719 // Note: This function does something unusual that moves floats after their
720 // frames are constructed under a column hierarchy which has column-span
721 // elements. Do not use this if you're not dealing with columns.
722 void ReparentFloats(nsContainerFrame* aNewParent);
723
724 /**
725 * Function to add a new frame to the right frame list. This MUST be called
726 * on frames before their children have been processed if the frames might
727 * conceivably be out-of-flow; otherwise cleanup in error cases won't work
728 * right. Also, this MUST be called on frames after they have been
729 * initialized.
730 * @param aNewFrame the frame to add
731 * @param aFrameList the list to add in-flow frames to
732 * @param aContent the content pointer for aNewFrame
733 * @param aParentFrame the parent frame for the content if it were in-flow
734 * @param aCanBePositioned pass false if the frame isn't allowed to be
735 * positioned
736 * @param aCanBeFloated pass false if the frame isn't allowed to be
737 * floated
738 */
739 void AddChild(nsIFrame* aNewFrame, nsFrameList& aFrameList,
740 nsIContent* aContent, nsContainerFrame* aParentFrame,
741 bool aCanBePositioned = true, bool aCanBeFloated = true,
742 bool aInsertAfter = false,
743 nsIFrame* aInsertAfterFrame = nullptr);
744
745 /**
746 * Function to return the fixed-pos element list. Normally this will just
747 * hand back the fixed-pos element list, but in case we're dealing with a
748 * transformed element that's acting as an abs-pos and fixed-pos container,
749 * we'll hand back the abs-pos list. Callers should use this function if they
750 * want to get the list acting as the fixed-pos item parent.
751 */
752 AbsoluteFrameList& GetFixedList() { return *mFixedList; }
753 const AbsoluteFrameList& GetFixedList() const { return *mFixedList; }
754
755 protected:
756 friend class nsFrameConstructorSaveState;
757
758 /**
759 * ProcessFrameInsertions takes the frames in aFrameList and adds them as
760 * kids to the aChildListID child list of |aFrameList.containingBlock|.
761 */
762 void ProcessFrameInsertions(AbsoluteFrameList& aFrameList,
763 mozilla::FrameChildListID aChildListID);
764
765 /**
766 * GetOutOfFlowFrameList selects the out-of-flow frame list the new
767 * frame should be added to. If the frame shouldn't be added to any
768 * out-of-flow list, it returns nullptr. The corresponding type of
769 * placeholder is also returned via the aPlaceholderType parameter
770 * if this method doesn't return nullptr. The caller should check
771 * whether the returned list really has a containing block.
772 */
773 AbsoluteFrameList* GetOutOfFlowFrameList(nsIFrame* aNewFrame,
774 bool aCanBePositioned,
775 bool aCanBeFloated,
776 nsFrameState* aPlaceholderType);
777};
778
779nsFrameConstructorState::nsFrameConstructorState(
780 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
781 nsContainerFrame* aAbsoluteContainingBlock,
782 nsContainerFrame* aFloatContainingBlock,
783 already_AddRefed<nsILayoutHistoryState> aHistoryState)
784 : mPresContext(aPresShell->GetPresContext()),
785 mPresShell(aPresShell),
786 mFrameConstructor(aPresShell->FrameConstructor()),
787 mFloatedList(aFloatContainingBlock),
788 mAbsoluteList(aAbsoluteContainingBlock),
789 mTopLayerAbsoluteList(mFrameConstructor->GetCanvasFrame()),
790 mAncestorFixedList(aFixedContainingBlock),
791 mRealFixedList(
792 static_cast<nsContainerFrame*>(mFrameConstructor->GetRootFrame())),
793 // See PushAbsoluteContaningBlock below
794 mFrameState(aHistoryState),
795 mCreatingExtraFrames(false),
796 mHasRenderedLegend(false) {
797 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)
;
798 mFixedList = [&] {
799 if (aFixedContainingBlock == aAbsoluteContainingBlock) {
800 return &mAbsoluteList;
801 }
802 if (aAbsoluteContainingBlock == mRealFixedList.mContainingBlock) {
803 return &mRealFixedList;
804 }
805 return &mAncestorFixedList;
806 }();
807}
808
809nsFrameConstructorState::nsFrameConstructorState(
810 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
811 nsContainerFrame* aAbsoluteContainingBlock,
812 nsContainerFrame* aFloatContainingBlock)
813 : nsFrameConstructorState(
814 aPresShell, aFixedContainingBlock, aAbsoluteContainingBlock,
815 aFloatContainingBlock,
816 aPresShell->GetDocument()->GetLayoutHistoryState()) {}
817
818nsFrameConstructorState::~nsFrameConstructorState() {
819 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)
;
820 ProcessFrameInsertionsForAllLists();
821 for (auto& content : Reversed(mGeneratedContentWithInitializer)) {
822 content->RemoveProperty(nsGkAtoms::genConInitializerProperty);
823 }
824}
825
826void nsFrameConstructorState::ProcessFrameInsertionsForAllLists() {
827 ProcessFrameInsertions(mFloatedList, FrameChildListID::Float);
828 ProcessFrameInsertions(mAbsoluteList, FrameChildListID::Absolute);
829 ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
830 ProcessFrameInsertions(*mFixedList, FrameChildListID::Absolute);
831 ProcessFrameInsertions(mRealFixedList, FrameChildListID::Absolute);
832}
833
834void nsFrameConstructorState::PushAbsoluteContainingBlock(
835 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
836 nsFrameConstructorSaveState& aSaveState) {
837 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"
, 838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 838); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
838 "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"
, 838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 838); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
839 aSaveState.mList = &mAbsoluteList;
840 aSaveState.mChildListID = FrameChildListID::Absolute;
841 aSaveState.mState = this;
842 aSaveState.mSavedList = std::move(mAbsoluteList);
843 aSaveState.mSavedFixedList = mFixedList;
844 mAbsoluteList = AbsoluteFrameList(aNewAbsoluteContainingBlock);
845 mFixedList = [&] {
846 if (!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock()) {
847 // See if we need to treat abspos and fixedpos the same. This happens if
848 // we're a transformed/filtered/etc element, or if we force a null abspos
849 // containing block (for mathml for example).
850 return &mAbsoluteList;
851 }
852 if (aPositionedFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Auto) {
853 // If our new CB is in the top layer, and isn't a fixed CB itself, we also
854 // escape the usual containment.
855 return &mRealFixedList;
856 }
857 if (mFixedList == &mAbsoluteList) {
858 // If we were pointing to our old absolute list, keep pointing to it.
859 return &aSaveState.mSavedList;
860 }
861 // Otherwise keep pointing to the current thing (another ancestor's
862 // absolute list, or the real fixed list, doesn't matter).
863 return mFixedList;
864 }();
865
866 if (aNewAbsoluteContainingBlock &&
867 !aNewAbsoluteContainingBlock->IsAbsoluteContainer()) {
868 aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
869 }
870}
871
872void nsFrameConstructorState::MaybePushFloatContainingBlock(
873 nsContainerFrame* aFloatCBCandidate,
874 nsFrameConstructorSaveState& aSaveState) {
875 // The logic here needs to match the logic in GetFloatContainingBlock().
876 if (ShouldSuppressFloatingOfDescendants(aFloatCBCandidate)) {
877 // Pushing a null float containing block forbids any frames from being
878 // floated until a new float containing block is pushed. See implementation
879 // of nsFrameConstructorState::AddChild().
880 //
881 // XXX we should get rid of null float containing blocks and teach the
882 // various frame classes to deal with floats instead.
883 PushFloatContainingBlock(nullptr, aSaveState);
884 } else if (aFloatCBCandidate->IsFloatContainingBlock()) {
885 PushFloatContainingBlock(aFloatCBCandidate, aSaveState);
886 }
887
888#ifdef DEBUG1
889 mFloatCBCandidate = aFloatCBCandidate;
890#endif
891}
892
893void nsFrameConstructorState::PushFloatContainingBlock(
894 nsContainerFrame* aNewFloatContainingBlock,
895 nsFrameConstructorSaveState& aSaveState) {
896 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"
, 898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 898); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
897 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"
, 898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 898); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
898 "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"
, 898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 898); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
899 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", 903); MOZ_PretendNoReturn
(); } } while (0)
900 !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", 903); MOZ_PretendNoReturn
(); } } while (0)
901 !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", 903); MOZ_PretendNoReturn
(); } } while (0)
902 "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", 903); MOZ_PretendNoReturn
(); } } while (0)
903 "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", 903); MOZ_PretendNoReturn
(); } } while (0)
;
904 aSaveState.mList = &mFloatedList;
905 aSaveState.mSavedList = std::move(mFloatedList);
906 aSaveState.mChildListID = FrameChildListID::Float;
907 aSaveState.mState = this;
908 mFloatedList = AbsoluteFrameList(aNewFloatContainingBlock);
909}
910
911nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
912 const nsStyleDisplay& aStyleDisplay,
913 nsContainerFrame* aContentParentFrame) const {
914 // If there is no container for a fixed, absolute, or floating root
915 // frame, we will ignore the positioning. This hack is originally
916 // brought to you by the letter T: tables, since other roots don't
917 // even call into this code. See bug 178855.
918 //
919 // XXX Disabling positioning in this case is a hack. If one was so inclined,
920 // one could support this either by (1) inserting a dummy block between the
921 // table and the canvas or (2) teaching the canvas how to reflow positioned
922 // elements. (1) has the usual problems when multiple frames share the same
923 // content (notice all the special cases in this file dealing with inner
924 // tables and table wrappers which share the same content). (2) requires some
925 // work and possible factoring.
926 //
927 // XXXbz couldn't we just force position to "static" on roots and
928 // float to "none"? That's OK per CSS 2.1, as far as I can tell.
929
930 if (aContentParentFrame && aContentParentFrame->IsInSVGTextSubtree()) {
931 return aContentParentFrame;
932 }
933
934 if (aStyleDisplay.IsFloatingStyle() && mFloatedList.mContainingBlock) {
935 NS_ASSERTION(!aStyleDisplay.IsAbsolutelyPositionedStyle(),do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 936); MOZ_PretendNoReturn(); } } while (0)
936 "Absolutely positioned _and_ floating?")do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 936); MOZ_PretendNoReturn(); } } while (0)
;
937 return mFloatedList.mContainingBlock;
938 }
939
940 if (aStyleDisplay.mTopLayer != StyleTopLayer::None) {
941 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"
, 942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 942); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
942 "-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"
, 942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 942); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
943 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", 944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
944 "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", 944
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
945 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed) {
946 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"
, 946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealFixedList.mContainingBlock"
") (" "No root frame?" ")"); do { MOZ_CrashSequence(__null, 946
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
947 return mRealFixedList.mContainingBlock;
948 }
949 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", 949); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStyleDisplay.mPosition == StylePositionProperty::Absolute"
")"); do { MOZ_CrashSequence(__null, 949); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
950 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", 950); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mTopLayerAbsoluteList.mContainingBlock" ")"
); do { MOZ_CrashSequence(__null, 950); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
951 return mTopLayerAbsoluteList.mContainingBlock;
952 }
953
954 if (aStyleDisplay.mPosition == StylePositionProperty::Absolute &&
955 mAbsoluteList.mContainingBlock) {
956 return mAbsoluteList.mContainingBlock;
957 }
958
959 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed &&
960 mFixedList->mContainingBlock) {
961 return mFixedList->mContainingBlock;
962 }
963
964 return aContentParentFrame;
965}
966
967void nsFrameConstructorState::ReparentAbsoluteItems(
968 nsContainerFrame* aNewParent) {
969 // Bug 1491727: This function might not conform to the spec. See
970 // https://github.com/w3c/csswg-drafts/issues/1894.
971
972 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"
, 973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 973); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
973 "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"
, 973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 973); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
974
975 AbsoluteFrameList newAbsoluteItems(aNewParent);
976
977 nsIFrame* current = mAbsoluteList.FirstChild();
978 while (current) {
979 nsIFrame* placeholder = current->GetPlaceholderFrame();
980
981 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
982 nsIFrame* next = current->GetNextSibling();
983 mAbsoluteList.RemoveFrame(current);
984 newAbsoluteItems.AppendFrame(aNewParent, current);
985 current = next;
986 } else {
987 current = current->GetNextSibling();
988 }
989 }
990
991 if (newAbsoluteItems.NotEmpty()) {
992 // ~nsFrameConstructorSaveState() will move newAbsoluteItems to
993 // aNewParent's absolute child list.
994 nsFrameConstructorSaveState absoluteSaveState;
995
996 // It doesn't matter whether aNewParent has position style or not. Caller
997 // won't call us if we can't have absolute children.
998 PushAbsoluteContainingBlock(aNewParent, aNewParent, absoluteSaveState);
999 mAbsoluteList = std::move(newAbsoluteItems);
1000 }
1001}
1002
1003void nsFrameConstructorState::ReparentFloats(nsContainerFrame* aNewParent) {
1004 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"
, 1005); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1005); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1005 "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"
, 1005); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1005); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1006 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", 1008
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1008); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1007 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", 1008
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1008); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1008 "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", 1008
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1008); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1009
1010 // Gather floats that should reparent under aNewParent.
1011 AbsoluteFrameList floats(aNewParent);
1012 nsIFrame* current = mFloatedList.FirstChild();
1013 while (current) {
1014 nsIFrame* placeholder = current->GetPlaceholderFrame();
1015 nsIFrame* next = current->GetNextSibling();
1016 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
1017 mFloatedList.RemoveFrame(current);
1018 floats.AppendFrame(aNewParent, current);
1019 }
1020 current = next;
1021 }
1022
1023 if (floats.NotEmpty()) {
1024 // Make floats move into aNewParent's float child list in
1025 // ~nsFrameConstructorSaveState() when destructing floatSaveState.
1026 nsFrameConstructorSaveState floatSaveState;
1027 PushFloatContainingBlock(aNewParent, floatSaveState);
1028 mFloatedList = std::move(floats);
1029 }
1030}
1031
1032AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
1033 nsIFrame* aNewFrame, bool aCanBePositioned, bool aCanBeFloated,
1034 nsFrameState* aPlaceholderType) {
1035 const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1036 if (aCanBeFloated && disp->IsFloatingStyle()) {
1037 *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1038 return &mFloatedList;
1039 }
1040
1041 if (aCanBePositioned) {
1042 if (disp->mTopLayer != StyleTopLayer::None) {
1043 *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1044 if (disp->mPosition == StylePositionProperty::Fixed) {
1045 *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1046 return &mRealFixedList;
1047 }
1048 *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1049 return &mTopLayerAbsoluteList;
1050 }
1051 if (disp->mPosition == StylePositionProperty::Absolute) {
1052 *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1053 return &mAbsoluteList;
1054 }
1055 if (disp->mPosition == StylePositionProperty::Fixed) {
1056 *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1057 return mFixedList;
1058 }
1059 }
1060 return nullptr;
1061}
1062
1063void nsFrameConstructorState::AddChild(
1064 nsIFrame* aNewFrame, nsFrameList& aFrameList, nsIContent* aContent,
1065 nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated,
1066 bool aInsertAfter, nsIFrame* aInsertAfterFrame) {
1067 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", 1067); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aNewFrame->GetNextSibling()" ") (" "Shouldn't happen"
")"); do { MOZ_CrashSequence(__null, 1067); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1068
1069 nsFrameState placeholderType = NS_FRAME_STATE_NONE;
1070 AbsoluteFrameList* outOfFlowFrameList = GetOutOfFlowFrameList(
1071 aNewFrame, aCanBePositioned, aCanBeFloated, &placeholderType);
1072
1073 // The comments in GetGeometricParent regarding root table frames
1074 // all apply here, unfortunately. Thus, we need to check whether
1075 // the returned frame items really has containing block.
1076 nsFrameList* frameList;
1077 if (outOfFlowFrameList && outOfFlowFrameList->mContainingBlock) {
1078 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", 1079); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1079); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1079 "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", 1079); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1079); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1080 frameList = outOfFlowFrameList;
1081 } else {
1082 frameList = &aFrameList;
1083 placeholderType = NS_FRAME_STATE_NONE;
1084 }
1085
1086 if (placeholderType != NS_FRAME_STATE_NONE) {
1087 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", 1088); MOZ_PretendNoReturn
(); } } while (0)
1088 "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", 1088); MOZ_PretendNoReturn
(); } } while (0)
;
1089 nsIFrame* placeholderFrame =
1090 nsCSSFrameConstructor::CreatePlaceholderFrameFor(
1091 mPresShell, aContent, aNewFrame, aParentFrame, nullptr,
1092 placeholderType);
1093
1094 placeholderFrame->AddStateBits(mAdditionalStateBits);
1095 // Add the placeholder frame to the flow
1096 aFrameList.AppendFrame(nullptr, placeholderFrame);
1097 }
1098#ifdef DEBUG1
1099 else {
1100 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", 1101); MOZ_PretendNoReturn
(); } } while (0)
1101 "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", 1101); MOZ_PretendNoReturn
(); } } while (0)
;
1102 }
1103#endif
1104
1105 if (aInsertAfter) {
1106 frameList->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1107 } else {
1108 frameList->AppendFrame(nullptr, aNewFrame);
1109 }
1110}
1111
1112// Some of this function's callers recurse 1000 levels deep in crashtests. On
1113// platforms where stack limits are low, we can't afford to incorporate this
1114// function's `AutoTArray`s into its callers' stack frames, so disable inlining.
1115MOZ_NEVER_INLINE__attribute__((noinline)) void nsFrameConstructorState::ProcessFrameInsertions(
1116 AbsoluteFrameList& aFrameList, FrameChildListID aChildListID) {
1117 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", 1120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1118 &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", 1120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1119 &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", 1120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1120 &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", 1120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1121 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"
, 1122); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1122); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1122 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"
, 1122); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1122); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1123 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", 1124); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1124); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1124 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", 1124); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1124); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1125 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"
, 1126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1126); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1126 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"
, 1126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1126); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1127 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"
, 1128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1128); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1128 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"
, 1128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1128); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1129 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"
, 1130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1130); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1130 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"
, 1130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1130); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1131 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"
, 1132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1132); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1132 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"
, 1132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1132); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1133
1134 if (aFrameList.IsEmpty()) {
1135 return;
1136 }
1137
1138 nsContainerFrame* containingBlock = aFrameList.mContainingBlock;
1139
1140 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"
, 1140); MOZ_PretendNoReturn(); } } while (0)
;
1141
1142 // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1143 // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1144 // is set) and doesn't have any frames in the aChildListID child list yet.
1145 const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1146 if (childList.IsEmpty() &&
1147 containingBlock->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1148 // If we're injecting absolutely positioned frames, inject them on the
1149 // absolute containing block
1150 if (aChildListID == FrameChildListID::Absolute) {
1151 containingBlock->GetAbsoluteContainingBlock()->SetInitialChildList(
1152 containingBlock, aChildListID, std::move(aFrameList));
1153 } else {
1154 containingBlock->SetInitialChildList(aChildListID, std::move(aFrameList));
1155 }
1156 } else if (childList.IsEmpty() ||
1157 aChildListID == FrameChildListID::Absolute) {
1158 // The order is not important for abs-pos/fixed-pos frame list, just
1159 // append the frame items to the list directly.
1160 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1161 std::move(aFrameList));
1162 } else {
1163 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", 1163); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float" ")"
); do { MOZ_CrashSequence(__null, 1163); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1164 // Note that whether the frame construction context is doing an append or
1165 // not is not helpful here, since it could be appending to some frame in
1166 // the middle of the document, which means we're not necessarily
1167 // appending to the children of the containing block.
1168 //
1169 // We need to make sure the 'append to the end of document' case is fast.
1170 // So first test the last child of the containing block
1171 nsIFrame* lastChild = childList.LastChild();
1172 lastChild = lastChild->FirstContinuation()->GetPlaceholderFrame();
1173
1174 // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1175 // so this will make out-of-flows respect the ordering of placeholders,
1176 // which is great because it takes care of anonymous content.
1177 nsIFrame* firstNewFrame = aFrameList.FirstChild();
1178 firstNewFrame = firstNewFrame->GetPlaceholderFrame();
1179
1180 // Cache the ancestor chain so that we can reuse it if needed.
1181 AutoTArray<const nsIFrame*, 20> firstNewFrameAncestors;
1182 const nsIFrame* notCommonAncestor = nsLayoutUtils::FillAncestors(
1183 firstNewFrame, containingBlock, &firstNewFrameAncestors);
1184
1185 if (nsLayoutUtils::CompareTreePosition(
1186 lastChild, firstNewFrame, firstNewFrameAncestors,
1187 notCommonAncestor ? containingBlock : nullptr) < 0) {
1188 // lastChild comes before the new children, so just append
1189 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1190 std::move(aFrameList));
1191 } else {
1192 // Try the other children. First collect them to an array so that a
1193 // reasonable fast binary search can be used to find the insertion point.
1194 AutoTArray<std::pair<nsIFrame*, nsPlaceholderFrame*>, 128> children;
1195 for (nsIFrame* f : childList) {
1196 children.AppendElement(
1197 std::make_pair(f, f->FirstContinuation()->GetPlaceholderFrame()));
1198 }
1199
1200 nsIFrame* insertionPoint = nullptr;
1201 int32_t imin = 0;
1202 int32_t max = children.Length();
1203 while (max > imin) {
1204 int32_t imid = imin + ((max - imin) / 2);
1205 const auto& pair = children[imid];
1206 int32_t compare = nsLayoutUtils::CompareTreePosition(
1207 pair.second, firstNewFrame, firstNewFrameAncestors,
1208 notCommonAncestor ? containingBlock : nullptr);
1209 if (compare > 0) {
1210 // f is after the new frame.
1211 max = imid;
1212 insertionPoint = imid > 0 ? children[imid - 1].first : nullptr;
1213 } else if (compare < 0) {
1214 // f is before the new frame.
1215 imin = imid + 1;
1216 insertionPoint = pair.first;
1217 } else {
1218 // This is for the old behavior. Should be removed once it is
1219 // guaranteed that CompareTreePosition can't return 0!
1220 // See bug 928645.
1221 NS_WARNING("Something odd happening???")NS_DebugBreak(NS_DEBUG_WARNING, "Something odd happening???",
nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp",
1221)
;
1222 insertionPoint = nullptr;
1223 for (auto [frame, placeholder] : children) {
1224 if (nsLayoutUtils::CompareTreePosition(
1225 placeholder, firstNewFrame, firstNewFrameAncestors,
1226 notCommonAncestor ? containingBlock : nullptr) > 0) {
1227 break;
1228 }
1229 insertionPoint = frame;
1230 }
1231 break;
1232 }
1233 }
1234 mFrameConstructor->InsertFrames(containingBlock, aChildListID,
1235 insertionPoint, std::move(aFrameList));
1236 }
1237 }
1238
1239 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"
, 1239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrameList.IsEmpty()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 1239); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1240}
1241
1242nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
1243 // Restore the state
1244 if (mList) {
1245 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", 1245
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mState" ") (" "Can't have mList set without having a state!"
")"); do { MOZ_CrashSequence(__null, 1245); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1246 mState->ProcessFrameInsertions(*mList, mChildListID);
1247
1248 if (mList == &mState->mAbsoluteList) {
1249 mState->mAbsoluteList = std::move(mSavedList);
1250 mState->mFixedList = mSavedFixedList;
1251 } else {
1252 mState->mFloatedList = std::move(mSavedList);
1253 }
1254
1255 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", 1256
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1256); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1256 "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", 1256
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1256); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1257 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"
, 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1258); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1258 "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"
, 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1258); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1259 }
1260}
1261
1262/**
1263 * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1264 * pointer of the frames in the list, and reparents their views as needed.
1265 * nsIFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1266 * ancestors as needed. Then it sets the list as the initial child list
1267 * on aNewParent, unless aNewParent either already has kids or has been
1268 * reflowed; in that case it appends the new frames. Note that this
1269 * method differs from ReparentFrames in that it doesn't change the kids'
1270 * style.
1271 */
1272// XXXbz Since this is only used for {ib} splits, could we just copy the view
1273// bits from aOldParent to aNewParent and then use the
1274// nsFrameList::ApplySetParent? That would still leave us doing two passes
1275// over the list, of course; if we really wanted to we could factor out the
1276// relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1277// views, which would make most of this function go away.
1278static void MoveChildrenTo(nsIFrame* aOldParent, nsContainerFrame* aNewParent,
1279 nsFrameList& aFrameList) {
1280 aFrameList.ApplySetParent(aNewParent);
1281
1282 if (aNewParent->PrincipalChildList().IsEmpty() &&
1283 aNewParent->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1284 aNewParent->SetInitialChildList(FrameChildListID::Principal,
1285 std::move(aFrameList));
1286 } else {
1287 aNewParent->AppendFrames(FrameChildListID::Principal,
1288 std::move(aFrameList));
1289 }
1290}
1291
1292static void EnsureAutoPageName(nsFrameConstructorState& aState,
1293 const nsContainerFrame* const aFrame) {
1294 // Check if we need to figure out our used page name.
1295 // When building the entire document, this should only happen for the
1296 // root, which will mean the loop will immediately end. Either way, this will
1297 // only happen once for each time the frame constructor is run.
1298 if (aState.mAutoPageNameValue) {
1299 return;
1300 }
1301
1302 for (const nsContainerFrame* frame = aFrame; frame;
1303 frame = frame->GetParent()) {
1304 if (const nsAtom* maybePageName = frame->GetStylePageName()) {
1305 aState.mAutoPageNameValue = maybePageName;
1306 return;
1307 }
1308 }
1309 // Ensure that a root with `page: auto` gets an empty page name
1310 // https://drafts.csswg.org/css-page-3/#using-named-pages
1311 aState.mAutoPageNameValue = nsGkAtoms::_empty;
1312}
1313
1314nsCSSFrameConstructor::AutoFrameConstructionPageName::
1315 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1316 nsIFrame* const aFrame)
1317 : mState(aState), mNameToRestore(nullptr) {
1318 if (!aState.mPresContext->IsPaginated()) {
1319 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"
, 1320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1320); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1320 "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"
, 1320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1320); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1321 return;
1322 }
1323#ifdef DEBUG1
1324 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"
, 1325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1325); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1325 "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"
, 1325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1325); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1326 aFrame->mWasVisitedByAutoFrameConstructionPageName = true;
1327#endif
1328
1329 EnsureAutoPageName(aState, aFrame->GetParent());
1330 mNameToRestore = aState.mAutoPageNameValue;
1331
1332 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", 1333
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1333 "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", 1333
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1334 if (const nsAtom* maybePageName = aFrame->GetStylePageName()) {
1335 aState.mAutoPageNameValue = maybePageName;
1336 }
1337 aFrame->SetAutoPageValue(aState.mAutoPageNameValue);
1338}
1339
1340nsCSSFrameConstructor::AutoFrameConstructionPageName::
1341 ~AutoFrameConstructionPageName() {
1342 // This isn't actually useful when not in paginated layout, but it's very
1343 // likely cheaper to unconditionally write this pointer than to test for
1344 // paginated layout and then branch on the result.
1345 mState.mAutoPageNameValue = mNameToRestore;
1346}
1347
1348//----------------------------------------------------------------------
1349
1350nsCSSFrameConstructor::nsCSSFrameConstructor(Document* aDocument,
1351 PresShell* aPresShell)
1352 : nsFrameManager(aPresShell),
1353 mDocument(aDocument),
1354 mFirstFreeFCItem(nullptr),
1355 mFCItemsInUse(0),
1356 mCurrentDepth(0),
1357 mQuotesDirty(false),
1358 mCountersDirty(false),
1359 mAlwaysCreateFramesForIgnorableWhitespace(false),
1360 mRemovingContent(false) {
1361#ifdef DEBUG1
1362 static bool gFirstTime = true;
1363 if (gFirstTime) {
1364 gFirstTime = false;
1365 char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1366 if (flags) {
1367 bool error = false;
1368 for (;;) {
1369 char* comma = strchr(flags, ',');
1370 if (comma) *comma = '\0';
1371
1372 bool found = false;
1373 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1374 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1375 while (flag < limit) {
1376 if (nsCRT::strcasecmp(flag->name, flags) == 0) {
1377 *(flag->on) = true;
1378 printf("nsCSSFrameConstructor: setting %s debug flag on\n",
1379 flag->name);
1380 found = true;
1381 break;
1382 }
1383 ++flag;
1384 }
1385
1386 if (!found) error = true;
1387
1388 if (!comma) break;
1389
1390 *comma = ',';
1391 flags = comma + 1;
1392 }
1393
1394 if (error) {
1395 printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1396 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1397 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1398 while (flag < limit) {
1399 printf(" %s\n", flag->name);
1400 ++flag;
1401 }
1402 printf(
1403 "Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of "
1404 "flag\n");
1405 printf("names (no whitespace)\n");
1406 }
1407 }
1408 }
1409#endif
1410}
1411
1412void nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) {
1413 if (aFrame->StyleDisplay()->IsContainStyle()) {
1414 mContainStyleScopeManager.DestroyScopesFor(aFrame);
1415 }
1416
1417 if (aFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
1418 mContainStyleScopeManager.DestroyQuoteNodesFor(aFrame)) {
1419 QuotesDirty();
1420 }
1421
1422 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1423 mContainStyleScopeManager.DestroyCounterNodesFor(aFrame)) {
1424 // Technically we don't need to update anything if we destroyed only
1425 // USE nodes. However, this is unlikely to happen in the real world
1426 // since USE nodes generally go along with INCREMENT nodes.
1427 CountersDirty();
1428 }
1429
1430 RestyleManager()->NotifyDestroyingFrame(aFrame);
1431}
1432
1433struct nsGenConInitializer {
1434 UniquePtr<nsGenConNode> mNode;
1435 // Null if we should use the quote list.
1436 RefPtr<nsAtom> mCounterListName;
1437
1438 nsGenConInitializer(UniquePtr<nsGenConNode> aNode, nsAtom* aCounterListName)
1439 : mNode(std::move(aNode)), mCounterListName(aCounterListName) {}
1440};
1441
1442already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
1443 nsFrameConstructorState& aState, const nsAString& aString,
1444 UniquePtr<nsGenConInitializer> aInitializer) {
1445 RefPtr<nsTextNode> content = new (mDocument->NodeInfoManager())
1446 nsTextNode(mDocument->NodeInfoManager());
1447 content->SetText(aString, false);
1448 if (aInitializer) {
1449 aInitializer->mNode->mText = content;
1450 content->SetProperty(nsGkAtoms::genConInitializerProperty,
1451 aInitializer.release(),
1452 nsINode::DeleteProperty<nsGenConInitializer>);
1453 aState.mGeneratedContentWithInitializer.AppendElement(content);
1454 }
1455 return content.forget();
1456}
1457
1458void nsCSSFrameConstructor::CreateGeneratedContent(
1459 nsFrameConstructorState& aState, Element& aOriginatingElement,
1460 ComputedStyle& aPseudoStyle, const StyleContentItem& aItem,
1461 size_t aContentIndex, const FunctionRef<void(nsIContent*)> aAddChild) {
1462 using Type = StyleContentItem::Tag;
1463 // Get the content value
1464 const Type type = aItem.tag;
1465
1466 switch (type) {
1467 case Type::Image: {
1468 RefPtr c = GeneratedImageContent::Create(*mDocument, aContentIndex);
1469 aAddChild(c);
1470 return;
1471 }
1472
1473 case Type::String: {
1474 const auto string = aItem.AsString().AsString();
1475 if (string.IsEmpty()) {
1476 return;
1477 }
1478 RefPtr text =
1479 CreateGenConTextNode(aState, NS_ConvertUTF8toUTF16(string), nullptr);
1480 aAddChild(text);
1481 return;
1482 }
1483
1484 case Type::Counter:
1485 case Type::Counters: {
1486 RefPtr<nsAtom> name;
1487 const StyleCounterStyle* style;
1488 nsString separator;
1489 if (type == Type::Counter) {
1490 const auto& counter = aItem.AsCounter();
1491 name = counter._0.AsAtom();
1492 style = &counter._1;
1493 } else {
1494 const auto& counters = aItem.AsCounters();
1495 name = counters._0.AsAtom();
1496 CopyUTF8toUTF16(counters._1.AsString(), separator);
1497 style = &counters._2;
1498 }
1499 auto node = MakeUnique<nsCounterUseNode>(
1500 *style, std::move(separator), aContentIndex,
1501 /* aAllCounters = */ type == Type::Counters);
1502 auto initializer = MakeUnique<nsGenConInitializer>(std::move(node), name);
1503 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1504 aAddChild(c);
1505 return;
1506 }
1507 case Type::OpenQuote:
1508 case Type::CloseQuote:
1509 case Type::NoOpenQuote:
1510 case Type::NoCloseQuote: {
1511 auto node = MakeUnique<nsQuoteNode>(type, aContentIndex);
1512 auto initializer =
1513 MakeUnique<nsGenConInitializer>(std::move(node), nullptr);
1514 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1515 aAddChild(c);
1516 return;
1517 }
1518
1519 case Type::MozLabelContent: {
1520 nsAutoString accesskey;
1521 if (!aOriginatingElement.GetAttr(nsGkAtoms::accesskey, accesskey) ||
1522 accesskey.IsEmpty() || !LookAndFeel::GetMenuAccessKey()) {
1523 // Easy path: just return a regular value attribute content.
1524 nsCOMPtr<nsIContent> content;
1525 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::value,
1526 getter_AddRefs(content));
1527 aAddChild(content);
1528 return;
1529 }
1530
1531 nsAutoString value;
1532 aOriginatingElement.GetAttr(nsGkAtoms::value, value);
1533
1534 auto AppendAccessKeyLabel = [&] {
1535 // Always append accesskey text in uppercase, see bug 1806167.
1536 ToUpperCase(accesskey);
1537 nsAutoString accessKeyLabel = u"("_ns + accesskey + u")"_ns;
1538 if (!StringEndsWith(value, accessKeyLabel)) {
1539 if (InsertSeparatorBeforeAccessKey() && !value.IsEmpty() &&
1540 !NS_IS_SPACE(value.Last())) {
1541 value.Append(' ');
1542 }
1543 value.Append(accessKeyLabel);
1544 }
1545 };
1546 if (AlwaysAppendAccessKey()) {
1547 AppendAccessKeyLabel();
1548 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1549 aAddChild(c);
1550 return;
1551 }
1552
1553 const auto accessKeyStart = [&]() -> Maybe<size_t> {
1554 nsAString::const_iterator start, end;
1555 value.BeginReading(start);
1556 value.EndReading(end);
1557
1558 const auto originalStart = start;
1559 // not appending access key - do case-sensitive search
1560 // first
1561 bool found = true;
1562 if (!FindInReadable(accesskey, start, end)) {
1563 start = originalStart;
1564 // didn't find it - perform a case-insensitive search
1565 found = CaseInsensitiveFindInReadable(accesskey, start, end);
1566 }
1567 if (!found) {
1568 return Nothing();
1569 }
1570 return Some(Distance(originalStart, start));
1571 }();
1572
1573 if (accessKeyStart.isNothing()) {
1574 AppendAccessKeyLabel();
1575 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1576 aAddChild(c);
1577 return;
1578 }
1579
1580 if (*accessKeyStart != 0) {
1581 RefPtr beginning = CreateGenConTextNode(
1582 aState, Substring(value, 0, *accessKeyStart), nullptr);
1583 aAddChild(beginning);
1584 }
1585
1586 {
1587 RefPtr accessKeyText = CreateGenConTextNode(
1588 aState, Substring(value, *accessKeyStart, accesskey.Length()),
1589 nullptr);
1590 RefPtr<nsIContent> underline =
1591 mDocument->CreateHTMLElement(nsGkAtoms::u);
1592 underline->AppendChildTo(accessKeyText, /* aNotify = */ false,
1593 IgnoreErrors());
1594 aAddChild(underline);
1595 }
1596
1597 size_t accessKeyEnd = *accessKeyStart + accesskey.Length();
1598 if (accessKeyEnd != value.Length()) {
1599 RefPtr valueEnd = CreateGenConTextNode(
1600 aState, Substring(value, *accessKeyStart + accesskey.Length()),
1601 nullptr);
1602 aAddChild(valueEnd);
1603 }
1604 break;
1605 }
1606 case Type::MozAltContent: {
1607 // Use the "alt" attribute; if that fails and the node is an HTML
1608 // <input>, try the value attribute and then fall back to some default
1609 // localized text we have.
1610 // XXX what if the 'alt' attribute is added later, how will we
1611 // detect that and do the right thing here?
1612 if (aOriginatingElement.HasAttr(nsGkAtoms::alt)) {
1613 nsCOMPtr<nsIContent> content;
1614 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::alt,
1615 getter_AddRefs(content));
1616 aAddChild(content);
1617 return;
1618 }
1619
1620 if (aOriginatingElement.IsHTMLElement(nsGkAtoms::input)) {
1621 if (aOriginatingElement.HasAttr(nsGkAtoms::value)) {
1622 nsCOMPtr<nsIContent> content;
1623 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::value,
1624 getter_AddRefs(content));
1625 aAddChild(content);
1626 return;
1627 }
1628
1629 nsAutoString temp;
1630 nsContentUtils::GetMaybeLocalizedString(
1631 PropertiesFile::FORMS_PROPERTIES, "Submit", mDocument, temp);
1632 RefPtr c = CreateGenConTextNode(aState, temp, nullptr);
1633 aAddChild(c);
1634 return;
1635 }
1636 break;
1637 }
1638 }
1639}
1640
1641void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
1642 nsFrameConstructorState& aState, Element& aOriginatingElement,
1643 const ComputedStyle& aPseudoStyle,
1644 const FunctionRef<void(nsIContent*)> aAddChild) {
1645 const nsStyleList* styleList = aPseudoStyle.StyleList();
1646 if (!styleList->mListStyleImage.IsNone()) {
1647 RefPtr<nsIContent> child =
1648 GeneratedImageContent::CreateForListStyleImage(*mDocument);
1649 aAddChild(child);
1650 child = CreateGenConTextNode(aState, u" "_ns, nullptr);
1651 aAddChild(child);
1652 return;
1653 }
1654 CreateGeneratedContentFromListStyleType(aState, aOriginatingElement,
1655 aPseudoStyle, aAddChild);
1656}
1657
1658void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
1659 nsFrameConstructorState& aState, Element& aOriginatingElement,
1660 const ComputedStyle& aPseudoStyle,
1661 const FunctionRef<void(nsIContent*)> aAddChild) {
1662 using Tag = StyleCounterStyle::Tag;
1663 const auto& styleType = aPseudoStyle.StyleList()->mListStyleType;
1664 switch (styleType.tag) {
1665 case Tag::None:
1666 return;
1667 case Tag::String: {
1668 nsDependentAtomString string(styleType.AsString().AsAtom());
1669 RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr);
1670 aAddChild(child);
1671 return;
1672 }
1673 case Tag::Name:
1674 case Tag::Symbols:
1675 break;
1676 }
1677
1678 auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet,
1679 styleType);
1680 if (styleType.IsName()) {
1681 nsAtom* name = styleType.AsName().AsAtom();
1682 if (name == nsGkAtoms::disc || name == nsGkAtoms::circle ||
1683 name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed ||
1684 name == nsGkAtoms::disclosure_open) {
1685 // We don't need a use node inserted for these.
1686 CounterStyle* counterStyle = mPresShell->GetPresContext()
1687 ->CounterStyleManager()
1688 ->ResolveCounterStyle(name);
1689 nsAutoString text;
1690 node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
1691 // Note that we're done with 'node' in this case. It's not inserted into
1692 // any list so it's deleted when we return.
1693 RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
1694 aAddChild(child);
1695 return;
1696 }
1697 }
1698
1699 auto initializer =
1700 MakeUnique<nsGenConInitializer>(std::move(node), nsGkAtoms::list_item);
1701 RefPtr<nsIContent> child =
1702 CreateGenConTextNode(aState, EmptyString(), std::move(initializer));
1703 aAddChild(child);
1704}
1705
1706// Frames for these may not be leaves in the proper sense, but we still don't
1707// want to expose generated content on them. For the purposes of the page they
1708// should be leaves.
1709static bool HasUAWidget(const Element& aOriginatingElement) {
1710 const ShadowRoot* sr = aOriginatingElement.GetShadowRoot();
1711 return sr && sr->IsUAWidget();
1712}
1713
1714static bool IsBaseAppearanceSelect(const Element& aElement) {
1715 if (const auto* select = HTMLSelectElement::FromNode(aElement)) {
1716 return select->IsBaseSelectAppearance();
1717 }
1718 return false;
1719}
1720
1721/*
1722 * aParentFrame - the frame that should be the parent of the generated
1723 * content. This is the frame for the corresponding content node,
1724 * which must not be a leaf frame.
1725 *
1726 * Any items created are added to aItems.
1727 *
1728 * We create an XML element (tag _moz_generated_content_before/after/marker)
1729 * representing the pseudoelement. We create a DOM node for each 'content'
1730 * item and make those nodes the children of the XML element. Then we create
1731 * a frame subtree for the XML element as if it were a regular child of
1732 * aParentFrame/aParentContent, giving the XML element the ::before, ::after
1733 * or ::marker style.
1734 */
1735void nsCSSFrameConstructor::CreateGeneratedContentItem(
1736 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
1737 Element& aOriginatingElement, ComputedStyle& aStyle,
1738 PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems,
1739 ItemFlags aExtraFlags) {
1740 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1741 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1742 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1743 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1744 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1745 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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1746 "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"
, 1746); 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, 1746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1747
1748 if (aPseudoElement != PseudoStyleType::Backdrop &&
1749 aPseudoElement != PseudoStyleType::PickerIcon &&
1750 HasUAWidget(aOriginatingElement) &&
1751 !aOriginatingElement.IsHTMLElement(nsGkAtoms::details) &&
1752 !IsBaseAppearanceSelect(aOriginatingElement)) {
1753 // ::before / ::after / ::marker shouldn't work on <video> / <input>.
1754 return;
1755 }
1756
1757 ServoStyleSet* styleSet = mPresShell->StyleSet();
1758
1759 // Probe for the existence of the pseudo-element.
1760 // |ProbePseudoElementStyle| checks the relevant properties for the pseudo.
1761 // It only returns a non-null value if the pseudo should exist.
1762 RefPtr<ComputedStyle> pseudoStyle = styleSet->ProbePseudoElementStyle(
1763 aOriginatingElement, aPseudoElement, nullptr, &aStyle);
1764 if (!pseudoStyle) {
1765 return;
1766 }
1767
1768 nsAtom* elemName = nullptr;
1769 nsAtom* property = nullptr;
1770 switch (aPseudoElement) {
1771 case PseudoStyleType::Before:
1772 elemName = nsGkAtoms::mozgeneratedcontentbefore;
1773 property = nsGkAtoms::beforePseudoProperty;
1774 break;
1775 case PseudoStyleType::After:
1776 elemName = nsGkAtoms::mozgeneratedcontentafter;
1777 property = nsGkAtoms::afterPseudoProperty;
1778 break;
1779 case PseudoStyleType::Marker:
1780 // We want to get a marker style even if we match no rules, but we still
1781 // want to check the result of GeneratedContentPseudoExists.
1782 elemName = nsGkAtoms::mozgeneratedcontentmarker;
1783 property = nsGkAtoms::markerPseudoProperty;
1784 break;
1785 case PseudoStyleType::Backdrop:
1786 elemName = nsGkAtoms::mozgeneratedcontentbackdrop;
1787 property = nsGkAtoms::backdropPseudoProperty;
1788 break;
1789 case PseudoStyleType::Checkmark:
1790 elemName = nsGkAtoms::mozgeneratedcontentcheckmark;
1791 property = nsGkAtoms::checkmarkPseudoProperty;
1792 break;
1793 case PseudoStyleType::PickerIcon:
1794 elemName = nsGkAtoms::mozgeneratedcontentpickericon;
1795 property = nsGkAtoms::pickerIconPseudoProperty;
1796 break;
1797 default:
1798 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"
, 1798); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected aPseudoElement" ")");
do { MOZ_CrashSequence(__null, 1798); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1799 }
1800
1801 auto flags = ItemFlags{ItemFlag::IsGeneratedContent} + aExtraFlags;
1802 if (aState.mCreatingExtraFrames) {
1803 // Extra frames (e.g. repeated table headers) share the pseudo-element of
1804 // the original frame, rather than creating a new one.
1805 RefPtr existing =
1806 static_cast<Element*>(aOriginatingElement.GetProperty(property));
1807 if (!existing || !existing->GetPrimaryFrame()) {
1808 return;
1809 }
1810 AddFrameConstructionItemsInternal(aState, existing, aParentFrame, true,
1811 existing->GetPrimaryFrame()->Style(),
1812 flags, aItems);
1813 return;
1814 }
1815
1816 RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
1817 elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
1818 RefPtr<Element> container;
1819 nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1820 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1821 return;
1822 }
1823
1824 // Cleared when the pseudo is unbound from the tree, so no need to store a
1825 // strong reference, nor a destructor.
1826 aOriginatingElement.SetProperty(property, container.get());
1827
1828 container->SetIsNativeAnonymousRoot();
1829 container->SetPseudoElementType(aPseudoElement);
1830
1831 BindContext context(aOriginatingElement, BindContext::ForNativeAnonymous);
1832 rv = container->BindToTree(context, aOriginatingElement);
1833 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1834 container->UnbindFromTree();
1835 return;
1836 }
1837
1838 if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
1839 container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
1840 }
1841
1842 // Servo has already eagerly computed the style for the container, so we can
1843 // just stick the style on the element and avoid an additional traversal.
1844 //
1845 // We don't do this for pseudos that may trigger animations or transitions,
1846 // since those need to be kicked off by the traversal machinery.
1847 //
1848 // Note that when a pseudo-element animates, we flag the originating element,
1849 // so we check that flag, but we could also a more expensive (but exhaustive)
1850 // check using EffectSet::GetEffectSet, for example.
1851 if (!Servo_ComputedValues_SpecifiesAnimationsOrTransitions(pseudoStyle) &&
1852 !aOriginatingElement.MayHaveAnimations()) {
1853 Servo_SetExplicitStyle(container, pseudoStyle);
1854 } else {
1855 // If animations are involved, we avoid the SetExplicitStyle optimization
1856 // above. We need to grab style with animations from the pseudo element and
1857 // replace old one.
1858 mPresShell->StyleSet()->StyleNewSubtree(container);
1859 pseudoStyle = ServoStyleSet::ResolveServoStyle(*container);
1860 }
1861 if (aPseudoElement != PseudoStyleType::Backdrop) {
1862 auto AppendChild = [&container, this](nsIContent* aChild) {
1863 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
1864 // here; it would get set under AppendChildTo. But AppendChildTo might
1865 // think that we're going from not being anonymous to being anonymous and
1866 // do some extra work; setting the flag here avoids that.
1867 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1868 container->AppendChildTo(aChild, false, IgnoreErrors());
1869 if (auto* childElement = Element::FromNode(aChild)) {
1870 // If we created any children elements, Servo needs to traverse them,
1871 // but the root is already set up.
1872 mPresShell->StyleSet()->StyleNewSubtree(childElement);
1873 }
1874 };
1875 auto items = pseudoStyle->StyleContent()->NonAltContentItems();
1876 size_t index = 0;
1877 for (const auto& item : items) {
1878 CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
1879 index++, AppendChild);
1880 }
1881 // If a ::marker has no 'content' then generate it from its 'list-style-*'.
1882 if (index == 0 && aPseudoElement == PseudoStyleType::Marker) {
1883 CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
1884 *pseudoStyle, AppendChild);
1885 }
1886 }
1887 AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
1888 pseudoStyle, flags, aItems);
1889}
1890
1891/****************************************************
1892 ** BEGIN TABLE SECTION
1893 ****************************************************/
1894
1895// The term pseudo frame is being used instead of anonymous frame, since
1896// anonymous frame has been used elsewhere to refer to frames that have
1897// generated content
1898
1899// Return whether the given frame is a table pseudo-frame. Note that
1900// cell-content and table-outer frames have pseudo-types, but are always
1901// created, even for non-anonymous cells and tables respectively. So for those
1902// we have to examine the cell or table frame to see whether it's a pseudo
1903// frame. In particular, a lone table caption will have a table wrapper as its
1904// parent, but will also trigger construction of an empty inner table, which
1905// will be the one we can examine to see whether the wrapper was a pseudo-frame.
1906static bool IsTablePseudo(nsIFrame* aFrame) {
1907 auto pseudoType = aFrame->Style()->GetPseudoType();
1908 if (pseudoType == PseudoStyleType::NotPseudo) {
1909 return false;
1910 }
1911 return pseudoType == PseudoStyleType::MozTable ||
1912 pseudoType == PseudoStyleType::MozInlineTable ||
1913 pseudoType == PseudoStyleType::MozTableColumnGroup ||
1914 pseudoType == PseudoStyleType::MozTableRowGroup ||
1915 pseudoType == PseudoStyleType::MozTableRow ||
1916 pseudoType == PseudoStyleType::MozTableCell ||
1917 (pseudoType == PseudoStyleType::MozCellContent &&
1918 aFrame->GetParent()->Style()->GetPseudoType() ==
1919 PseudoStyleType::MozTableCell) ||
1920 (pseudoType == PseudoStyleType::MozTableWrapper &&
1921 static_cast<nsTableWrapperFrame*>(aFrame)
1922 ->InnerTableFrame()
1923 ->Style()
1924 ->IsPseudoOrAnonBox());
1925}
1926
1927static bool IsRubyPseudo(nsIFrame* aFrame) {
1928 return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudoType());
1929}
1930
1931// Note that this is (subtly) different to ParentIsWrapperAnonBox, since
1932// ParentIsWrapperAnonBox is really just about restyles, but there are wrapper
1933// anon boxes that don't need to return true for that...
1934// FIXME(emilio): This should be less complicated, ParentIsWrapperAnonBox should
1935// probably be renamed to something else, and this should just use
1936// IsWrapperAnonBox or similar...
1937static bool IsWrapperPseudo(nsIFrame* aFrame) {
1938 auto pseudoType = aFrame->Style()->GetPseudoType();
1939 if (!PseudoStyle::IsAnonBox(pseudoType)) {
1940 return false;
1941 }
1942 return PseudoStyle::IsWrapperAnonBox(pseudoType) || IsTablePseudo(aFrame);
1943}
1944
1945static bool IsInAnonymousTable(nsIFrame* aFrame) {
1946 for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
1947 if (!IsWrapperPseudo(f)) {
1948 return false;
1949 }
1950 if (f->IsTableWrapperFrame()) {
1951 return true;
1952 }
1953 }
1954 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"
, 1954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Expected to be called inside tables"
")"); do { MOZ_CrashSequence(__null, 1954); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1955 return false;
1956}
1957
1958/* static */
1959nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType(
1960 LayoutFrameType aFrameType) {
1961 if (aFrameType == LayoutFrameType::Table) {
1962 return eTypeTable;
1963 }
1964 if (aFrameType == LayoutFrameType::TableRowGroup) {
1965 return eTypeRowGroup;
1966 }
1967 if (aFrameType == LayoutFrameType::TableRow) {
1968 return eTypeRow;
1969 }
1970 if (aFrameType == LayoutFrameType::TableColGroup) {
1971 return eTypeColGroup;
1972 }
1973 if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1974 return eTypeRubyBaseContainer;
1975 }
1976 if (aFrameType == LayoutFrameType::RubyTextContainer) {
1977 return eTypeRubyTextContainer;
1978 }
1979 if (aFrameType == LayoutFrameType::Ruby) {
1980 return eTypeRuby;
1981 }
1982
1983 return eTypeBlock;
1984}
1985
1986// Pull all the captions present in aItems out into aCaptions.
1987static void PullOutCaptionFrames(nsFrameList& aList, nsFrameList& aCaptions) {
1988 nsIFrame* child = aList.FirstChild();
1989 while (child) {
1990 nsIFrame* nextSibling = child->GetNextSibling();
1991 if (child->StyleDisplay()->mDisplay == StyleDisplay::TableCaption) {
1992 aList.RemoveFrame(child);
1993 aCaptions.AppendFrame(nullptr, child);
1994 }
1995 child = nextSibling;
1996 }
1997}
1998
1999// Construct the outer, inner table frames and the children frames for the
2000// table.
2001// XXX Page break frames for pseudo table frames are not constructed to avoid
2002// the risk associated with revising the pseudo frame mechanism. The long term
2003// solution of having frames handle page-break-before/after will solve the
2004// problem.
2005nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
2006 FrameConstructionItem& aItem,
2007 nsContainerFrame* aParentFrame,
2008 const nsStyleDisplay* aDisplay,
2009 nsFrameList& aFrameList) {
2010 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"
, 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2012); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
2011 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"
, 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2012); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
2012 "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"
, 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2012); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2013
2014 nsIContent* const content = aItem.mContent;
2015 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2016 const bool isMathMLContent = content->IsMathMLElement();
2017
2018 // create the pseudo SC for the table wrapper as a child of the inner SC
2019 RefPtr<ComputedStyle> outerComputedStyle =
2020 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2021 PseudoStyleType::MozTableWrapper, computedStyle);
2022
2023 // Create the table wrapper frame which holds the caption and inner table
2024 // frame
2025 nsContainerFrame* newFrame;
2026 if (isMathMLContent) {
2027 newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
2028 } else {
2029 newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
2030 }
2031
2032 nsContainerFrame* geometricParent = aState.GetGeometricParent(
2033 *outerComputedStyle->StyleDisplay(), aParentFrame);
2034
2035 // Init the table wrapper frame
2036 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2037
2038 // Create the inner table frame
2039 nsContainerFrame* innerFrame;
2040 if (isMathMLContent) {
2041 innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
2042 } else {
2043 innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
2044 }
2045
2046 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2047 innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2048
2049 // Put the newly created frames into the right child list
2050 SetInitialSingleChild(newFrame, innerFrame);
2051
2052 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
2053
2054 if (!mRootElementFrame) {
2055 mRootElementFrame = newFrame;
2056 }
2057
2058 nsFrameList childList;
2059
2060 // Process children
2061 nsFrameConstructorSaveState absoluteSaveState;
2062
2063 // Mark the table frame as an absolute container if needed
2064 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2065 if (newFrame->IsAbsPosContainingBlock()) {
2066 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2067 }
2068
2069 nsFrameConstructorSaveState floatSaveState;
2070 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
2071
2072 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2073 ConstructFramesFromItemList(
2074 aState, aItem.mChildItems, innerFrame,
2075 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2076 } else {
2077 ProcessChildren(aState, content, computedStyle, innerFrame, true, childList,
2078 false);
2079 }
2080
2081 nsFrameList captionList;
2082 PullOutCaptionFrames(childList, captionList);
2083
2084 // Set the inner table frame's principal child list.
2085 innerFrame->SetInitialChildList(FrameChildListID::Principal,
2086 std::move(childList));
2087
2088 // Append caption frames to the table wrapper frame's principal child list.
2089 if (captionList.NotEmpty()) {
2090 captionList.ApplySetParent(newFrame);
2091 newFrame->AppendFrames(FrameChildListID::Principal, std::move(captionList));
2092 }
2093
2094 return newFrame;
2095}
2096
2097static void MakeTablePartAbsoluteContainingBlock(
2098 nsFrameConstructorState& aState, nsFrameConstructorSaveState& aAbsSaveState,
2099 nsContainerFrame* aFrame) {
2100 // If we're positioned, then we need to become an absolute containing block
2101 // for any absolutely positioned children.
2102 aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2103 if (aFrame->IsAbsPosContainingBlock()) {
2104 aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2105 }
2106}
2107
2108nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
2109 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2110 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2111 nsFrameList& aFrameList) {
2112 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"
, 2116); 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, 2116); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2113 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"
, 2116); 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, 2116); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2114 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"
, 2116); 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, 2116); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2115 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"
, 2116); 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, 2116); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2116 "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"
, 2116); 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, 2116); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2117 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"
, 2118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2118); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2118 "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"
, 2118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2118); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2119 nsIContent* const content = aItem.mContent;
2120 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2121
2122 nsContainerFrame* newFrame;
2123 if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2124 if (content->IsMathMLElement()) {
2125 newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
2126 } else {
2127 newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
2128 }
2129 } else {
2130 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
2131 }
2132
2133 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2134
2135 nsFrameConstructorSaveState absoluteSaveState;
2136 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
2137
2138 nsFrameConstructorSaveState floatSaveState;
2139 aState.MaybePushFloatContainingBlock(newFrame, floatSaveState);
2140
2141 nsFrameList childList;
2142 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2143 ConstructFramesFromItemList(
2144 aState, aItem.mChildItems, newFrame,
2145 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2146 } else {
2147 ProcessChildren(aState, content, computedStyle, newFrame, true, childList,
2148 false);
2149 }
2150
2151 newFrame->SetInitialChildList(FrameChildListID::Principal,
2152 std::move(childList));
2153 aFrameList.AppendFrame(nullptr, newFrame);
2154 return newFrame;
2155}
2156
2157nsIFrame* nsCSSFrameConstructor::ConstructTableCol(
2158 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2159 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2160 nsFrameList& aFrameList) {
2161 nsIContent* const content = aItem.mContent;
2162 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2163
2164 nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
2165 InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2166
2167 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", 2167); MOZ_PretendNoReturn
(); } } while (0)
;
2168
2169 aFrameList.AppendFrame(nullptr, colFrame);
2170
2171 // construct additional col frames if the col frame has a span > 1
2172 int32_t span = colFrame->GetSpan();
2173 for (int32_t spanX = 1; spanX < span; spanX++) {
2174 nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
2175 InitAndRestoreFrame(aState, content, aParentFrame, newCol,
2176 AllowCounters::No);
2177 aFrameList.LastChild()->SetNextContinuation(newCol);
2178 newCol->SetPrevContinuation(aFrameList.LastChild());
2179 aFrameList.AppendFrame(nullptr, newCol);
2180 newCol->SetColType(eColAnonymousCol);
2181 }
2182
2183 return colFrame;
2184}
2185
2186nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
2187 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2188 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2189 nsFrameList& aFrameList) {
2190 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"
, 2190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableCell"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2190); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2191
2192 nsIContent* const content = aItem.mContent;
2193 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2194 const bool isMathMLContent = content->IsMathMLElement();
2195
2196 nsTableFrame* tableFrame =
2197 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2198 nsContainerFrame* cellFrame;
2199 // <mtable> is border separate in mathml.css and the MathML code doesn't
2200 // implement border collapse. For those users who style <mtable> with border
2201 // collapse, give them the default non-MathML table frames that understand
2202 // border collapse. This won't break us because MathML table frames are all
2203 // subclasses of the default table code, and so we can freely mix <mtable>
2204 // with <mtr> or <tr>, <mtd> or <td>. What will happen is just that non-MathML
2205 // frames won't understand MathML attributes and will therefore miss the
2206 // special handling that the MathML code does.
2207 if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
2208 cellFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
2209 } else {
2210 // Warning: If you change this and add a wrapper frame around table cell
2211 // frames, make sure Bug 368554 doesn't regress!
2212 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2213 cellFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
2214 }
2215
2216 // Initialize the table cell frame
2217 InitAndRestoreFrame(aState, content, aParentFrame, cellFrame);
2218 cellFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2219
2220 // Resolve pseudo style and initialize the body cell frame
2221 RefPtr<ComputedStyle> innerPseudoStyle =
2222 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2223 PseudoStyleType::MozCellContent, computedStyle);
2224
2225 nsContainerFrame* cellInnerFrame;
2226 nsContainerFrame* scrollFrame = nullptr;
2227 bool isScrollable = false;
2228 // Create a block frame that will format the cell's content
2229 if (isMathMLContent) {
2230 cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2231 } else {
2232 isScrollable = innerPseudoStyle->StyleDisplay()->IsScrollableOverflow() &&
2233 !aState.mPresContext->IsPaginated() &&
2234 StaticPrefs::layout_tables_scrollable_cells();
2235 if (isScrollable) {
2236 innerPseudoStyle = BeginBuildingScrollContainerFrame(
2237 aState, content, innerPseudoStyle, cellFrame, false, scrollFrame);
2238 }
2239 cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle);
2240 }
2241 auto* parent = scrollFrame ? scrollFrame : cellFrame;
2242 InitAndRestoreFrame(aState, content, parent, cellInnerFrame);
2243
2244 nsFrameConstructorSaveState absoluteSaveState;
2245 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, cellFrame);
2246
2247 nsFrameConstructorSaveState floatSaveState;
2248 aState.MaybePushFloatContainingBlock(cellInnerFrame, floatSaveState);
2249
2250 nsFrameList childList;
2251 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2252 AutoFrameConstructionPageName pageNameTracker(aState, cellInnerFrame);
2253 ConstructFramesFromItemList(
2254 aState, aItem.mChildItems, cellInnerFrame,
2255 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2256 } else {
2257 // Process the child content
2258 ProcessChildren(aState, content, computedStyle, cellInnerFrame, true,
2259 childList, !isMathMLContent);
2260 }
2261
2262 cellInnerFrame->SetInitialChildList(FrameChildListID::Principal,
2263 std::move(childList));
2264
2265 if (isScrollable) {
2266 FinishBuildingScrollContainerFrame(scrollFrame, cellInnerFrame);
2267 }
2268 SetInitialSingleChild(cellFrame, scrollFrame ? scrollFrame : cellInnerFrame);
2269 aFrameList.AppendFrame(nullptr, cellFrame);
2270 return cellFrame;
2271}
2272
2273static inline bool NeedFrameFor(const nsFrameConstructorState& aState,
2274 nsContainerFrame* aParentFrame,
2275 nsIContent* aChildContent) {
2276 // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2277 // Remove it once that's fixed.
2278 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2281); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2279 !aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2281); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2280 aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2281); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2281 "Why did we get called?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aChildContent->GetPrimaryFrame()->GetContent() != aChildContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
" (" "Why did we get called?" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2281); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2282
2283 // don't create a whitespace frame if aParentFrame doesn't want it.
2284 // always create frames for children in generated content. counter(),
2285 // quotes, and attr() content can easily change dynamically and we don't
2286 // want to be reconstructing frames. It's not even clear that these
2287 // should be considered ignorable just because they evaluate to
2288 // whitespace.
2289
2290 // We could handle all this in CreateNeededPseudoContainers or some other
2291 // place after we build our frame construction items, but that would involve
2292 // creating frame construction items for whitespace kids that ignores
2293 // white-space, where we know we'll be dropping them all anyway, and involve
2294 // an extra walk down the frame construction item list.
2295 auto excludesIgnorableWhitespace = [](nsIFrame* aParentFrame) {
2296 return aParentFrame->IsMathMLFrame();
2297 };
2298 if (!aParentFrame || !excludesIgnorableWhitespace(aParentFrame) ||
2299 aParentFrame->IsGeneratedContentFrame() || !aChildContent->IsText()) {
2300 return true;
2301 }
2302
2303 aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2304 NS_REFRAME_IF_WHITESPACE);
2305 return !aChildContent->TextIsOnlyWhitespace();
2306}
2307
2308/***********************************************
2309 * END TABLE SECTION
2310 ***********************************************/
2311
2312nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
2313 Element* aDocElement) {
2314 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", 2315
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2315 "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", 2315
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2316 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", 2317); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2317); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2317 "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", 2317); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2317); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2318
2319 // Ensure the document element is styled at this point.
2320 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2321 // construction from PresShell::Initialize.
2322 if (!aDocElement->HasServoData()) {
2323 mPresShell->StyleSet()->StyleNewSubtree(aDocElement);
2324 }
2325 aDocElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2326
2327 // Make sure to call UpdateViewportScrollStylesOverride before
2328 // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2329 // properly.
2330 DebugOnly<nsIContent*> propagatedScrollFrom;
2331 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2332 propagatedScrollFrom = presContext->UpdateViewportScrollStylesOverride();
2333 }
2334
2335 SetUpDocElementContainingBlock(aDocElement);
2336
2337 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"
, 2337); MOZ_PretendNoReturn(); } } while (0)
;
2338 nsFrameConstructorState state(
2339 mPresShell,
2340 GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2341 nullptr, nullptr);
2342
2343 RefPtr<ComputedStyle> computedStyle =
2344 ServoStyleSet::ResolveServoStyle(*aDocElement);
2345
2346 const nsStyleDisplay* display = computedStyle->StyleDisplay();
2347
2348 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2349
2350 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", 2353); MOZ_PretendNoReturn
(); } } while (0)
2351 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", 2353); MOZ_PretendNoReturn
(); } } while (0)
2352 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", 2353); MOZ_PretendNoReturn
(); } } while (0)
2353 "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", 2353); MOZ_PretendNoReturn
(); } } while (0)
;
2354
2355 if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)(__builtin_expect(!!(display->mDisplay == StyleDisplay::None
), 0))
) {
2356 return nullptr;
2357 }
2358
2359 // This implements "The Principal Writing Mode".
2360 // https://drafts.csswg.org/css-writing-modes-3/#principal-flow
2361 //
2362 // If there's a <body> element in an HTML document, its writing-mode,
2363 // direction, and text-orientation override the root element's used value.
2364 //
2365 // We need to copy <body>'s WritingMode to mDocElementContainingBlock before
2366 // construct mRootElementFrame so that anonymous internal frames such as
2367 // <html> with table style can copy their parent frame's mWritingMode in
2368 // nsIFrame::Init().
2369 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"
, 2371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2371); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2370 "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"
, 2371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2371); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2371 "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"
, 2371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2371); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2372
2373 const WritingMode propagatedWM = [&] {
2374 const WritingMode rootWM(computedStyle);
2375 if (computedStyle->StyleDisplay()->IsContainAny()) {
2376 return rootWM;
2377 }
2378 Element* body = mDocument->GetBodyElement();
2379 if (!body) {
2380 return rootWM;
2381 }
2382 RefPtr<ComputedStyle> bodyStyle = ResolveComputedStyle(body);
2383 if (bodyStyle->StyleDisplay()->IsContainAny()) {
2384 return rootWM;
2385 }
2386 const WritingMode bodyWM(bodyStyle);
2387 if (bodyWM != rootWM) {
2388 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Layout"_ns,
2389 mDocument,
2390 PropertiesFile::LAYOUT_PROPERTIES,
2391 "PrincipalWritingModePropagationWarning");
2392 }
2393 return bodyWM;
2394 }();
2395
2396 mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
2397 propagatedWM);
2398
2399 // Push the absolute containing block now so we can absolutely position the
2400 // root element
2401 nsFrameConstructorSaveState canvasCbSaveState;
2402 mCanvasFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2403
2404 state.PushAbsoluteContainingBlock(mCanvasFrame, mCanvasFrame,
2405 canvasCbSaveState);
2406
2407 nsFrameConstructorSaveState docElementCbSaveState;
2408 if (mCanvasFrame != mDocElementContainingBlock) {
2409 mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2410 state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2411 mDocElementContainingBlock,
2412 docElementCbSaveState);
2413 }
2414
2415 // The rules from CSS 2.1, section 9.2.4, have already been applied
2416 // by the style system, so we can assume that display->mDisplay is
2417 // either NONE, BLOCK, or TABLE.
2418
2419 // contentFrame is the primary frame for the root element. frameList contains
2420 // the children of the initial containing block.
2421 //
2422 // The first of those frames is usually `contentFrame`, but it can be
2423 // different, in particular if the root frame is positioned, in which case
2424 // contentFrame is the out-of-flow frame and frameList.FirstChild() is the
2425 // placeholder.
2426 //
2427 // The rest of the frames in frameList are the anonymous content of the canvas
2428 // frame.
2429 nsContainerFrame* contentFrame;
2430 nsFrameList frameList;
2431 bool processChildren = false;
2432
2433 nsFrameConstructorSaveState absoluteSaveState;
2434
2435 if (aDocElement->IsSVGElement()) {
2436 if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2437 return nullptr;
2438 }
2439 // We're going to call the right function ourselves, so no need to give a
2440 // function to this FrameConstructionData.
2441
2442 // XXXbz on the other hand, if we converted this whole function to
2443 // FrameConstructionData/Item, then we'd need the right function
2444 // here... but would probably be able to get away with less code in this
2445 // function in general.
2446 static constexpr FrameConstructionData rootSVGData;
2447 AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
2448 do_AddRef(computedStyle), true);
2449
2450 contentFrame = static_cast<nsContainerFrame*>(ConstructOuterSVG(
2451 state, item, mDocElementContainingBlock, display, frameList));
2452 } else if (display->mDisplay == StyleDisplay::Flex ||
2453 display->mDisplay == StyleDisplay::WebkitBox ||
2454 display->mDisplay == StyleDisplay::Grid ||
2455 display->mDisplay == StyleDisplay::GridLanes) {
2456 auto func = [&] {
2457 if (display->mDisplay == StyleDisplay::Grid ||
2458 display->mDisplay == StyleDisplay::GridLanes) {
2459 return NS_NewGridContainerFrame;
2460 }
2461 return NS_NewFlexContainerFrame;
2462 }();
2463 contentFrame = func(mPresShell, computedStyle);
2464 InitAndRestoreFrame(
2465 state, aDocElement,
2466 state.GetGeometricParent(*display, mDocElementContainingBlock),
2467 contentFrame);
2468 state.AddChild(contentFrame, frameList, aDocElement,
2469 mDocElementContainingBlock);
2470 processChildren = true;
2471
2472 contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2473 if (contentFrame->IsAbsPosContainingBlock()) {
2474 state.PushAbsoluteContainingBlock(contentFrame, contentFrame,
2475 absoluteSaveState);
2476 }
2477 } else if (display->mDisplay == StyleDisplay::Table) {
2478 // We're going to call the right function ourselves, so no need to give a
2479 // function to this FrameConstructionData.
2480
2481 // XXXbz on the other hand, if we converted this whole function to
2482 // FrameConstructionData/Item, then we'd need the right function
2483 // here... but would probably be able to get away with less code in this
2484 // function in general.
2485 static constexpr FrameConstructionData rootTableData;
2486 AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
2487 do_AddRef(computedStyle), true);
2488
2489 // if the document is a table then just populate it.
2490 contentFrame = static_cast<nsContainerFrame*>(ConstructTable(
2491 state, item, mDocElementContainingBlock, display, frameList));
2492 } else if (display->DisplayInside() == StyleDisplayInside::Ruby) {
2493 static constexpr FrameConstructionData data(
2494 &nsCSSFrameConstructor::ConstructBlockRubyFrame);
2495 AutoFrameConstructionItem item(this, &data, aDocElement,
2496 do_AddRef(computedStyle), true);
2497 contentFrame = static_cast<nsContainerFrame*>(ConstructBlockRubyFrame(
2498 state, item,
2499 state.GetGeometricParent(*display, mDocElementContainingBlock), display,
2500 frameList));
2501 } else {
2502 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"
, 2504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2504); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2503 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"
, 2504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2504); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2504 "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"
, 2504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2504); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2505 contentFrame = NS_NewBlockFrame(mPresShell, computedStyle);
2506 ConstructBlock(
2507 state, aDocElement,
2508 state.GetGeometricParent(*display, mDocElementContainingBlock),
2509 mDocElementContainingBlock, computedStyle, &contentFrame, frameList,
2510 contentFrame->IsAbsPosContainingBlock() ? contentFrame : nullptr);
2511 }
2512
2513 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", 2513); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "frameList.FirstChild()" ")"); do { MOZ_CrashSequence
(__null, 2513); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2514 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"
, 2514); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameList.FirstChild()->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2514); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2515 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"
, 2515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentFrame"
")"); do { MOZ_CrashSequence(__null, 2515); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2516
2517 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"
, 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2519); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2518 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"
, 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2519); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2519 "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"
, 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2519); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2520 if (processChildren) {
2521 mRootElementFrame = contentFrame;
2522 }
2523
2524 // Figure out which frame has the main style for the document element,
2525 // assigning it to mRootElementStyleFrame.
2526 // Backgrounds should be propagated from that frame to the viewport.
2527 contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
2528 bool isChild = mRootElementStyleFrame &&
2529 mRootElementStyleFrame->GetParent() == contentFrame;
2530 if (!isChild) {
2531 mRootElementStyleFrame = mRootElementFrame;
2532 }
2533
2534 if (processChildren) {
2535 // Still need to process the child content
2536 nsFrameList childList;
2537
2538 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", 2540); MOZ_PretendNoReturn
(); } } while (0)
2539 !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", 2540); MOZ_PretendNoReturn
(); } } while (0)
2540 "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", 2540); MOZ_PretendNoReturn
(); } } while (0)
;
2541
2542 nsFrameConstructorSaveState floatSaveState;
2543 state.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
2544
2545 ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
2546 childList, false);
2547
2548 // Set the initial child lists
2549 contentFrame->SetInitialChildList(FrameChildListID::Principal,
2550 std::move(childList));
2551 }
2552
2553 nsIFrame* newFrame = frameList.FirstChild();
2554 // set the primary frame
2555 aDocElement->SetPrimaryFrame(contentFrame);
2556 mDocElementContainingBlock->AppendFrames(FrameChildListID::Principal,
2557 std::move(frameList));
2558
2559 // NOTE(emilio): This is in the reverse order compared to normal anonymous
2560 // children. We usually generate anonymous kids first, then non-anonymous,
2561 // but we generate the doc element frame the other way around. This is fine
2562 // either way, but generating anonymous children in a different order requires
2563 // changing nsCanvasFrame (and a whole lot of other potentially unknown code)
2564 // to look at the last child to find the root frame rather than the first
2565 // child.
2566 ConstructAnonymousContentForRoot(state, mCanvasFrame,
2567 mRootElementFrame->GetContent(), frameList);
2568 mCanvasFrame->AppendFrames(FrameChildListID::Principal, std::move(frameList));
2569
2570 return newFrame;
2571}
2572
2573RestyleManager* nsCSSFrameConstructor::RestyleManager() const {
2574 return mPresShell->GetPresContext()->RestyleManager();
2575}
2576
2577ViewportFrame* nsCSSFrameConstructor::ConstructRootFrame() {
2578 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ConstructRootFrame",mozilla::AutoProfilerLabelHot raiiObject2579( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
2579 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject2579( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
2580 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
2581
2582 ServoStyleSet* styleSet = mPresShell->StyleSet();
2583
2584 // --------- BUILD VIEWPORT -----------
2585 RefPtr<ComputedStyle> viewportPseudoStyle =
2586 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2587 PseudoStyleType::MozViewport);
2588 ViewportFrame* viewportFrame =
2589 NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2590
2591 // XXXbz do we _have_ to pass a null content pointer to that frame?
2592 // Would it really kill us to pass in the root element or something?
2593 // What would that break?
2594 viewportFrame->Init(nullptr, nullptr, nullptr);
2595
2596 viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2597
2598 mPresShell->SetNeedsWindowPropertiesSync();
2599
2600 // Make it an absolute container for fixed-pos elements
2601 viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2602 viewportFrame->MarkAsAbsoluteContainingBlock();
2603
2604 return viewportFrame;
2605}
2606
2607void nsCSSFrameConstructor::SetUpDocElementContainingBlock(
2608 nsIContent* aDocElement) {
2609 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"
, 2609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement"
") (" "No element?" ")"); do { MOZ_CrashSequence(__null, 2609
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2610 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"
, 2610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aDocElement->GetParent()"
") (" "Not root content?" ")"); do { MOZ_CrashSequence(__null
, 2610); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2611 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", 2611
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()"
") (" "Not in a document?" ")"); do { MOZ_CrashSequence(__null
, 2611); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2612 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"
, 2613); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2613); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2613 "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"
, 2613); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2613); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2614
2615 /*
2616 how the root frame hierarchy should look
2617
2618 Galley presentation, with scrolling:
2619
2620 ViewportFrame [fixed-cb]
2621 ScrollContainerFrame (if needed)
2622 nsCanvasFrame [abs-cb]
2623 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2624 nsTableWrapperFrame, nsPlaceholderFrame,
2625 nsFlexContainerFrame, nsGridContainerFrame)
2626
2627 Print presentation, non-XUL
2628
2629 ViewportFrame
2630 nsCanvasFrame
2631 nsPageSequenceFrame
2632 PrintedSheetFrame
2633 nsPageFrame
2634 nsPageContentFrame [fixed-cb]
2635 nsCanvasFrame [abs-cb]
2636 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2637 nsTableWrapperFrame, nsPlaceholderFrame,
2638 nsFlexContainerFrame,
2639 nsGridContainerFrame)
2640
2641 Print-preview presentation, non-XUL
2642
2643 ViewportFrame
2644 ScrollContainerFrame
2645 nsCanvasFrame
2646 nsPageSequenceFrame
2647 PrintedSheetFrame
2648 nsPageFrame
2649 nsPageContentFrame [fixed-cb]
2650 nsCanvasFrame [abs-cb]
2651 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2652 nsTableWrapperFrame,
2653 nsPlaceholderFrame,
2654 nsFlexContainerFrame,
2655 nsGridContainerFrame)
2656
2657 Print/print preview of XUL is not supported.
2658 [fixed-cb]: the default containing block for fixed-pos content
2659 [abs-cb]: the default containing block for abs-pos content
2660
2661 Meaning of nsCSSFrameConstructor fields:
2662 mRootElementFrame is "root element frame". This is the primary frame for
2663 the root element.
2664 mDocElementContainingBlock is the parent of mRootElementFrame
2665 (i.e. nsCanvasFrame)
2666 mPageSequenceFrame is the nsPageSequenceFrame, or null if there isn't
2667 one
2668 */
2669
2670 // --------- CREATE ROOT FRAME -------
2671
2672 // Create the root frame. The document element's frame is a child of the
2673 // root frame.
2674 //
2675 // The root frame serves two purposes:
2676 // - reserves space for any margins needed for the document element's frame
2677 // - renders the document element's background. This ensures the background
2678 // covers the entire canvas as specified by the CSS2 spec
2679
2680 nsPresContext* presContext = mPresShell->GetPresContext();
2681 const bool isPaginated = presContext->IsRootPaginatedDocument();
2682
2683 const bool isHTML = aDocElement->IsHTMLElement();
2684 const bool isXUL = !isHTML && aDocElement->IsXULElement();
2685
2686 const bool isScrollable = [&] {
2687 if (isPaginated) {
2688 return presContext->HasPaginatedScrolling();
2689 }
2690 // Never create scrollbars for XUL documents or top level XHTML documents
2691 // that disable scrolling.
2692 if (isXUL) {
2693 return false;
2694 }
2695 if (aDocElement->OwnerDoc()->ChromeRulesEnabled() &&
2696 aDocElement->AsElement()->AttrValueIs(
2697 kNameSpaceID_None, nsGkAtoms::scrolling, nsGkAtoms::_false,
2698 eCaseMatters)) {
2699 return false;
2700 }
2701 return true;
2702 }();
2703
2704 nsContainerFrame* viewportFrame =
2705 static_cast<nsContainerFrame*>(GetRootFrame());
2706 ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
2707
2708 nsCanvasFrame* rootCanvasFrame =
2709 NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2710 mCanvasFrame = rootCanvasFrame;
2711 mDocElementContainingBlock = rootCanvasFrame;
2712
2713 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2714
2715 // If the device supports scrolling (e.g., in galley mode on the screen and
2716 // for print-preview, but not when printing), then create a scroll frame that
2717 // will act as the scrolling mechanism for the viewport.
2718 // XXX Do we even need a viewport when printing to a printer?
2719
2720 // We no longer need to do overflow propagation here. It's taken care of
2721 // when we construct frames for the element whose overflow might be
2722 // propagated
2723 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", 2724); MOZ_PretendNoReturn
(); } } while (0)
2724 "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", 2724); MOZ_PretendNoReturn
(); } } while (0)
;
2725
2726 nsContainerFrame* newFrame = rootCanvasFrame;
2727 RefPtr<ComputedStyle> rootPseudoStyle;
2728 // we must create a state because if the scrollbars are GFX it needs the
2729 // state to build the scrollbar frames.
2730 nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
2731
2732 // Start off with the viewport as parent; we'll adjust it as needed.
2733 nsContainerFrame* parentFrame = viewportFrame;
2734
2735 ServoStyleSet* styleSet = mPresShell->StyleSet();
2736 // If paginated, make sure we don't put scrollbars in
2737 if (!isScrollable) {
2738 rootPseudoStyle = styleSet->ResolveNonInheritingAnonymousBoxStyle(
2739 PseudoStyleType::MozCanvas);
2740 } else {
2741 // Build the frame. We give it the content we are wrapping which is the
2742 // document element, the root frame, the parent view port frame, and we
2743 // should get back the new frame and the scrollable view if one was
2744 // created.
2745
2746 // Resolve a style for the scrollframe
2747 RefPtr<ComputedStyle> computedStyle =
2748 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2749 PseudoStyleType::MozViewportScroll);
2750
2751 newFrame = nullptr;
2752 rootPseudoStyle = BeginBuildingScrollContainerFrame(
2753 state, aDocElement, computedStyle, viewportFrame, true, newFrame);
2754 parentFrame = newFrame;
2755 }
2756
2757 rootCanvasFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
2758 rootCanvasFrame->Init(aDocElement, parentFrame, nullptr);
2759
2760 if (isScrollable) {
2761 FinishBuildingScrollContainerFrame(parentFrame, rootCanvasFrame);
2762 }
2763
2764 if (isPaginated) {
2765 // Create a page sequence frame
2766 {
2767 RefPtr<ComputedStyle> pageSequenceStyle =
2768 styleSet->ResolveInheritingAnonymousBoxStyle(
2769 PseudoStyleType::MozPageSequence, viewportPseudoStyle);
2770 mPageSequenceFrame =
2771 NS_NewPageSequenceFrame(mPresShell, pageSequenceStyle);
2772 mPageSequenceFrame->Init(aDocElement, rootCanvasFrame, nullptr);
2773 SetInitialSingleChild(rootCanvasFrame, mPageSequenceFrame);
2774 }
2775
2776 // Create the first printed sheet frame, as the sole child (for now) of our
2777 // page sequence frame (mPageSequenceFrame).
2778 auto* printedSheetFrame =
2779 ConstructPrintedSheetFrame(mPresShell, mPageSequenceFrame, nullptr);
2780 SetInitialSingleChild(mPageSequenceFrame, printedSheetFrame);
2781
2782 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", 2783
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2783); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2783 "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", 2783
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2783); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2784
2785 // Create the first page, as the sole child (for now) of the printed sheet
2786 // frame that we just created.
2787 nsCanvasFrame* canvasFrame;
2788 nsContainerFrame* pageFrame =
2789 ConstructPageFrame(mPresShell, printedSheetFrame, nullptr, canvasFrame);
2790 pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2791 SetInitialSingleChild(printedSheetFrame, pageFrame);
2792
2793 // The eventual parent of the document element frame.
2794 // XXX should this be set for every new page (in ConstructPageFrame)?
2795 mDocElementContainingBlock = canvasFrame;
2796 }
2797
2798 if (viewportFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
2799 SetInitialSingleChild(viewportFrame, newFrame);
2800 } else {
2801 viewportFrame->AppendFrames(FrameChildListID::Principal,
2802 nsFrameList(newFrame, newFrame));
2803 }
2804
2805 if (ScrollContainerFrame* rootScroll = do_QueryFrame(newFrame)) {
2806 if (nsCOMPtr state = mPresShell->GetDocument()->GetLayoutHistoryState();
2807 state && state->HasStates()) {
2808 rootScroll->RestoreState(state.get());
2809 }
2810 }
2811}
2812
2813void nsCSSFrameConstructor::ConstructAnonymousContentForRoot(
2814 nsFrameConstructorState& aState, nsContainerFrame* aCanvasFrame,
2815 nsIContent* aDocElement, nsFrameList& aFrameList) {
2816 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", 2816); MOZ_PretendNoReturn
(); } } while (0)
;
2817 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", 2817); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mRootElementFrame->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2817); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2818
2819 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2820 GetAnonymousContent(aDocElement, aCanvasFrame, anonymousItems);
2821
2822 // If we get here, we are rebuilding the anonymous content of the root
2823 // element. In this case, we also need to deal with the custom content
2824 // container.
2825 if (auto* container =
2826 aState.mPresContext->Document()->GetCustomContentContainer()) {
2827 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2828 // construction from PresShell::Initialize. See the similar code-path in
2829 // ConstructDocElementFrame.
2830 if (!container->HasServoData()) {
2831 mPresShell->StyleSet()->StyleNewSubtree(container);
2832 }
2833 anonymousItems.AppendElement(container);
2834 }
2835
2836 if (anonymousItems.IsEmpty()) {
2837 return;
2838 }
2839
2840 AutoFrameConstructionItemList itemsToConstruct(this);
2841 AutoFrameConstructionPageName pageNameTracker(aState, aCanvasFrame);
2842 AddFCItemsForAnonymousContent(aState, aCanvasFrame, anonymousItems,
2843 itemsToConstruct, pageNameTracker);
2844 ConstructFramesFromItemList(aState, itemsToConstruct, aCanvasFrame,
2845 /* aParentIsWrapperAnonBox = */ false,
2846 aFrameList);
2847}
2848
2849PrintedSheetFrame* nsCSSFrameConstructor::ConstructPrintedSheetFrame(
2850 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2851 nsIFrame* aPrevSheetFrame) {
2852 RefPtr<ComputedStyle> printedSheetPseudoStyle =
2853 aPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
2854 PseudoStyleType::MozPrintedSheet);
2855
2856 auto* printedSheetFrame =
2857 NS_NewPrintedSheetFrame(aPresShell, printedSheetPseudoStyle);
2858
2859 printedSheetFrame->Init(nullptr, aParentFrame, aPrevSheetFrame);
2860
2861 return printedSheetFrame;
2862}
2863
2864nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
2865 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2866 nsIFrame* aPrevPageFrame, nsCanvasFrame*& aCanvasFrame) {
2867 ServoStyleSet* styleSet = aPresShell->StyleSet();
2868
2869 RefPtr<ComputedStyle> pagePseudoStyle =
2870 styleSet->ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::MozPage);
2871
2872 nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2873
2874 // Initialize the page frame and force it to have a view. This makes printing
2875 // of the pages easier and faster.
2876 pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2877
2878 RefPtr<const nsAtom> pageName;
2879 if (mNextPageContentFramePageName) {
2880 pageName = mNextPageContentFramePageName.forget();
2881 } else if (aPrevPageFrame) {
2882 pageName = aPrevPageFrame->ComputePageValue();
2883 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", 2884
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2884 "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", 2884
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2885 }
2886 RefPtr<ComputedStyle> pageContentPseudoStyle =
2887 styleSet->ResolvePageContentStyle(pageName,
2888 StylePagePseudoClassFlags::NONE);
2889
2890 nsContainerFrame* pageContentFrame = NS_NewPageContentFrame(
2891 aPresShell, pageContentPseudoStyle, pageName.forget());
2892
2893 nsPageContentFrame* prevPageContentFrame = nullptr;
2894 if (aPrevPageFrame) {
2895 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"
, 2895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevPageFrame->IsPageFrame()"
")"); do { MOZ_CrashSequence(__null, 2895); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2896 prevPageContentFrame =
2897 static_cast<nsPageFrame*>(aPrevPageFrame)->PageContentFrame();
2898 }
2899 pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2900 if (!prevPageContentFrame) {
2901 // The canvas is an inheriting anon box, so needs to be "owned" by the page
2902 // content.
2903 pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES |
2904 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2905 // Make it an absolute container for fixed-pos elements
2906 pageContentFrame->MarkAsAbsoluteContainingBlock();
2907 } else {
2908 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"
, 2911); 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, 2911
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2909 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"
, 2911); 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, 2911
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2910 "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"
, 2911); 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, 2911
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2911 "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"
, 2911); 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, 2911
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2912 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"
, 2914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2914
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2913 "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"
, 2914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2914
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2914 "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"
, 2914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2914
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2915 }
2916 SetInitialSingleChild(pageFrame, pageContentFrame);
2917
2918 RefPtr<ComputedStyle> canvasPseudoStyle =
2919 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2920 PseudoStyleType::MozCanvas);
2921 aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2922
2923 nsIFrame* prevCanvasFrame = nullptr;
2924 if (prevPageContentFrame) {
2925 prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
2926 NS_ASSERTION(prevCanvasFrame, "missing canvas frame")do { if (!(prevCanvasFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "missing canvas frame", "prevCanvasFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2926); MOZ_PretendNoReturn(); } } while (0)
;
2927 }
2928 aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
2929 SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2930 return pageFrame;
2931}
2932
2933/* static */
2934nsIFrame* nsCSSFrameConstructor::CreatePlaceholderFrameFor(
2935 PresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame,
2936 nsContainerFrame* aParentFrame, nsIFrame* aPrevInFlow,
2937 nsFrameState aTypeBit) {
2938 RefPtr<ComputedStyle> placeholderStyle =
2939 aPresShell->StyleSet()->ResolveStyleForPlaceholder();
2940
2941 // The placeholder frame gets a pseudo style.
2942 nsPlaceholderFrame* placeholderFrame =
2943 NS_NewPlaceholderFrame(aPresShell, placeholderStyle, aTypeBit);
2944
2945 placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2946
2947 // Associate the placeholder/out-of-flow with each other.
2948 placeholderFrame->SetOutOfFlowFrame(aFrame);
2949 aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
2950
2951 aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2952
2953 return placeholderFrame;
2954}
2955
2956// Clears any lazy bits set in the range [aStartContent, aEndContent). If
2957// aEndContent is null, that means to clear bits in all siblings starting with
2958// aStartContent. aStartContent must not be null unless aEndContent is also
2959// null. We do this so that when new children are inserted under elements whose
2960// frame is a leaf the new children don't cause us to try to construct frames
2961// for the existing children again.
2962static inline void ClearLazyBits(nsIContent* aStartContent,
2963 nsIContent* aEndContent) {
2964 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", 2965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2965); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2965 "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", 2965
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2965); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2966
2967 for (nsIContent* cur = aStartContent; cur != aEndContent;
2968 cur = cur->GetNextSibling()) {
2969 cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2970 }
2971}
2972
2973/* static */
2974const nsCSSFrameConstructor::FrameConstructionData*
2975nsCSSFrameConstructor::FindSelectData(const Element& aElement,
2976 ComputedStyle& aStyle) {
2977 // Construct a frame-based listbox or combobox
2978 const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
2979 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"
, 2979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sel" ")"); do
{ MOZ_CrashSequence(__null, 2979); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2980 switch (aStyle.StyleDisplay()->EffectiveAppearance()) {
2981 case StyleAppearance::Base:
2982 case StyleAppearance::BaseSelect:
2983 return nullptr;
2984 default:
2985 break;
2986 }
2987 if (sel->IsCombobox()) {
2988 static constexpr FrameConstructionData sComboboxData{
2989 ToCreationFunc(NS_NewComboboxControlFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewComboboxControlFrame(aPs, aStyle); }
};
2990 return &sComboboxData;
2991 }
2992 // FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
2993 // and reuse ConstructScrollableBlock or so?
2994 static constexpr FrameConstructionData sListBoxData{
2995 &nsCSSFrameConstructor::ConstructListBoxSelectFrame};
2996 return &sListBoxData;
2997}
2998
2999nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
3000 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3001 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3002 nsFrameList& aFrameList) {
3003 nsContainerFrame* listFrame =
3004 NS_NewListControlFrame(mPresShell, aItem.mComputedStyle);
3005 InitAndRestoreFrame(aState, aItem.mContent,
3006 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3007 listFrame);
3008 ConstructScrollableBlockWithScrollContainer(
3009 aState, aItem, aParentFrame, aStyleDisplay, aFrameList, listFrame);
3010 return listFrame;
3011}
3012
3013nsIFrame* nsCSSFrameConstructor::ConstructTextControl(
3014 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3015 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3016 nsFrameList& aFrameList) {
3017 nsContainerFrame* tcf =
3018 NS_NewTextControlFrame(mPresShell, aItem.mComputedStyle);
3019 InitAndRestoreFrame(aState, aItem.mContent,
3020 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3021 tcf);
3022 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
3023 aStyleDisplay, aFrameList, tcf);
3024 return tcf;
3025}
3026
3027nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
3028 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3029 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3030 nsFrameList& aFrameList) {
3031 AutoRestore<bool> savedHasRenderedLegend(aState.mHasRenderedLegend);
3032 aState.mHasRenderedLegend = false;
3033 nsIContent* const content = aItem.mContent;
3034 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3035
3036 nsContainerFrame* fieldsetFrame =
3037 NS_NewFieldSetFrame(mPresShell, computedStyle);
3038
3039 // Initialize it
3040 InitAndRestoreFrame(aState, content,
3041 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3042 fieldsetFrame);
3043
3044 fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3045
3046 // Resolve style and initialize the frame
3047 RefPtr<ComputedStyle> fieldsetContentStyle =
3048 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3049 PseudoStyleType::MozFieldsetContent, computedStyle);
3050
3051 const nsStyleDisplay* fieldsetContentDisplay =
3052 fieldsetContentStyle->StyleDisplay();
3053 const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3054 nsContainerFrame* scrollFrame = nullptr;
3055 if (isScrollable) {
3056 fieldsetContentStyle =
3057 BeginBuildingScrollContainerFrame(aState, content, fieldsetContentStyle,
3058 fieldsetFrame, false, scrollFrame);
3059 }
3060
3061 // Create the inner ::-moz-fieldset-content frame.
3062 nsContainerFrame* contentFrameTop;
3063 nsContainerFrame* contentFrame;
3064 auto* parent = scrollFrame ? scrollFrame : fieldsetFrame;
3065 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", 3066); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3066); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3066 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", 3066); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3066); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3067 switch (fieldsetContentDisplay->DisplayInside()) {
3068 case StyleDisplayInside::Flex:
3069 contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3070 InitAndRestoreFrame(aState, content, parent, contentFrame);
3071 contentFrameTop = contentFrame;
3072 break;
3073 case StyleDisplayInside::Grid:
3074 contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3075 InitAndRestoreFrame(aState, content, parent, contentFrame);
3076 contentFrameTop = contentFrame;
3077 break;
3078 default: {
3079 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", 3080); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3080); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3080 "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", 3080); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3080); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3081
3082 contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle);
3083 if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) {
3084 contentFrameTop = BeginBuildingColumns(
3085 aState, content, parent, contentFrame, fieldsetContentStyle);
3086 } else {
3087 // No need to create column container. Initialize content frame.
3088 InitAndRestoreFrame(aState, content, parent, contentFrame);
3089 contentFrameTop = contentFrame;
3090 }
3091
3092 break;
3093 }
3094 }
3095
3096 aState.AddChild(fieldsetFrame, aFrameList, content, aParentFrame);
3097
3098 // Process children
3099 nsFrameConstructorSaveState absoluteSaveState;
3100 nsFrameList childList;
3101
3102 contentFrameTop->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3103 if (fieldsetFrame->IsAbsPosContainingBlock()) {
3104 aState.PushAbsoluteContainingBlock(contentFrameTop, fieldsetFrame,
3105 absoluteSaveState);
3106 }
3107
3108 nsFrameConstructorSaveState floatSaveState;
3109 aState.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
3110
3111 ProcessChildren(aState, content, computedStyle, contentFrame, true, childList,
3112 true);
3113 nsFrameList fieldsetKids;
3114 fieldsetKids.AppendFrame(nullptr,
3115 scrollFrame ? scrollFrame : contentFrameTop);
3116
3117 if (!MayNeedToCreateColumnSpanSiblings(contentFrame, childList)) {
3118 // Set the inner frame's initial child lists.
3119 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3120 std::move(childList));
3121 } else {
3122 // Extract any initial non-column-span kids, and put them in inner frame's
3123 // child list.
3124 nsFrameList initialNonColumnSpanKids =
3125 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
3126 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3127 std::move(initialNonColumnSpanKids));
3128
3129 if (childList.NotEmpty()) {
3130 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
3131 aState, contentFrame, childList,
3132 // Column content should never be a absolute/fixed positioned
3133 // containing block. Pass nullptr as aPositionedFrame.
3134 nullptr);
3135 FinishBuildingColumns(aState, contentFrameTop, contentFrame,
3136 columnSpanSiblings);
3137 }
3138 }
3139
3140 if (isScrollable) {
3141 FinishBuildingScrollContainerFrame(scrollFrame, contentFrameTop);
3142 }
3143
3144 // We use AppendFrames here because the rendered legend will already
3145 // be present in the principal child list if it exists.
3146 fieldsetFrame->AppendFrames(FrameChildListID::NoReflowPrincipal,
3147 std::move(fieldsetKids));
3148
3149 return fieldsetFrame;
3150}
3151
3152const nsCSSFrameConstructor::FrameConstructionData*
3153nsCSSFrameConstructor::FindDetailsData(const Element& aElement,
3154 ComputedStyle& aStyle) {
3155 if (!StaticPrefs::layout_details_force_block_layout()) {
3156 return nullptr;
3157 }
3158 static constexpr FrameConstructionData sBlockData[2] = {
3159 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3160 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3161 };
3162 return &sBlockData[aStyle.StyleDisplay()->IsScrollableOverflow()];
3163}
3164
3165nsIFrame* nsCSSFrameConstructor::ConstructBlockRubyFrame(
3166 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3167 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3168 nsFrameList& aFrameList) {
3169 nsIContent* const content = aItem.mContent;
3170 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3171
3172 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, computedStyle);
3173 nsContainerFrame* newFrame = blockFrame;
3174 nsContainerFrame* geometricParent =
3175 aState.GetGeometricParent(*aStyleDisplay, aParentFrame);
3176 AutoFrameConstructionPageName pageNameTracker(aState, blockFrame);
3177 if ((aItem.mFCData->mBits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3178 aStyleDisplay->IsScrollableOverflow()) {
3179 nsContainerFrame* scrollframe = nullptr;
3180 BuildScrollContainerFrame(aState, content, computedStyle, blockFrame,
3181 geometricParent, scrollframe);
3182 newFrame = scrollframe;
3183 } else {
3184 InitAndRestoreFrame(aState, content, geometricParent, blockFrame);
3185 }
3186
3187 RefPtr<ComputedStyle> rubyStyle =
3188 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3189 PseudoStyleType::MozBlockRubyContent, computedStyle);
3190 nsContainerFrame* rubyFrame = NS_NewRubyFrame(mPresShell, rubyStyle);
3191 InitAndRestoreFrame(aState, content, blockFrame, rubyFrame);
3192 SetInitialSingleChild(blockFrame, rubyFrame);
3193 blockFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3194
3195 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
3196
3197 if (!mRootElementFrame) {
3198 mRootElementFrame = newFrame;
3199 }
3200
3201 nsFrameConstructorSaveState absoluteSaveState;
3202 blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3203 if (newFrame->IsAbsPosContainingBlock()) {
3204 aState.PushAbsoluteContainingBlock(blockFrame, blockFrame,
3205 absoluteSaveState);
3206 }
3207 nsFrameConstructorSaveState floatSaveState;
3208 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
3209
3210 nsFrameList childList;
3211 ProcessChildren(aState, content, rubyStyle, rubyFrame, true, childList, false,
3212 nullptr);
3213 rubyFrame->SetInitialChildList(FrameChildListID::Principal,
3214 std::move(childList));
3215
3216 return newFrame;
3217}
3218
3219static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
3220 for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3221 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"
, 3222); MOZ_PretendNoReturn(); } } while (0)
3222 "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"
, 3222); MOZ_PretendNoReturn(); } } while (0)
;
3223 auto pseudo = f->Style()->GetPseudoType();
3224 if (pseudo == PseudoStyleType::Before || pseudo == PseudoStyleType::After ||
3225 pseudo == PseudoStyleType::Marker ||
3226 pseudo == PseudoStyleType::Backdrop ||
3227 pseudo == PseudoStyleType::Checkmark ||
3228 pseudo == PseudoStyleType::PickerIcon) {
3229 return f;
3230 }
3231 }
3232 return nullptr;
3233}
3234
3235/* static */
3236const nsCSSFrameConstructor::FrameConstructionData*
3237nsCSSFrameConstructor::FindTextData(const Text& aTextContent,
3238 nsIFrame* aParentFrame) {
3239 if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3240 if (!aParentFrame->IsInSVGTextSubtree()) {
3241 return nullptr;
3242 }
3243
3244 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
3245 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
3246 // really know how to deal with it. This kinda sucks. :(
3247 if (aParentFrame->GetContent() != aTextContent.GetParent()) {
3248 return nullptr;
3249 }
3250
3251 static constexpr FrameConstructionData sSVGTextData(
3252 NS_NewTextFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_SVG_TEXT0x80000);
3253 return &sSVGTextData;
3254 }
3255
3256 static constexpr FrameConstructionData sTextData(NS_NewTextFrame,
3257 FCDATA_IS_LINE_PARTICIPANT0x2000);
3258 return &sTextData;
3259}
3260
3261void nsCSSFrameConstructor::ConstructTextFrame(
3262 const FrameConstructionData* aData, nsFrameConstructorState& aState,
3263 nsIContent* aContent, nsContainerFrame* aParentFrame,
3264 ComputedStyle* aComputedStyle, nsFrameList& aFrameList) {
3265 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", 3265
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aData" ") (" "Must have frame construction data"
")"); do { MOZ_CrashSequence(__null, 3265); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3266
3267 nsIFrame* newFrame =
3268 (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
3269
3270 InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3271
3272 if (newFrame->IsGeneratedContentFrame()) {
3273 UniquePtr<nsGenConInitializer> initializer(
3274 static_cast<nsGenConInitializer*>(
3275 aContent->TakeProperty(nsGkAtoms::genConInitializerProperty)));
3276 if (initializer) {
3277 // All generated text has an element as its parent.
3278 auto* element = aContent->GetParent()->AsElement();
3279 nsGenConList* list = nullptr;
3280 if (initializer->mCounterListName) {
3281 list = mContainStyleScopeManager.GetOrCreateCounterList(
3282 *element, initializer->mCounterListName);
3283 } else {
3284 list = mContainStyleScopeManager.QuoteListFor(*element);
3285 }
3286 if (initializer->mNode.release()->InitTextFrame(
3287 list, FindAncestorWithGeneratedContentPseudo(newFrame),
3288 newFrame)) {
3289 if (initializer->mCounterListName) {
3290 CountersDirty();
3291 } else {
3292 QuotesDirty();
3293 }
3294 }
3295 }
3296 }
3297
3298 // Add the newly constructed frame to the flow
3299 aFrameList.AppendFrame(nullptr, newFrame);
3300
3301 if (!aState.mCreatingExtraFrames || (aContent->IsInNativeAnonymousSubtree() &&
3302 !aContent->GetPrimaryFrame())) {
3303 aContent->SetPrimaryFrame(newFrame);
3304 }
3305}
3306
3307/* static */
3308const nsCSSFrameConstructor::FrameConstructionData*
3309nsCSSFrameConstructor::FindDataByInt(int32_t aInt, const Element& aElement,
3310 ComputedStyle& aComputedStyle,
3311 const FrameConstructionDataByInt* aDataPtr,
3312 uint32_t aDataLength) {
3313 for (const FrameConstructionDataByInt *curData = aDataPtr,
3314 *endData = aDataPtr + aDataLength;
3315 curData != endData; ++curData) {
3316 if (curData->mInt == aInt) {
3317 const FrameConstructionData* data = &curData->mData;
3318 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3319 return data->mFunc.mDataGetter(aElement, aComputedStyle);
3320 }
3321
3322 return data;
3323 }
3324 }
3325
3326 return nullptr;
3327}
3328
3329/* static */
3330const nsCSSFrameConstructor::FrameConstructionData*
3331nsCSSFrameConstructor::FindDataByTag(const Element& aElement,
3332 ComputedStyle& aStyle,
3333 const FrameConstructionDataByTag* aDataPtr,
3334 uint32_t aDataLength) {
3335 const nsAtom* tag = aElement.NodeInfo()->NameAtom();
3336 for (const FrameConstructionDataByTag *curData = aDataPtr,
3337 *endData = aDataPtr + aDataLength;
3338 curData != endData; ++curData) {
3339 if (curData->mTag == tag) {
3340 const FrameConstructionData* data = &curData->mData;
3341 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3342 return data->mFunc.mDataGetter(aElement, aStyle);
3343 }
3344
3345 return data;
3346 }
3347 }
3348
3349 return nullptr;
3350}
3351
3352#define SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40) FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME0x40)
3353#define SIMPLE_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3354 {int32_t(_int), FrameConstructionData(_func)}
3355#define SIMPLE_INT_CHAIN(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3356 {int32_t(_int), FrameConstructionData(_func)}
3357#define COMPLEX_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3358 {int32_t(_int), FrameConstructionData(_func)}
3359
3360#define SIMPLE_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3361 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3362#define SIMPLE_TAG_CHAIN(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3363 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3364#define COMPLEX_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3365 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3366
3367static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) {
3368 auto pseudo = aFrame->Style()->GetPseudoType();
3369 if (pseudo == PseudoStyleType::MozFieldsetContent ||
3370 pseudo == PseudoStyleType::MozScrolledContent ||
3371 pseudo == PseudoStyleType::MozColumnSet ||
3372 pseudo == PseudoStyleType::MozColumnContent) {
3373 return GetFieldSetFrameFor(aFrame->GetParent());
3374 }
3375 return do_QueryFrame(aFrame);
3376}
3377
3378/* static */
3379const nsCSSFrameConstructor::FrameConstructionData*
3380nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
3381 nsIFrame* aParentFrame,
3382 ComputedStyle& aStyle) {
3383 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", 3383); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsHTMLElement()" ")"); do { MOZ_CrashSequence
(__null, 3383); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3384 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", 3388); MOZ_PretendNoReturn
(); } } while (0)
3385 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", 3388); MOZ_PretendNoReturn
(); } } while (0)
3386 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", 3388); MOZ_PretendNoReturn
(); } } while (0)
3387 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", 3388); MOZ_PretendNoReturn
(); } } while (0)
3388 "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", 3388); MOZ_PretendNoReturn
(); } } while (0)
;
3389
3390 switch (aStyle.GetPseudoType()) {
3391 case PseudoStyleType::ViewTransitionOld:
3392 case PseudoStyleType::ViewTransitionNew: {
3393 static constexpr FrameConstructionData sViewTransitionData(
3394 NS_NewImageFrameForViewTransition);
3395 return &sViewTransitionData;
3396 }
3397 case PseudoStyleType::MozSelectContent: {
3398 if (aParentFrame && aParentFrame->IsComboboxControlFrame()) {
3399 static constexpr FrameConstructionData sComboboxLabelData(
3400 NS_NewComboboxLabelFrame);
3401 return &sComboboxLabelData;
3402 }
3403 break;
3404 }
3405 case PseudoStyleType::MozFileContent: {
3406 if (aParentFrame && aParentFrame->IsFileControlFrame()) {
3407 static constexpr FrameConstructionData sFileLabelData(
3408 NS_NewFileControlLabelFrame);
3409 return &sFileLabelData;
3410 }
3411 break;
3412 }
3413 case PseudoStyleType::MozReveal:
3414 case PseudoStyleType::MozNumberSpinBox: {
3415 if (aParentFrame && aParentFrame->StyleDisplay()->EffectiveAppearance() ==
3416 StyleAppearance::Textfield) {
3417 // Suppress button-box pseudo-elements with appearance: textfield.
3418 static constexpr FrameConstructionData sSuppressData =
3419 SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
3420 return &sSuppressData;
3421 }
3422 break;
3423 }
3424 default:
3425 break;
3426 }
3427
3428 static constexpr FrameConstructionDataByTag sHTMLData[] = {
3429 SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData){nsGkAtoms::img, FrameConstructionData(nsCSSFrameConstructor::
FindImgData)}
,
3430 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,{nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
3431 nsCSSFrameConstructor::FindGeneratedImageData){nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
,
3432 {nsGkAtoms::br,
3433 {NS_NewBRFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_LINE_BREAK0x4000}},
3434 SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame){nsGkAtoms::wbr, FrameConstructionData(NS_NewWBRFrame)},
3435 SIMPLE_TAG_CHAIN(button, nsCSSFrameConstructor::FindHTMLButtonData){nsGkAtoms::button, FrameConstructionData(nsCSSFrameConstructor
::FindHTMLButtonData)}
,
3436 SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData){nsGkAtoms::input, FrameConstructionData(nsCSSFrameConstructor
::FindInputData)}
,
3437 SIMPLE_TAG_CREATE(textarea, &nsCSSFrameConstructor::ConstructTextControl){nsGkAtoms::textarea, FrameConstructionData(&nsCSSFrameConstructor
::ConstructTextControl)}
,
3438 SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData){nsGkAtoms::select, FrameConstructionData(nsCSSFrameConstructor
::FindSelectData)}
,
3439 SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::object, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3440 SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::embed, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3441 COMPLEX_TAG_CREATE(fieldset,{nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
3442 &nsCSSFrameConstructor::ConstructFieldSetFrame){nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
,
3443 SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame){nsGkAtoms::frameset, FrameConstructionData(NS_NewHTMLFramesetFrame
)}
,
3444 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3445 SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData){nsGkAtoms::canvas, FrameConstructionData(nsCSSFrameConstructor
::FindCanvasData)}
,
3446 SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame){nsGkAtoms::video, FrameConstructionData(NS_NewHTMLVideoFrame
)}
,
3447 SIMPLE_TAG_CREATE(audio, NS_NewHTMLAudioFrame){nsGkAtoms::audio, FrameConstructionData(NS_NewHTMLAudioFrame
)}
,
3448 SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame){nsGkAtoms::progress, FrameConstructionData(NS_NewProgressFrame
)}
,
3449 SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame){nsGkAtoms::meter, FrameConstructionData(NS_NewMeterFrame)},
3450 SIMPLE_TAG_CHAIN(details, nsCSSFrameConstructor::FindDetailsData){nsGkAtoms::details, FrameConstructionData(nsCSSFrameConstructor
::FindDetailsData)}
,
3451 SIMPLE_TAG_CHAIN(label,{nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
3452 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
3453 SIMPLE_TAG_CHAIN(area, SUPPRESS_FCDATA()){nsGkAtoms::area, FrameConstructionData(FrameConstructionData
(nullptr, 0x40))}
,
3454 };
3455
3456 return FindDataByTag(aElement, aStyle, sHTMLData, std::size(sHTMLData));
3457}
3458
3459/* static */
3460const nsCSSFrameConstructor::FrameConstructionData*
3461nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
3462 ComputedStyle&) {
3463 if (!aElement.IsInNativeAnonymousSubtree()) {
3464 return nullptr;
3465 }
3466
3467 auto& generatedContent = static_cast<const GeneratedImageContent&>(aElement);
3468 if (generatedContent.IsForListStyleImageMarker()) {
3469 static constexpr FrameConstructionData sImgData(
3470 NS_NewImageFrameForListStyleImage);
3471 return &sImgData;
3472 }
3473
3474 static constexpr FrameConstructionData sImgData(
3475 NS_NewImageFrameForGeneratedContentIndex);
3476 return &sImgData;
3477}
3478
3479const nsCSSFrameConstructor::FrameConstructionData*
3480nsCSSFrameConstructor::FindHTMLButtonData(const Element&,
3481 ComputedStyle& aStyle) {
3482 // Buttons force a (maybe inline) block unless their display is flex or grid.
3483 // TODO(emilio): It'd be good to remove this restriction more broadly.
3484 // There are some tests that expect block baselines on e.g. a `display: table`
3485 // button, but seems like it would be doable.
3486 const auto* disp = aStyle.StyleDisplay();
3487 const bool respectDisplay = [&] {
3488 if (disp->IsInlineFlow()) {
3489 // For compat, `display: inline` and co need to create an inline-block.
3490 return false;
3491 }
3492 switch (disp->DisplayInside()) {
3493 case StyleDisplayInside::Flex:
3494 case StyleDisplayInside::Grid:
3495 case StyleDisplayInside::FlowRoot:
3496 return true;
3497 default:
3498 return false;
3499 }
3500 }();
3501 if (respectDisplay) {
3502 return nullptr;
3503 }
3504 static constexpr FrameConstructionData sBlockData[2] = {
3505 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3506 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3507 };
3508 return &sBlockData[disp->IsScrollableOverflow()];
3509}
3510
3511/* static */
3512const nsCSSFrameConstructor::FrameConstructionData*
3513nsCSSFrameConstructor::FindImgData(const Element& aElement,
3514 ComputedStyle& aStyle) {
3515 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3516 nsImageFrame::ImageFrameType::ForElementRequest) {
3517 // content: url gets handled by the generic code-path.
3518 return nullptr;
3519 }
3520
3521 static constexpr FrameConstructionData sImgData(NS_NewImageFrame);
3522 return &sImgData;
3523}
3524
3525/* static */
3526const nsCSSFrameConstructor::FrameConstructionData*
3527nsCSSFrameConstructor::FindImgControlData(const Element& aElement,
3528 ComputedStyle& aStyle) {
3529 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3530 nsImageFrame::ImageFrameType::ForElementRequest) {
3531 return nullptr;
3532 }
3533
3534 static constexpr FrameConstructionData sImgControlData(
3535 NS_NewImageControlFrame);
3536 return &sImgControlData;
3537}
3538
3539/* static */
3540const nsCSSFrameConstructor::FrameConstructionData*
3541nsCSSFrameConstructor::FindInputData(const Element& aElement,
3542 ComputedStyle& aStyle) {
3543 static constexpr FrameConstructionDataByInt sInputData[] = {
3544 SIMPLE_INT_CREATE(FormControlType::InputCheckbox,{int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3545 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3546 SIMPLE_INT_CREATE(FormControlType::InputRadio,{int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3547 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3548 SIMPLE_INT_CREATE(FormControlType::InputFile, NS_NewFileControlFrame){int32_t(FormControlType::InputFile), FrameConstructionData(NS_NewFileControlFrame
)}
,
3549 SIMPLE_INT_CHAIN(FormControlType::InputImage,{int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
3550 nsCSSFrameConstructor::FindImgControlData){int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
,
3551 SIMPLE_INT_CREATE(FormControlType::InputEmail,{int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3552 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3553 SIMPLE_INT_CREATE(FormControlType::InputText,{int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3554 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3555 SIMPLE_INT_CREATE(FormControlType::InputTel,{int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3556 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3557 SIMPLE_INT_CREATE(FormControlType::InputUrl,{int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3558 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3559 SIMPLE_INT_CREATE(FormControlType::InputRange, NS_NewRangeFrame){int32_t(FormControlType::InputRange), FrameConstructionData(
NS_NewRangeFrame)}
,
3560 SIMPLE_INT_CREATE(FormControlType::InputPassword,{int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3561 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3562 SIMPLE_INT_CREATE(FormControlType::InputColor, NS_NewColorControlFrame){int32_t(FormControlType::InputColor), FrameConstructionData(
NS_NewColorControlFrame)}
,
3563 SIMPLE_INT_CREATE(FormControlType::InputSearch,{int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3564 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3565 SIMPLE_INT_CREATE(FormControlType::InputNumber,{int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3566 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3567 SIMPLE_INT_CREATE(FormControlType::InputTime, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputTime), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3568 SIMPLE_INT_CREATE(FormControlType::InputDate, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDate), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3569 SIMPLE_INT_CREATE(FormControlType::InputDatetimeLocal,{int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
3570 NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
,
3571 // TODO: this is temporary until a frame is written: bug 888320
3572 SIMPLE_INT_CREATE(FormControlType::InputMonth,{int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3573 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3574 // TODO: this is temporary until a frame is written: bug 888320
3575 SIMPLE_INT_CREATE(FormControlType::InputWeek,{int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3576 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3577 SIMPLE_INT_CREATE(FormControlType::InputSubmit,{int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3578 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3579 SIMPLE_INT_CREATE(FormControlType::InputReset,{int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
3580 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
,
3581 SIMPLE_INT_CREATE(FormControlType::InputButton,{int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3582 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3583 // Keeping hidden inputs out of here on purpose for so they get frames by
3584 // display (in practice, none).
3585 };
3586
3587 auto controlType = HTMLInputElement::FromNode(aElement)->ControlType();
3588
3589 // radio and checkbox inputs with appearance:none should be constructed
3590 // by display type. (Note that we're not checking that appearance is
3591 // not (respectively) StyleAppearance::Radio and StyleAppearance::Checkbox.)
3592 if ((controlType == FormControlType::InputCheckbox ||
3593 controlType == FormControlType::InputRadio) &&
3594 !aStyle.StyleDisplay()->HasNativeAppearance()) {
3595 return nullptr;
3596 }
3597
3598 return FindDataByInt(int32_t(controlType), aElement, aStyle, sInputData,
3599 std::size(sInputData));
3600}
3601
3602/* static */
3603const nsCSSFrameConstructor::FrameConstructionData*
3604nsCSSFrameConstructor::FindObjectData(const Element& aElement,
3605 ComputedStyle& aStyle) {
3606 uint32_t type;
3607 nsCOMPtr<nsIObjectLoadingContent> objContent =
3608 do_QueryInterface(const_cast<Element*>(&aElement));
3609 NS_ASSERTION(objContent,do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3611); MOZ_PretendNoReturn(); } } while (0)
3610 "embed and object must implement "do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3611); MOZ_PretendNoReturn(); } } while (0)
3611 "nsIObjectLoadingContent!")do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3611); MOZ_PretendNoReturn(); } } while (0)
;
3612 objContent->GetDisplayedType(&type);
3613
3614 static constexpr FrameConstructionDataByInt sObjectData[] = {
3615 // TODO(emilio): Can we remove the NS_NewEmptyFrame case and just use a
3616 // subdocument frame here?
3617 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,{int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
3618 NS_NewEmptyFrame){int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
,
3619 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,{int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
3620 NS_NewSubDocumentFrame){int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
,
3621 // Nothing for TYPE_FALLBACK so we'll construct frames by display there
3622 };
3623
3624 return FindDataByInt((int32_t)type, aElement, aStyle, sObjectData,
3625 std::size(sObjectData));
3626}
3627
3628/* static */
3629const nsCSSFrameConstructor::FrameConstructionData*
3630nsCSSFrameConstructor::FindCanvasData(const Element& aElement,
3631 ComputedStyle& aStyle) {
3632 // We want to check whether script is enabled on the document that
3633 // could be painting to the canvas. That's the owner document of
3634 // the canvas, except when the owner document is a static document,
3635 // in which case it's the original document it was cloned from.
3636 Document* doc = aElement.OwnerDoc();
3637 if (doc->IsStaticDocument()) {
3638 doc = doc->GetOriginalDocument();
3639 }
3640 if (!doc->IsScriptEnabled()) {
3641 return nullptr;
3642 }
3643
3644 static constexpr FrameConstructionData sCanvasData(
3645 NS_NewHTMLCanvasFrame, 0, PseudoStyleType::MozHtmlCanvasContent);
3646 return &sCanvasData;
3647}
3648
3649static MOZ_NEVER_INLINE__attribute__((noinline)) void DestroyFramesInList(PresShell* aPs,
3650 nsFrameList& aList) {
3651 nsIFrame::DestroyContext context(aPs);
3652 aList.DestroyFrames(context);
3653}
3654
3655void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
3656 FrameConstructionItem& aItem, nsFrameConstructorState& aState,
3657 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
3658 const FrameConstructionData* data = aItem.mFCData;
3659 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",
3659); MOZ_PretendNoReturn(); } } while (0)
;
3660
3661 uint32_t bits = data->mBits;
3662
3663 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", 3664); MOZ_PretendNoReturn
(); } } while (0)
3664 "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", 3664); MOZ_PretendNoReturn
(); } } while (0)
;
3665
3666 // Some sets of bits are not compatible with each other
3667#define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3668 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", 3669); MOZ_PretendNoReturn
(); } } while (0)
3669 "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", 3669); MOZ_PretendNoReturn
(); } } while (0)
3670 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3671 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10);
3672 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
3673 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_SKIP_ABSPOS_PUSH0x200);
3674 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3675 FCDATA_DISALLOW_GENERATED_CONTENT0x400);
3676 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_ALLOW_BLOCK_STYLES0x8000);
3677 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3678 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3679 CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS0x20,
3680 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3681#undef CHECK_ONLY_ONE_BIT
3682 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", 3684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3683 !(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", 3684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3684 "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", 3684
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3685
3686 // Don't create a subdocument frame for iframes if we're creating extra frames
3687 if (aState.mCreatingExtraFrames &&
3688 aItem.mContent->IsHTMLElement(nsGkAtoms::iframe)) {
3689 return;
3690 }
3691
3692 nsIContent* const content = aItem.mContent;
3693 nsIFrame* newFrame;
3694 nsIFrame* primaryFrame;
3695 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3696 const nsStyleDisplay* display = computedStyle->StyleDisplay();
3697 if (bits & FCDATA_FUNC_IS_FULL_CTOR0x4) {
3698 newFrame = (this->*(data->mFunc.mFullConstructor))(
3699 aState, aItem, aParentFrame, display, aFrameList);
3700 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", 3700
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ") (" "Full constructor failed"
")"); do { MOZ_CrashSequence(__null, 3700); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3701 primaryFrame = newFrame;
3702 } else {
3703 newFrame = (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
3704
3705 const bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8);
3706 nsContainerFrame* geometricParent =
3707 allowOutOfFlow ? aState.GetGeometricParent(*display, aParentFrame)
3708 : aParentFrame;
3709
3710 // In the non-scrollframe case, primaryFrame and newFrame are equal; in the
3711 // scrollframe case, newFrame is the scrolled frame while primaryFrame is
3712 // the scrollframe.
3713 if ((bits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3714 display->IsScrollableOverflow()) {
3715 nsContainerFrame* scrollframe = nullptr;
3716 BuildScrollContainerFrame(aState, content, computedStyle, newFrame,
3717 geometricParent, scrollframe);
3718 primaryFrame = scrollframe;
3719 } else {
3720 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3721 primaryFrame = newFrame;
3722 }
3723
3724 // If we need to create a block formatting context to wrap our
3725 // kids, do it now.
3726 nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3727 nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3728 nsIFrame* possiblyLeafFrame = newFrame;
3729 nsContainerFrame* outerFrame = nullptr;
3730 if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000) {
3731 RefPtr<ComputedStyle> outerStyle =
3732 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3733 data->mAnonBoxPseudo, computedStyle);
3734#ifdef DEBUG1
3735 nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3736 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", 3736); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "containerFrame" ")"); do { MOZ_CrashSequence
(__null, 3736); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3737#endif
3738 nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3739 nsContainerFrame* innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
3740 InitAndRestoreFrame(aState, content, container, innerFrame);
3741 outerFrame = innerFrame;
3742
3743 SetInitialSingleChild(container, outerFrame);
3744
3745 container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3746
3747 // Now figure out whether newFrame or outerFrame should be the
3748 // absolute container.
3749 if (outerFrame->IsAbsPosContainingBlock()) {
3750 maybeAbsoluteContainingBlock = outerFrame;
3751 maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3752 innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3753 }
3754
3755 // Our kids should go into the innerFrame.
3756 newFrame = innerFrame;
3757 }
3758
3759 aState.AddChild(primaryFrame, aFrameList, content, aParentFrame,
3760 allowOutOfFlow, allowOutOfFlow);
3761
3762 nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3763 if (newFrameAsContainer) {
3764 // Process the child content if requested
3765 nsFrameList childList;
3766 nsFrameConstructorSaveState absoluteSaveState;
3767
3768 if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10) {
3769 aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3770 } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH0x200)) {
3771 maybeAbsoluteContainingBlock->AddStateBits(
3772 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3773 if (maybeAbsoluteContainingBlockStyleFrame->IsAbsPosContainingBlock()) {
3774 auto* cf =
3775 static_cast<nsContainerFrame*>(maybeAbsoluteContainingBlock);
3776 aState.PushAbsoluteContainingBlock(
3777 cf, maybeAbsoluteContainingBlockStyleFrame, absoluteSaveState);
3778 }
3779 }
3780
3781 nsFrameConstructorSaveState floatSaveState;
3782 aState.MaybePushFloatContainingBlock(newFrameAsContainer, floatSaveState);
3783
3784 if (bits & FCDATA_USE_CHILD_ITEMS0x10000) {
3785 // At this point, we have not set up the auto value for this frame, and
3786 // no caller will have set it so it is not redundant and therefor will
3787 // not assert.
3788 AutoFrameConstructionPageName pageNameTracker(aState,
3789 newFrameAsContainer);
3790 ConstructFramesFromItemList(
3791 aState, aItem.mChildItems, newFrameAsContainer,
3792 bits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
3793 } else {
3794 // Process the child frames.
3795 ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
3796 !(bits & FCDATA_DISALLOW_GENERATED_CONTENT0x400), childList,
3797 (bits & FCDATA_ALLOW_BLOCK_STYLES0x8000) != 0,
3798 possiblyLeafFrame);
3799 }
3800
3801 if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS0x20) {
3802 nsFrameList newList;
3803 nsFrameList currentBlockList;
3804 nsIFrame* f;
3805 while ((f = childList.FirstChild()) != nullptr) {
3806 bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
3807 if (!wrapFrame) {
3808 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3809 currentBlockList, newList);
3810 }
3811
3812 childList.RemoveFrame(f);
3813 if (wrapFrame) {
3814 currentBlockList.AppendFrame(nullptr, f);
3815 } else {
3816 newList.AppendFrame(nullptr, f);
3817 }
3818 }
3819 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3820 currentBlockList, newList);
3821
3822 if (childList.NotEmpty()) {
3823 // an error must have occurred, delete unprocessed frames
3824 DestroyFramesInList(mPresShell, childList);
3825 }
3826
3827 childList = std::move(newList);
3828 }
3829
3830 // Set the frame's initial child list. Note that MathML depends on this
3831 // being called even if childList is empty!
3832 newFrameAsContainer->SetInitialChildList(FrameChildListID::Principal,
3833 std::move(childList));
3834 }
3835 }
3836
3837 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", 3839); MOZ_PretendNoReturn
(); } } while (0)
3838 ((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", 3839); MOZ_PretendNoReturn
(); } } while (0)
3839 "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", 3839); MOZ_PretendNoReturn
(); } } while (0)
;
3840
3841 // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
3842 // generated content that doesn't have one yet. Note that we have to examine
3843 // the frame bit, because by this point mIsGeneratedContent has been cleared
3844 // on aItem.
3845 if ((!aState.mCreatingExtraFrames ||
3846 (aItem.mContent->IsRootOfNativeAnonymousSubtree() &&
3847 !aItem.mContent->GetPrimaryFrame())) &&
3848 !(bits & FCDATA_SKIP_FRAMESET0x1)) {
3849 aItem.mContent->SetPrimaryFrame(primaryFrame);
3850 ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
3851 }
3852}
3853
3854static void GatherSubtreeElements(Element* aElement,
3855 nsTArray<Element*>& aElements) {
3856 aElements.AppendElement(aElement);
3857 StyleChildrenIterator iter(aElement);
3858 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
3859 if (!c->IsElement()) {
3860 continue;
3861 }
3862 GatherSubtreeElements(c->AsElement(), aElements);
3863 }
3864}
3865
3866nsresult nsCSSFrameConstructor::GetAnonymousContent(
3867 nsIContent* aParent, nsIFrame* aParentFrame,
3868 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
3869 nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3870 if (!creator) {
3871 return NS_OK;
3872 }
3873
3874 nsresult rv = creator->CreateAnonymousContent(aContent);
3875 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3876 // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
3877 return rv;
3878 }
3879
3880 if (aContent.IsEmpty()) {
3881 return NS_OK;
3882 }
3883
3884 const bool devtoolsEventsEnabled =
3885 mDocument->DevToolsAnonymousAndShadowEventsEnabled();
3886
3887 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", 3887); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aParent->IsElement()" ")"); do { MOZ_CrashSequence
(__null, 3887); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3888 for (const auto& info : aContent) {
3889 // get our child's content and set its parent to our content
3890 nsIContent* content = info.mContent;
3891 content->SetIsNativeAnonymousRoot();
3892
3893 BindContext context(*aParent->AsElement(), BindContext::ForNativeAnonymous);
3894 rv = content->BindToTree(context, *aParent);
3895
3896 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3897 content->UnbindFromTree();
3898 return rv;
3899 }
3900
3901 if (devtoolsEventsEnabled) {
3902 content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
3903 }
3904 }
3905
3906 // Some situations where we don't cache anonymous content styles:
3907 //
3908 // * when visibility or pointer-events is anything other than the initial
3909 // value; we rely on visibility and pointer-events inheriting into anonymous
3910 // content, but don't bother adding this state to the AnonymousContentKey,
3911 // since it's not so common. Note that with overlay scrollbars, scrollbars
3912 // always start off with pointer-events: none so we don't need to check for
3913 // that in that case.
3914 //
3915 // * when the medium is anything other than screen; some UA style sheet rules
3916 // apply in e.g. print medium, and will give different results from the
3917 // cached styles
3918 Maybe<bool> computedAllowStyleCaching;
3919 auto ComputeAllowStyleCaching = [&] {
3920 if (!StaticPrefs::layout_css_cached_scrollbar_styles_enabled()) {
3921 return false;
3922 }
3923 if (aParentFrame->StyleVisibility()->mVisible != StyleVisibility::Visible) {
3924 return false;
3925 }
3926 nsPresContext* pc = mPresShell->GetPresContext();
3927 if (!pc->UseOverlayScrollbars() &&
3928 aParentFrame->StyleUI()->ComputedPointerEvents() !=
3929 StylePointerEvents::Auto) {
3930 return false;
3931 }
3932 if (pc->Medium() != nsGkAtoms::screen) {
3933 return false;
3934 }
3935 return true;
3936 };
3937
3938 auto AllowStyleCaching = [&] {
3939 if (computedAllowStyleCaching.isNothing()) {
3940 computedAllowStyleCaching.emplace(ComputeAllowStyleCaching());
3941 }
3942 return computedAllowStyleCaching.value();
3943 };
3944
3945 // Compute styles for the anonymous content tree.
3946 ServoStyleSet* styleSet = mPresShell->StyleSet();
3947 for (auto& info : aContent) {
3948 Element* e = Element::FromNode(info.mContent);
3949 if (!e) {
3950 continue;
3951 }
3952
3953 if (info.mKey == AnonymousContentKey::None || !AllowStyleCaching()) {
3954 // Most NAC subtrees do not use caching of computed styles. Just go
3955 // ahead and eagerly style the subtree.
3956 styleSet->StyleNewSubtree(e);
3957 continue;
3958 }
3959
3960 // We have a NAC subtree for which we can use cached styles.
3961 AutoTArray<RefPtr<ComputedStyle>, 2> cachedStyles;
3962 AutoTArray<Element*, 2> elements;
3963
3964 GatherSubtreeElements(e, elements);
3965 styleSet->GetCachedAnonymousContentStyles(info.mKey, cachedStyles);
3966
3967 if (cachedStyles.IsEmpty()) {
3968 // We haven't stored cached styles for this kind of NAC subtree yet.
3969 // Eagerly compute those styles, then cache them for later.
3970 styleSet->StyleNewSubtree(e);
3971 for (Element* e : elements) {
3972 if (e->HasServoData()) {
3973 cachedStyles.AppendElement(ServoStyleSet::ResolveServoStyle(*e));
3974 } else {
3975 cachedStyles.AppendElement(nullptr);
3976 }
3977 }
3978 styleSet->PutCachedAnonymousContentStyles(info.mKey,
3979 std::move(cachedStyles));
3980 continue;
3981 }
3982
3983 // We previously stored cached styles for this kind of NAC subtree.
3984 // Iterate over them and set them on the subtree's elements.
3985 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"
, 3986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3986); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3986 "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"
, 3986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3986); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3987 for (size_t i = 0, len = cachedStyles.Length(); i != len; ++i) {
3988 if (cachedStyles[i]) {
3989#ifdef DEBUG1
3990 // Assert that our cached style is the same as one we could compute.
3991 RefPtr<ComputedStyle> cs = styleSet->ResolveStyleLazily(*elements[i]);
3992 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"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3995); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3993 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"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3995); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3994 "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"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3995); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3995 "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"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3995); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3996 // All overlay scrollbars start off as inactive, so we can rely on their
3997 // pointer-events value being always none.
3998 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", 4000); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 4000); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3999 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", 4000); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 4000); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4000 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", 4000); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 4000); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4001#endif
4002 Servo_SetExplicitStyle(elements[i], cachedStyles[i]);
4003 }
4004 }
4005 }
4006
4007 return NS_OK;
4008}
4009
4010/* static */
4011const nsCSSFrameConstructor::FrameConstructionData*
4012nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
4013 ComputedStyle& aStyle) {
4014 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", 4014); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsXULElement()" ")"); do { MOZ_CrashSequence
(__null, 4014); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4015 static constexpr FrameConstructionData kPopupData(NS_NewMenuPopupFrame);
4016
4017 static constexpr FrameConstructionDataByTag sXULTagData[] = {
4018 SIMPLE_TAG_CREATE(image, NS_NewXULImageFrame){nsGkAtoms::image, FrameConstructionData(NS_NewXULImageFrame)
}
,
4019 SIMPLE_TAG_CREATE(treechildren, NS_NewTreeBodyFrame){nsGkAtoms::treechildren, FrameConstructionData(NS_NewTreeBodyFrame
)}
,
4020 SIMPLE_TAG_CHAIN(label,{nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
4021 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
4022 SIMPLE_TAG_CHAIN(description,{nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
4023 nsCSSFrameConstructor::FindLabelOrDescriptionData){nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindLabelOrDescriptionData)}
,
4024 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4025 SIMPLE_TAG_CREATE(editor, NS_NewSubDocumentFrame){nsGkAtoms::editor, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4026 SIMPLE_TAG_CREATE(browser, NS_NewSubDocumentFrame){nsGkAtoms::browser, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
4027 SIMPLE_TAG_CREATE(splitter, NS_NewSplitterFrame){nsGkAtoms::splitter, FrameConstructionData(NS_NewSplitterFrame
)}
,
4028 SIMPLE_TAG_CREATE(scrollbar, NS_NewScrollbarFrame){nsGkAtoms::scrollbar, FrameConstructionData(NS_NewScrollbarFrame
)}
,
4029 SIMPLE_TAG_CREATE(slider, NS_NewSliderFrame){nsGkAtoms::slider, FrameConstructionData(NS_NewSliderFrame)},
4030 SIMPLE_TAG_CREATE(thumb, NS_NewSimpleXULLeafFrame){nsGkAtoms::thumb, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4031 SIMPLE_TAG_CREATE(scrollcorner, NS_NewSimpleXULLeafFrame){nsGkAtoms::scrollcorner, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4032 SIMPLE_TAG_CREATE(resizer, NS_NewSimpleXULLeafFrame){nsGkAtoms::resizer, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4033 SIMPLE_TAG_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame){nsGkAtoms::scrollbarbutton, FrameConstructionData(NS_NewScrollbarButtonFrame
)}
,
4034 {nsGkAtoms::panel, kPopupData},
4035 {nsGkAtoms::menupopup, kPopupData},
4036 {nsGkAtoms::tooltip, kPopupData},
4037 };
4038
4039 return FindDataByTag(aElement, aStyle, sXULTagData, std::size(sXULTagData));
4040}
4041
4042/* static */
4043const nsCSSFrameConstructor::FrameConstructionData*
4044nsCSSFrameConstructor::FindLabelOrDescriptionData(const Element& aElement,
4045 ComputedStyle&) {
4046 if (!aElement.OwnerDoc()->ChromeRulesEnabled()) {
4047 return nullptr;
4048 }
4049
4050 // Follow CSS display value if no value attribute
4051 if (!aElement.HasAttr(nsGkAtoms::value)) {
4052 return nullptr;
4053 }
4054
4055 // Follow CSS display if there's no crop="center".
4056 if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::crop,
4057 nsGkAtoms::center, eCaseMatters)) {
4058 return nullptr;
4059 }
4060
4061 static constexpr FrameConstructionData sMiddleCroppingData(
4062 NS_NewMiddleCroppingLabelFrame);
4063 return &sMiddleCroppingData;
4064}
4065
4066already_AddRefed<ComputedStyle>
4067nsCSSFrameConstructor::BeginBuildingScrollContainerFrame(
4068 nsFrameConstructorState& aState, nsIContent* aContent,
4069 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame, bool aIsRoot,
4070 nsContainerFrame*& aNewFrame) {
4071 nsContainerFrame* scrollContainerFrame = aNewFrame;
4072
4073 if (!scrollContainerFrame) {
4074 scrollContainerFrame =
4075 NS_NewScrollContainerFrame(mPresShell, aContentStyle, aIsRoot);
4076 InitAndRestoreFrame(aState, aContent, aParentFrame, scrollContainerFrame);
4077 }
4078
4079 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", 4079); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "scrollContainerFrame" ")"); do { MOZ_CrashSequence
(__null, 4079); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4080
4081 // if there are any anonymous children for the scroll frame, create
4082 // frames for them.
4083 //
4084 // We can't take the normal ProcessChildren path, because the NAC needs to
4085 // be parented to the scrollframe, and everything else needs to be parented
4086 // to the scrolledframe.
4087 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4088 DebugOnly<nsresult> rv =
4089 GetAnonymousContent(aContent, scrollContainerFrame, scrollNAC);
4090 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"
, 4090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4090); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4091 nsFrameList anonymousList;
4092 if (!scrollNAC.IsEmpty()) {
4093 nsFrameConstructorSaveState floatSaveState;
4094 aState.MaybePushFloatContainingBlock(scrollContainerFrame, floatSaveState);
4095
4096 AutoFrameConstructionItemList items(this);
4097 AutoFrameConstructionPageName pageNameTracker(aState, scrollContainerFrame);
4098 AddFCItemsForAnonymousContent(aState, scrollContainerFrame, scrollNAC,
4099 items, pageNameTracker);
4100 ConstructFramesFromItemList(aState, items, scrollContainerFrame,
4101 /* aParentIsWrapperAnonBox = */ false,
4102 anonymousList);
4103 }
4104
4105 aNewFrame = scrollContainerFrame;
4106 scrollContainerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4107
4108 // we used the style that was passed in. So resolve another one.
4109 ServoStyleSet* styleSet = mPresShell->StyleSet();
4110 RefPtr<ComputedStyle> scrolledChildStyle =
4111 styleSet->ResolveInheritingAnonymousBoxStyle(
4112 PseudoStyleType::MozScrolledContent, aContentStyle);
4113
4114 scrollContainerFrame->SetInitialChildList(FrameChildListID::Principal,
4115 std::move(anonymousList));
4116
4117 return scrolledChildStyle.forget();
4118}
4119
4120void nsCSSFrameConstructor::FinishBuildingScrollContainerFrame(
4121 nsContainerFrame* aScrollContainerFrame, nsIFrame* aScrolledFrame) {
4122 aScrollContainerFrame->AppendFrames(
4123 FrameChildListID::Principal, nsFrameList(aScrolledFrame, aScrolledFrame));
4124}
4125
4126void nsCSSFrameConstructor::BuildScrollContainerFrame(
4127 nsFrameConstructorState& aState, nsIContent* aContent,
4128 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
4129 nsContainerFrame* aParentFrame, nsContainerFrame*& aNewFrame) {
4130 RefPtr<ComputedStyle> scrolledContentStyle =
4131 BeginBuildingScrollContainerFrame(aState, aContent, aContentStyle,
4132 aParentFrame, false, aNewFrame);
4133
4134 aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
4135 InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4136
4137 FinishBuildingScrollContainerFrame(aNewFrame, aScrolledFrame);
4138}
4139
4140const nsCSSFrameConstructor::FrameConstructionData*
4141nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
4142 const Element& aElement) {
4143 static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET28)),
4144 "Check eParentTypeCount should not overflow");
4145
4146 // The style system ensures that floated and positioned frames are
4147 // block-level.
4148 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", 4151); MOZ_PretendNoReturn
(); } } while (0)
4149 !(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", 4151); MOZ_PretendNoReturn
(); } } while (0)
4150 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", 4151); MOZ_PretendNoReturn
(); } } while (0)
4151 "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", 4151); MOZ_PretendNoReturn
(); } } while (0)
;
4152
4153 // If this is "body", try propagating its scroll style to the viewport
4154 // Note that we need to do this even if the body is NOT scrollable;
4155 // it might have dynamically changed from scrollable to not scrollable,
4156 // and that might need to be propagated.
4157 // XXXbz is this the right place to do this? If this code moves,
4158 // make this function static.
4159 bool propagatedScrollToViewport = false;
4160 if (aElement.IsHTMLElement(nsGkAtoms::body)) {
4161 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4162 propagatedScrollToViewport =
4163 presContext->UpdateViewportScrollStylesOverride() == &aElement;
4164 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", 4166); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4165 !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", 4166); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4166 "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", 4166); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4167 }
4168 }
4169
4170 switch (aDisplay.DisplayInside()) {
4171 case StyleDisplayInside::Flow:
4172 case StyleDisplayInside::FlowRoot: {
4173 if (aDisplay.IsInlineFlow()) {
4174 static constexpr FrameConstructionData data(
4175 &nsCSSFrameConstructor::ConstructInline,
4176 FCDATA_IS_INLINE0x1000 | FCDATA_IS_LINE_PARTICIPANT0x2000);
4177 return &data;
4178 }
4179
4180 // If the frame is a block-level frame and is scrollable, then wrap it in
4181 // a scroll frame. Except we don't want to do that for paginated contexts
4182 // for frames that are block-outside and aren't frames for native
4183 // anonymous stuff.
4184 // XXX Ignore tables for the time being (except caption)
4185 const uint32_t kCaptionCtorFlags =
4186 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28);
4187 const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
4188 const bool needScrollFrame =
4189 aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport;
4190 if (needScrollFrame) {
4191 const bool suppressScrollFrame =
4192 mPresShell->GetPresContext()->IsPaginated() &&
4193 aDisplay.IsBlockOutsideStyle() &&
4194 !aElement.IsInNativeAnonymousSubtree();
4195 if (!suppressScrollFrame) {
4196 static constexpr FrameConstructionData sScrollableBlockData[2] = {
4197 {&nsCSSFrameConstructor::ConstructScrollableBlock},
4198 {&nsCSSFrameConstructor::ConstructScrollableBlock,
4199 kCaptionCtorFlags}};
4200 return &sScrollableBlockData[caption];
4201 }
4202 }
4203
4204 // Handle various non-scrollable blocks.
4205 static constexpr FrameConstructionData sNonScrollableBlockData[2] = {
4206 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
4207 {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
4208 kCaptionCtorFlags}};
4209 return &sNonScrollableBlockData[caption];
4210 }
4211 case StyleDisplayInside::Table: {
4212 static constexpr FrameConstructionData data(
4213 &nsCSSFrameConstructor::ConstructTable);
4214 return &data;
4215 }
4216 // NOTE: In the unlikely event that we add another table-part here that
4217 // has a desired-parent-type (& hence triggers table fixup), we'll need to
4218 // also update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
4219 case StyleDisplayInside::TableRowGroup: {
4220 static constexpr FrameConstructionData data(
4221 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4222 FCDATA_IS_TABLE_PART0x800 |
4223 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4224 return &data;
4225 }
4226 case StyleDisplayInside::TableColumn: {
4227 static constexpr FrameConstructionData data(
4228 &nsCSSFrameConstructor::ConstructTableCol,
4229 FCDATA_IS_TABLE_PART0x800 |
4230 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup)(((uint32_t)(eTypeColGroup)) << 28));
4231 return &data;
4232 }
4233 case StyleDisplayInside::TableColumnGroup: {
4234 static constexpr FrameConstructionData data(
4235 ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
4236 FCDATA_IS_TABLE_PART0x800 | FCDATA_DISALLOW_OUT_OF_FLOW0x8 |
4237 FCDATA_SKIP_ABSPOS_PUSH0x200 |
4238 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4239 return &data;
4240 }
4241 case StyleDisplayInside::TableHeaderGroup: {
4242 static constexpr FrameConstructionData data(
4243 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4244 FCDATA_IS_TABLE_PART0x800 |
4245 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4246 return &data;
4247 }
4248 case StyleDisplayInside::TableFooterGroup: {
4249 static constexpr FrameConstructionData data(
4250 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4251 FCDATA_IS_TABLE_PART0x800 |
4252 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4253 return &data;
4254 }
4255 case StyleDisplayInside::TableRow: {
4256 static constexpr FrameConstructionData data(
4257 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4258 FCDATA_IS_TABLE_PART0x800 |
4259 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28));
4260 return &data;
4261 }
4262 case StyleDisplayInside::TableCell: {
4263 static constexpr FrameConstructionData data(
4264 &nsCSSFrameConstructor::ConstructTableCell,
4265 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28));
4266 return &data;
4267 }
4268 case StyleDisplayInside::Flex:
4269 case StyleDisplayInside::WebkitBox: {
4270 static constexpr FrameConstructionData nonScrollableData(
4271 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
);
4272 static constexpr FrameConstructionData data(
4273 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
,
4274 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4275 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4276 : &data;
4277 }
4278 case StyleDisplayInside::Grid:
4279 case StyleDisplayInside::GridLanes: {
4280 static constexpr FrameConstructionData nonScrollableData(
4281 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
);
4282 static constexpr FrameConstructionData data(
4283 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
,
4284 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4285 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4286 : &data;
4287 }
4288 case StyleDisplayInside::Ruby: {
4289 static constexpr FrameConstructionData data[] = {
4290 {&nsCSSFrameConstructor::ConstructBlockRubyFrame,
4291 FCDATA_MAY_NEED_SCROLLFRAME0x80},
4292 {ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
, FCDATA_IS_LINE_PARTICIPANT0x2000}};
4293 bool isInline = aDisplay.DisplayOutside() == StyleDisplayOutside::Inline;
4294 return &data[isInline];
4295 }
4296 case StyleDisplayInside::RubyBase: {
4297 static constexpr FrameConstructionData data(
4298 ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
4299 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4300 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28));
4301 return &data;
4302 }
4303 case StyleDisplayInside::RubyBaseContainer: {
4304 static constexpr FrameConstructionData data(
4305 ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
4306 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4307 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4308 return &data;
4309 }
4310 case StyleDisplayInside::RubyText: {
4311 static constexpr FrameConstructionData data(
4312 ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
4313 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4314 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28));
4315 return &data;
4316 }
4317 case StyleDisplayInside::RubyTextContainer: {
4318 static constexpr FrameConstructionData data(
4319 ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
4320 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4321 return &data;
4322 }
4323 default:
4324 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"
, 4324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown 'display' value" ")"); do
{ MOZ_CrashSequence(__null, 4324); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4325 return nullptr;
4326 }
4327}
4328
4329nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
4330 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4331 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4332 nsFrameList& aFrameList) {
4333 nsContainerFrame* newFrame = nullptr;
4334 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
4335 aDisplay, aFrameList, newFrame);
4336 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"
, 4336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ")"
); do { MOZ_CrashSequence(__null, 4336); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4337 return newFrame;
4338}
4339
4340void nsCSSFrameConstructor::ConstructScrollableBlockWithScrollContainer(
4341 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4342 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4343 nsFrameList& aFrameList, nsContainerFrame*& aNewFrame) {
4344 nsIContent* const content = aItem.mContent;
4345 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4346 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", 4346); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->IsScrollContainerOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 4346); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4347
4348 RefPtr<ComputedStyle> scrolledContentStyle =
4349 BeginBuildingScrollContainerFrame(
4350 aState, content, computedStyle,
4351 aState.GetGeometricParent(*aDisplay, aParentFrame), false, aNewFrame);
4352
4353 // Create our block frame
4354 // pass a temporary stylecontext, the correct one will be set later
4355 nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4356
4357 // Make sure to AddChild before we call ConstructBlock so that we
4358 // end up before our descendants in fixed-pos lists as needed.
4359 aState.AddChild(aNewFrame, aFrameList, content, aParentFrame);
4360
4361 nsFrameList blockList;
4362 ConstructBlock(aState, content, aNewFrame, aNewFrame, scrolledContentStyle,
4363 &scrolledFrame, blockList,
4364 aNewFrame->IsAbsPosContainingBlock() ? aNewFrame : nullptr);
4365
4366 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", 4367
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4367); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4367 "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", 4367
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4367); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4368 FinishBuildingScrollContainerFrame(aNewFrame, scrolledFrame);
4369}
4370
4371nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
4372 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4373 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4374 nsFrameList& aFrameList) {
4375 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4376 nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4377 ConstructBlock(aState, aItem.mContent,
4378 aState.GetGeometricParent(*aDisplay, aParentFrame),
4379 aParentFrame, computedStyle, &newFrame, aFrameList,
4380 newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
4381 return newFrame;
4382}
4383
4384void nsCSSFrameConstructor::InitAndRestoreFrame(
4385 const nsFrameConstructorState& aState, nsIContent* aContent,
4386 nsContainerFrame* aParentFrame, nsIFrame* aNewFrame,
4387 AllowCounters aAllowCounters) {
4388 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", 4388
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewFrame" ") (" "Null frame cannot be initialized"
")"); do { MOZ_CrashSequence(__null, 4388); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4389
4390 // Initialize the frame
4391 aNewFrame->Init(aContent, aParentFrame, nullptr);
4392 aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4393
4394 if (aAllowCounters == AllowCounters::Yes && !aState.mCreatingExtraFrames &&
4395 mContainStyleScopeManager.AddCounterChanges(aNewFrame)) {
4396 CountersDirty();
4397 }
4398}
4399
4400already_AddRefed<ComputedStyle> nsCSSFrameConstructor::ResolveComputedStyle(
4401 nsIContent* aContent) {
4402 if (auto* element = Element::FromNode(aContent)) {
4403 return ServoStyleSet::ResolveServoStyle(*element);
4404 }
4405
4406 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", 4408
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4408); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4407 "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", 4408
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4408); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4408 "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", 4408
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4408); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4409
4410 Element* parent = aContent->GetFlattenedTreeParentElement();
4411 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", 4411
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "Text out of the flattened tree?"
")"); do { MOZ_CrashSequence(__null, 4411); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4412
4413 // FIXME(emilio): The const_cast is unfortunate, but it's not worse than what
4414 // we did before.
4415 //
4416 // We could use ResolveServoStyle, but that would involve extra unnecessary
4417 // refcount traffic...
4418 auto* parentStyle =
4419 const_cast<ComputedStyle*>(Servo_Element_GetMaybeOutOfDateStyle(parent));
4420 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", 4421); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4421); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4421 "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", 4421); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4421); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4422 return mPresShell->StyleSet()->ResolveStyleForText(aContent, parentStyle);
4423}
4424
4425// MathML Mod - RBS
4426void nsCSSFrameConstructor::FlushAccumulatedBlock(
4427 nsFrameConstructorState& aState, nsIContent* aContent,
4428 nsContainerFrame* aParentFrame, nsFrameList& aBlockList,
4429 nsFrameList& aNewList) {
4430 if (aBlockList.IsEmpty()) {
4431 // Nothing to do
4432 return;
4433 }
4434
4435 auto anonPseudo = PseudoStyleType::MozMathmlAnonymousBlock;
4436
4437 ComputedStyle* parentContext =
4438 nsIFrame::CorrectStyleParentFrame(aParentFrame, anonPseudo)->Style();
4439 ServoStyleSet* styleSet = mPresShell->StyleSet();
4440 RefPtr<ComputedStyle> blockContext =
4441 styleSet->ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
4442
4443 // then, create a block frame that will wrap the child frames. Make it a
4444 // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4445 // is not a suitable block.
4446 nsContainerFrame* blockFrame =
4447 NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
4448
4449 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
4450 ReparentFrames(this, blockFrame, aBlockList, false);
4451 // We have to walk over aBlockList before we hand it over to blockFrame.
4452 for (nsIFrame* f : aBlockList) {
4453 f->SetParentIsWrapperAnonBox();
4454 }
4455 // abs-pos and floats are disabled in MathML children so we don't have to
4456 // worry about messing up those.
4457 blockFrame->SetInitialChildList(FrameChildListID::Principal,
4458 std::move(aBlockList));
4459 aNewList.AppendFrame(nullptr, blockFrame);
4460}
4461
4462// Only <math> elements can be floated or positioned. All other MathML
4463// should be in-flow.
4464#define MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 } \
4465 FrameConstructionData { \
4466 _func, FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | \
4467 FCDATA_WRAP_KIDS_IN_BLOCKS0x20 \
4468 }
4469
4470#define SIMPLE_MATHML_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData { _func, 0x8 | 0x10 |
0x20 }}
{nsGkAtoms::_tag, MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 }}
4471
4472/* static */
4473const nsCSSFrameConstructor::FrameConstructionData*
4474nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
4475 ComputedStyle& aStyle) {
4476 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", 4476); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsMathMLElement()" ")"); do { MOZ_CrashSequence
(__null, 4476); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4477
4478 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4479
4480 // Handle <math> specially, because it sometimes produces inlines
4481 if (tag == nsGkAtoms::math) {
4482 // The IsBlockOutsideStyle() check must match what
4483 // specified::Display::equivalent_block_display is checking for
4484 // already-block-outside things. Though the behavior here for the
4485 // display:table case is pretty weird...
4486 if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
4487 static constexpr FrameConstructionData sBlockMathData(
4488 ToCreationFunc(NS_NewMathMLmathBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathBlockFrame(aPs, aStyle); }
,
4489 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4490 return &sBlockMathData;
4491 }
4492
4493 static constexpr FrameConstructionData sInlineMathData(
4494 ToCreationFunc(NS_NewMathMLmathInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathInlineFrame(aPs, aStyle); }
,
4495 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4496 FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4497 return &sInlineMathData;
4498 }
4499
4500 // Special case for elements with a display value other than none
4501 // specified in mathml.css that are not handled by this function.
4502 // These shouldn't be rendered as an mrow.
4503 if (tag == nsGkAtoms::mtable || tag == nsGkAtoms::mtr ||
4504 tag == nsGkAtoms::mlabeledtr || tag == nsGkAtoms::mtd) {
4505 return nullptr;
4506 }
4507
4508 static constexpr FrameConstructionDataByTag sMathMLData[] = {
4509 SIMPLE_MATHML_CREATE(annotation, NS_NewMathMLTokenFrame){nsGkAtoms::annotation, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4510 SIMPLE_MATHML_CREATE(annotation_xml, NS_NewMathMLmrowFrame){nsGkAtoms::annotation_xml, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4511 SIMPLE_MATHML_CREATE(mi, NS_NewMathMLTokenFrame){nsGkAtoms::mi, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4512 SIMPLE_MATHML_CREATE(mn, NS_NewMathMLTokenFrame){nsGkAtoms::mn, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4513 SIMPLE_MATHML_CREATE(ms, NS_NewMathMLTokenFrame){nsGkAtoms::ms, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4514 SIMPLE_MATHML_CREATE(mtext, NS_NewMathMLTokenFrame){nsGkAtoms::mtext, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4515 SIMPLE_MATHML_CREATE(mo, NS_NewMathMLmoFrame){nsGkAtoms::mo, FrameConstructionData { NS_NewMathMLmoFrame, 0x8
| 0x10 | 0x20 }}
,
4516 SIMPLE_MATHML_CREATE(mfrac, NS_NewMathMLmfracFrame){nsGkAtoms::mfrac, FrameConstructionData { NS_NewMathMLmfracFrame
, 0x8 | 0x10 | 0x20 }}
,
4517 SIMPLE_MATHML_CREATE(msup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4518 SIMPLE_MATHML_CREATE(msub, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msub, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4519 SIMPLE_MATHML_CREATE(msubsup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msubsup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4520 SIMPLE_MATHML_CREATE(munder, NS_NewMathMLmunderoverFrame){nsGkAtoms::munder, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4521 SIMPLE_MATHML_CREATE(mover, NS_NewMathMLmunderoverFrame){nsGkAtoms::mover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4522 SIMPLE_MATHML_CREATE(munderover, NS_NewMathMLmunderoverFrame){nsGkAtoms::munderover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4523 SIMPLE_MATHML_CREATE(mphantom, NS_NewMathMLmrowFrame){nsGkAtoms::mphantom, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4524 SIMPLE_MATHML_CREATE(mpadded, NS_NewMathMLmpaddedFrame){nsGkAtoms::mpadded, FrameConstructionData { NS_NewMathMLmpaddedFrame
, 0x8 | 0x10 | 0x20 }}
,
4525 SIMPLE_MATHML_CREATE(mspace, NS_NewMathMLmspaceFrame){nsGkAtoms::mspace, FrameConstructionData { NS_NewMathMLmspaceFrame
, 0x8 | 0x10 | 0x20 }}
,
4526 SIMPLE_MATHML_CREATE(none, NS_NewMathMLmrowFrame){nsGkAtoms::none, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4527 SIMPLE_MATHML_CREATE(mprescripts, NS_NewMathMLmrowFrame){nsGkAtoms::mprescripts, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4528 SIMPLE_MATHML_CREATE(mfenced, NS_NewMathMLmrowFrame){nsGkAtoms::mfenced, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4529 SIMPLE_MATHML_CREATE(mmultiscripts, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::mmultiscripts, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4530 SIMPLE_MATHML_CREATE(mstyle, NS_NewMathMLmrowFrame){nsGkAtoms::mstyle, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4531 SIMPLE_MATHML_CREATE(msqrt, NS_NewMathMLmrootFrame){nsGkAtoms::msqrt, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4532 SIMPLE_MATHML_CREATE(mroot, NS_NewMathMLmrootFrame){nsGkAtoms::mroot, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4533 SIMPLE_MATHML_CREATE(maction, NS_NewMathMLmrowFrame){nsGkAtoms::maction, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4534 SIMPLE_MATHML_CREATE(mrow, NS_NewMathMLmrowFrame){nsGkAtoms::mrow, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4535 SIMPLE_MATHML_CREATE(merror, NS_NewMathMLmrowFrame){nsGkAtoms::merror, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4536 SIMPLE_MATHML_CREATE(menclose, NS_NewMathMLmencloseFrame){nsGkAtoms::menclose, FrameConstructionData { NS_NewMathMLmencloseFrame
, 0x8 | 0x10 | 0x20 }}
,
4537 SIMPLE_MATHML_CREATE(semantics, NS_NewMathMLmrowFrame){nsGkAtoms::semantics, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
};
4538
4539 if (const auto* data = FindDataByTag(aElement, aStyle, sMathMLData,
4540 std::size(sMathMLData))) {
4541 return data;
4542 }
4543 // Unknown MathML elements render as an mrow, see:
4544 // https://w3c.github.io/mathml-core/#ref-for-dfn-unknown-mathml-element-2
4545 static constexpr FrameConstructionData sMrowData =
4546 MATHML_DATA(NS_NewMathMLmrowFrame)FrameConstructionData { NS_NewMathMLmrowFrame, 0x8 | 0x10 | 0x20
}
;
4547 return &sMrowData;
4548}
4549
4550nsContainerFrame* nsCSSFrameConstructor::ConstructSVGFrameWithAnonymousChild(
4551 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4552 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
4553 ContainerFrameCreationFunc aConstructor,
4554 ContainerFrameCreationFunc aInnerConstructor, PseudoStyleType aInnerPseudo,
4555 bool aCandidateRootFrame) {
4556 nsIContent* const content = aItem.mContent;
4557 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4558
4559 // Create the outer frame:
4560 nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4561
4562 InitAndRestoreFrame(aState, content,
4563 aCandidateRootFrame
4564 ? aState.GetGeometricParent(
4565 *computedStyle->StyleDisplay(), aParentFrame)
4566 : aParentFrame,
4567 newFrame);
4568 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4569
4570 // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
4571 RefPtr<ComputedStyle> scForAnon =
4572 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(aInnerPseudo,
4573 computedStyle);
4574
4575 // Create the anonymous inner wrapper frame
4576 nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
4577
4578 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
4579
4580 // Put the newly created frames into the right child list
4581 SetInitialSingleChild(newFrame, innerFrame);
4582
4583 aState.AddChild(newFrame, aFrameList, content, aParentFrame,
4584 aCandidateRootFrame, aCandidateRootFrame);
4585
4586 if (!mRootElementFrame && aCandidateRootFrame) {
4587 mRootElementFrame = newFrame;
4588 }
4589
4590 nsFrameConstructorSaveState floatSaveState;
4591 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
4592
4593 nsFrameList childList;
4594
4595 // Process children
4596 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
4597 ConstructFramesFromItemList(
4598 aState, aItem.mChildItems, innerFrame,
4599 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
4600 } else {
4601 ProcessChildren(aState, content, computedStyle, innerFrame,
4602 /* aCanHaveGeneratedContent = */ false, childList, false);
4603 }
4604
4605 // Set the inner wrapper frame's initial primary list
4606 innerFrame->SetInitialChildList(FrameChildListID::Principal,
4607 std::move(childList));
4608
4609 return newFrame;
4610}
4611
4612nsIFrame* nsCSSFrameConstructor::ConstructOuterSVG(
4613 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4614 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4615 nsFrameList& aFrameList) {
4616 return ConstructSVGFrameWithAnonymousChild(
4617 aState, aItem, aParentFrame, aFrameList, NS_NewSVGOuterSVGFrame,
4618 NS_NewSVGOuterSVGAnonChildFrame, PseudoStyleType::MozSvgOuterSvgAnonChild,
4619 true);
4620}
4621
4622nsIFrame* nsCSSFrameConstructor::ConstructMarker(
4623 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4624 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4625 nsFrameList& aFrameList) {
4626 return ConstructSVGFrameWithAnonymousChild(
4627 aState, aItem, aParentFrame, aFrameList, NS_NewSVGMarkerFrame,
4628 NS_NewSVGMarkerAnonChildFrame, PseudoStyleType::MozSvgMarkerAnonChild,
4629 false);
4630}
4631
4632// Only outer <svg> elements can be floated or positioned. All other SVG
4633// should be in-flow.
4634#define SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
\
4635 FrameConstructionData(ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
, \
4636 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | \
4637 FCDATA_SKIP_ABSPOS_PUSH0x200 | \
4638 FCDATA_DISALLOW_GENERATED_CONTENT0x400)
4639#define SIMPLE_SVG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8
| 0x200 | 0x400)}
\
4640 {nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
}
4641
4642/* static */
4643const nsCSSFrameConstructor::FrameConstructionData*
4644nsCSSFrameConstructor::FindSVGData(const Element& aElement,
4645 nsIFrame* aParentFrame,
4646 bool aIsWithinSVGText,
4647 bool aAllowsTextPathChild,
4648 ComputedStyle& aStyle) {
4649 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", 4649); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsSVGElement()" ")"); do { MOZ_CrashSequence
(__null, 4649); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4650
4651 static constexpr FrameConstructionData sSuppressData = SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
4652 static constexpr FrameConstructionData sContainerData =
4653 SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)
;
4654
4655 bool parentIsSVG = aIsWithinSVGText;
4656 nsIContent* parentContent =
4657 aParentFrame ? aParentFrame->GetContent() : nullptr;
4658
4659 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4660
4661 if (aElement.OwnerDoc()->IsSVGGlyphsDocument()) {
4662 // SVG elements that are explicitly not supported in svg-glyphs documents.
4663 // (Partially applies the restrictions mentioned at
4664 // https://learn.microsoft.com/en-us/typography/opentype/spec/svg#svg-capability-requirements-and-restrictions
4665 if (tag == nsGkAtoms::text || tag == nsGkAtoms::tspan ||
4666 tag == nsGkAtoms::textPath || tag == nsGkAtoms::a ||
4667 tag == nsGkAtoms::foreignObject || tag == nsGkAtoms::svgSwitch ||
4668 tag == nsGkAtoms::view) {
4669 return &sSuppressData;
4670 }
4671 }
4672
4673 // XXXbz should this really be based on the tag of the parent frame's content?
4674 // Should it not be based on the type of the parent frame (e.g. whether it's
4675 // an SVG frame)?
4676 if (parentContent) {
4677 // It's not clear whether the SVG spec intends to allow any SVG
4678 // content within svg:foreignObject at all (SVG 1.1, section
4679 // 23.2), but if it does, it better be svg:svg. So given that
4680 // we're allowing it, treat it as a non-SVG parent.
4681 parentIsSVG =
4682 parentContent->IsSVGElement() &&
4683 parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
4684 }
4685
4686 if ((tag != nsGkAtoms::svg && !parentIsSVG) ||
4687 (tag == nsGkAtoms::desc || tag == nsGkAtoms::title ||
4688 tag == nsGkAtoms::metadata)) {
4689 // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4690 // svg:svg not contained within svg:svg are incorrect, although they
4691 // don't seem to specify error handling. Ignore them, since many of
4692 // our frame classes can't deal. It *may* be that the document
4693 // should at that point be considered in error according to F.2, but
4694 // it's hard to tell.
4695 //
4696 // We don't currently handle any UI for desc/title/metadata
4697 return &sSuppressData;
4698 }
4699
4700 // We don't need frames for animation elements
4701 if (aElement.IsSVGAnimationElement()) {
4702 return &sSuppressData;
4703 }
4704
4705 if (tag == nsGkAtoms::svg && !parentIsSVG) {
4706 // We need outer <svg> elements to have an SVGOuterSVGFrame regardless
4707 // of whether they fail conditional processing attributes, since various
4708 // SVG frames assume that one exists. We handle the non-rendering
4709 // of failing outer <svg> element contents like <switch> statements,
4710 // and do the PassesConditionalProcessingTests call in
4711 // SVGOuterSVGFrame::Init.
4712 static constexpr FrameConstructionData sOuterSVGData(
4713 &nsCSSFrameConstructor::ConstructOuterSVG);
4714 return &sOuterSVGData;
4715 }
4716
4717 if (tag == nsGkAtoms::marker) {
4718 static constexpr FrameConstructionData sMarkerSVGData(
4719 &nsCSSFrameConstructor::ConstructMarker);
4720 return &sMarkerSVGData;
4721 }
4722
4723 if (!aElement.PassesConditionalProcessingTests()) {
4724 // Elements with failing conditional processing attributes never get
4725 // rendered. Note that this is not where we select which frame in a
4726 // <switch> to render! That happens in SVGSwitchFrame::PaintSVG.
4727 if (aIsWithinSVGText) {
4728 // SVGTextFrame doesn't handle conditional processing attributes,
4729 // so don't create frames for descendants of <text> with failing
4730 // attributes. We need frames not to be created so that text layout
4731 // is correct.
4732 return &sSuppressData;
4733 }
4734 // If we're not inside <text>, create an SVGContainerFrame (which is a
4735 // frame that doesn't render) so that paint servers can still be referenced,
4736 // even if they live inside an element with failing conditional processing
4737 // attributes.
4738 return &sContainerData;
4739 }
4740
4741 // Ensure that a stop frame is a child of a gradient and that gradients
4742 // can only have stop children.
4743 bool parentIsGradient = aParentFrame && static_cast<SVGGradientFrame*>(
4744 do_QueryFrame(aParentFrame));
4745 bool stop = (tag == nsGkAtoms::stop);
4746 if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
4747 return &sSuppressData;
4748 }
4749
4750 // Prevent bad frame types being children of filters or parents of filter
4751 // primitives. If aParentFrame is null, we know that the frame that will
4752 // be created will be an nsInlineFrame, so it can never be a filter.
4753 bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
4754 if ((parentIsFilter && !aElement.IsSVGFilterPrimitiveElement()) ||
4755 (!parentIsFilter && aElement.IsSVGFilterPrimitiveElement())) {
4756 return &sSuppressData;
4757 }
4758
4759 // Prevent bad frame types being children of filter primitives or parents of
4760 // filter primitive children. If aParentFrame is null, we know that the frame
4761 // that will be created will be an nsInlineFrame, so it can never be a filter
4762 // primitive.
4763 bool parentIsFEContainerFrame =
4764 aParentFrame && aParentFrame->IsSVGFEContainerFrame();
4765 if ((parentIsFEContainerFrame &&
4766 !aElement.IsSVGFilterPrimitiveChildElement()) ||
4767 (!parentIsFEContainerFrame &&
4768 aElement.IsSVGFilterPrimitiveChildElement())) {
4769 return &sSuppressData;
4770 }
4771
4772 // Special cases for text/tspan/textPath, because the kind of frame
4773 // they get depends on the parent frame. We ignore 'a' elements when
4774 // determining the parent, however.
4775 if (aIsWithinSVGText) {
4776 // If aIsWithinSVGText is true, then we know that the "SVG text uses
4777 // CSS frames" pref was true when this SVG fragment was first constructed.
4778 //
4779 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
4780 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
4781 // really know how to deal with it. This kinda sucks. :(
4782 if (aParentFrame && aParentFrame->GetContent() != aElement.GetParent()) {
4783 return &sSuppressData;
4784 }
4785
4786 // We don't use ConstructInline because we want different behavior
4787 // for generated content.
4788 static constexpr FrameConstructionData sTSpanData(
4789 ToCreationFunc(NS_NewInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewInlineFrame(aPs, aStyle); }
,
4790 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_SKIP_ABSPOS_PUSH0x200 |
4791 FCDATA_DISALLOW_GENERATED_CONTENT0x400 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4792 FCDATA_IS_INLINE0x1000 | FCDATA_USE_CHILD_ITEMS0x10000);
4793 if (tag == nsGkAtoms::textPath) {
4794 if (aAllowsTextPathChild) {
4795 return &sTSpanData;
4796 }
4797 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::a) {
4798 return &sTSpanData;
4799 }
4800 return &sSuppressData;
4801 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::textPath) {
4802 return &sSuppressData;
4803 }
4804
4805 static constexpr FrameConstructionDataByTag sSVGData[] = {
4806 SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame){nsGkAtoms::svg, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGInnerSVGFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4807 SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame){nsGkAtoms::g, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4808 SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame){nsGkAtoms::svgSwitch, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGSwitchFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4809 SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame){nsGkAtoms::symbol, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGSymbolFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4810 SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame){nsGkAtoms::polygon, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4811 SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame){nsGkAtoms::polyline, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4812 SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame){nsGkAtoms::circle, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4813 SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame){nsGkAtoms::ellipse, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4814 SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame){nsGkAtoms::line, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4815 SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame){nsGkAtoms::rect, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4816 SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame){nsGkAtoms::path, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4817 SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame){nsGkAtoms::defs, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4818 {nsGkAtoms::text,
4819 {NS_NewSVGTextFrame,
4820 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_ALLOW_BLOCK_STYLES0x8000 |
4821 FCDATA_DISALLOW_GENERATED_CONTENT0x400,
4822 PseudoStyleType::MozSvgText}},
4823 {nsGkAtoms::foreignObject,
4824 {ToCreationFunc(NS_NewSVGForeignObjectFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewSVGForeignObjectFrame(aPs, aStyle); }
,
4825 FCDATA_DISALLOW_OUT_OF_FLOW0x8, PseudoStyleType::MozSvgForeignContent}},
4826 SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame){nsGkAtoms::a, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGAFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4827 SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame){nsGkAtoms::linearGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGLinearGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4828 SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame){nsGkAtoms::radialGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGRadialGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4829 SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame){nsGkAtoms::stop, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGStopFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4830 SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame){nsGkAtoms::use, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGUseFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4831 SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame){nsGkAtoms::view, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGViewFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4832 SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame){nsGkAtoms::image, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGImageFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4833 SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame){nsGkAtoms::clipPath, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGClipPathFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4834 SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame){nsGkAtoms::filter, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFilterFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4835 SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame){nsGkAtoms::pattern, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGPatternFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4836 SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame){nsGkAtoms::mask, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGMaskFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4837 SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feDistantLight, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4838 SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::fePointLight, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4839 SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feSpotLight, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4840 SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame){nsGkAtoms::feBlend, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4841 SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feColorMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4842 SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncR, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4843 SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncG, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4844 SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncB, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4845 SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncA, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4846 SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame){nsGkAtoms::feComposite, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4847 SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame){nsGkAtoms::feComponentTransfer, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4848 SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feConvolveMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4849 SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feDiffuseLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4850 SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame){nsGkAtoms::feDisplacementMap, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4851 SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame){nsGkAtoms::feDropShadow, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4852 SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame){nsGkAtoms::feFlood, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4853 SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame){nsGkAtoms::feGaussianBlur, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4854 SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame){nsGkAtoms::feImage, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEImageFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4855 SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame){nsGkAtoms::feMerge, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4856 SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feMergeNode, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4857 SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame){nsGkAtoms::feMorphology, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4858 SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame){nsGkAtoms::feOffset, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4859 SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feSpecularLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4860 SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame){nsGkAtoms::feTile, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4861 SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame){nsGkAtoms::feTurbulence, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
};
4862
4863 const FrameConstructionData* data =
4864 FindDataByTag(aElement, aStyle, sSVGData, std::size(sSVGData));
4865
4866 if (!data) {
4867 data = &sContainerData;
4868 }
4869
4870 return data;
4871}
4872
4873void nsCSSFrameConstructor::AppendPageBreakItem(
4874 nsIContent* aContent, FrameConstructionItemList& aItems) {
4875 RefPtr<ComputedStyle> pseudoStyle =
4876 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
4877 PseudoStyleType::MozPageBreak);
4878
4879 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"
, 4880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4880); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
4880 "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"
, 4880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4880); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4881
4882 static constexpr FrameConstructionData sPageBreakData(NS_NewPageBreakFrame,
4883 FCDATA_SKIP_FRAMESET0x1);
4884 aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
4885 true);
4886}
4887
4888bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
4889 nsFrameConstructorState& aState, nsIContent* aContent,
4890 nsContainerFrame* aParentFrame) {
4891 aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
4892 // XXX the GetContent() != aContent check is needed due to bug 135040.
4893 // Remove it once that's fixed.
4894 if (aContent->GetPrimaryFrame() &&
4895 aContent->GetPrimaryFrame()->GetContent() == aContent &&
4896 !aState.mCreatingExtraFrames) {
4897 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"
, 4899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4899); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4898 "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"
, 4899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4899); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4899 "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"
, 4899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4899); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4900 return false;
4901 }
4902
4903 // don't create a whitespace frame if aParent doesn't want it
4904 if (!NeedFrameFor(aState, aParentFrame, aContent)) {
4905 return false;
4906 }
4907
4908 // never create frames for comments or PIs
4909 if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
4910 return false;
4911 }
4912
4913 return true;
4914}
4915
4916void nsCSSFrameConstructor::AddFrameConstructionItems(
4917 nsFrameConstructorState& aState, nsIContent* aContent,
4918 bool aSuppressWhiteSpaceOptimizations, const ComputedStyle& aParentStyle,
4919 const InsertionPoint& aInsertion, FrameConstructionItemList& aItems,
4920 ItemFlags aFlags) {
4921 nsContainerFrame* parentFrame = aInsertion.mParentFrame;
4922 if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
4923 return;
4924 }
4925
4926 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
4927 auto flags = aFlags + ItemFlag::AllowPageBreak;
4928 if (parentFrame) {
4929 if (parentFrame->IsInSVGTextSubtree()) {
4930 flags += ItemFlag::IsWithinSVGText;
4931 }
4932 if (parentFrame->IsBlockFrame() && parentFrame->GetParent() &&
4933 parentFrame->GetParent()->IsSVGTextFrame()) {
4934 flags += ItemFlag::AllowTextPathChild;
4935 }
4936 }
4937 AddFrameConstructionItemsInternal(aState, aContent, parentFrame,
4938 aSuppressWhiteSpaceOptimizations,
4939 computedStyle, flags, aItems);
4940}
4941
4942// Whether we should suppress frames for a child under a <select> element.
4943// Right now we need this for two things:
4944// * To implement <option label>'s suppression of descendants (sad!)
4945// * To implement hiding of the <select>'s text content (hopefully going away
4946// soon enough, see https://github.com/whatwg/html/issues/12717).
4947static bool ShouldSuppressFrameForSelect(const nsIContent* aParent,
4948 const nsIContent& aChild) {
4949 if (!aParent) {
4950 return false;
4951 }
4952
4953 if (aChild.IsRootOfNativeAnonymousSubtree()) {
4954 // Allow native anonymous content no matter what.
4955 return false;
4956 }
4957
4958 if (aParent->IsHTMLElement(nsGkAtoms::option)) {
4959 // Options with labels have their label text added in ::before by forms.css.
4960 // Suppress frames for their children.
4961 // TODO(emilio): This should probably be done with shadow DOM instead (but a
4962 // ShadowRoot per option seems unfortunate...).
4963 return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
4964 }
4965
4966 if (const auto* select = HTMLSelectElement::FromNode(aParent)) {
4967 // Direct text descendants of listbox <select> are not expected to render.
4968 return !select->IsCombobox() && aChild.IsText() &&
4969 aParent == aChild.GetParent();
4970 }
4971
4972 return false;
4973}
4974
4975const nsCSSFrameConstructor::FrameConstructionData*
4976nsCSSFrameConstructor::FindDataForContent(nsIContent& aContent,
4977 ComputedStyle& aStyle,
4978 nsIFrame* aParentFrame,
4979 ItemFlags aFlags) {
4980 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", 4982
); 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, 4982); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4981 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", 4982
); 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, 4982); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4982 "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", 4982
); 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, 4982); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4983
4984 if (auto* text = Text::FromNode(aContent)) {
4985 return FindTextData(*text, aParentFrame);
4986 }
4987
4988 return FindElementData(*aContent.AsElement(), aStyle, aParentFrame, aFlags);
4989}
4990
4991const nsCSSFrameConstructor::FrameConstructionData*
4992nsCSSFrameConstructor::FindElementData(const Element& aElement,
4993 ComputedStyle& aStyle,
4994 nsIFrame* aParentFrame,
4995 ItemFlags aFlags) {
4996 // Don't create frames for non-SVG element children of SVG elements.
4997 if (!aElement.IsSVGElement()) {
4998 // NOTE: Anon content (from non display: contents) is allowed, the native
4999 // code should know what it's doing. In practice we care about ::backdrop
5000 // and the custom-content-container.
5001 if (aParentFrame && IsFrameForSVG(aParentFrame) &&
5002 !aParentFrame->IsSVGForeignObjectFrame() &&
5003 (aElement.GetParent() != aParentFrame->GetContent() ||
5004 !aElement.IsRootOfNativeAnonymousSubtree())) {
5005 return nullptr;
5006 }
5007 if (aFlags.contains(ItemFlag::IsWithinSVGText)) {
5008 return nullptr;
5009 }
5010 }
5011
5012 if (auto* data = FindElementTagData(aElement, aStyle, aParentFrame, aFlags)) {
5013 return data;
5014 }
5015
5016 // Check for 'content: <image-url>' on the element (which makes us ignore
5017 // 'display' values other than 'none' or 'contents').
5018 if (nsImageFrame::ShouldCreateImageFrameForContentProperty(aElement,
5019 aStyle)) {
5020 static constexpr FrameConstructionData sImgData(
5021 NS_NewImageFrameForContentProperty);
5022 return &sImgData;
5023 }
5024
5025 const bool shouldBlockify = aFlags.contains(ItemFlag::IsForRenderedLegend) ||
5026 aFlags.contains(ItemFlag::IsForOutsideMarker);
5027 if (shouldBlockify && !aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
5028 // Make a temp copy of StyleDisplay and blockify its mDisplay value.
5029 auto display = *aStyle.StyleDisplay();
5030 bool isRootElement = false;
5031 uint16_t rawDisplayValue =
5032 Servo_ComputedValues_BlockifiedDisplay(&aStyle, isRootElement);
5033 display.mDisplay = StyleDisplay{rawDisplayValue};
5034 return FindDisplayData(display, aElement);
5035 }
5036
5037 const auto& display = *aStyle.StyleDisplay();
5038 return FindDisplayData(display, aElement);
5039}
5040
5041const nsCSSFrameConstructor::FrameConstructionData*
5042nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
5043 ComputedStyle& aStyle,
5044 nsIFrame* aParentFrame,
5045 ItemFlags aFlags) {
5046 switch (aElement.GetNameSpaceID()) {
5047 case kNameSpaceID_XHTML3:
5048 return FindHTMLData(aElement, aParentFrame, aStyle);
5049 case kNameSpaceID_MathML6:
5050 return FindMathMLData(aElement, aStyle);
5051 case kNameSpaceID_SVG9:
5052 return FindSVGData(aElement, aParentFrame,
5053 aFlags.contains(ItemFlag::IsWithinSVGText),
5054 aFlags.contains(ItemFlag::AllowTextPathChild), aStyle);
5055 case kNameSpaceID_XUL8:
5056 return FindXULTagData(aElement, aStyle);
5057 default:
5058 return nullptr;
5059 }
5060}
5061
5062void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
5063 nsFrameConstructorState& aState, nsIContent* aContent,
5064 nsContainerFrame* aParentFrame, bool aSuppressWhiteSpaceOptimizations,
5065 ComputedStyle* aComputedStyle, ItemFlags aFlags,
5066 FrameConstructionItemList& aItems) {
5067 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"
, 5068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5068); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5068 "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"
, 5068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5068); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5069 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"
, 5069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsInComposedDoc()"
")"); do { MOZ_CrashSequence(__null, 5069); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5070 MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aContent->NodeInfo()->NameAtom() == nsGkAtoms::area
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aContent->NodeInfo()->NameAtom() == nsGkAtoms::area
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5071); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
")"); do { MOZ_CrashSequence(__null, 5071); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5071 aContent->NodeInfo()->NameAtom() == nsGkAtoms::area)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aContent->NodeInfo()->NameAtom() == nsGkAtoms::area
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames
|| aContent->NodeInfo()->NameAtom() == nsGkAtoms::area
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5071); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
")"); do { MOZ_CrashSequence(__null, 5071); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5072
5073 const bool withinSVGText = aFlags.contains(ItemFlag::IsWithinSVGText);
5074 const bool isGeneratedContent = aFlags.contains(ItemFlag::IsGeneratedContent);
5075 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"
, 5076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5076); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5076 "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"
, 5076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5076); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5077
5078 FrameConstructionItem* item = nullptr;
5079 auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
5080 if (isGeneratedContent && !item && !aState.mCreatingExtraFrames) {
5081 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"
, 5083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5083
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5082 "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"
, 5083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5083
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5083 "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"
, 5083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5083
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5084 aContent->UnbindFromTree();
5085 }
5086 });
5087
5088 // 'display:none' elements never creates any frames at all.
5089 const nsStyleDisplay& display = *aComputedStyle->StyleDisplay();
5090 if (display.mDisplay == StyleDisplay::None) {
5091 return;
5092 }
5093
5094 if (display.mDisplay == StyleDisplay::Contents) {
5095 // See the mDisplay fixup code in StyleAdjuster::adjust.
5096 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", 5097); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5097); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5097 "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", 5097); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5097); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5098
5099 // FIXME(bug 1588477): <svg:text>'s TextNodeCorrespondenceRecorder has
5100 // trouble with everything that looks like display: contents.
5101 if (withinSVGText) {
5102 return;
5103 }
5104
5105 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5106 *aComputedStyle, PseudoStyleType::Before,
5107 aItems);
5108
5109 FlattenedChildIterator iter(aContent);
5110 InsertionPoint insertion(aParentFrame, aContent);
5111 for (nsIContent* child = iter.GetNextChild(); child;
5112 child = iter.GetNextChild()) {
5113 AddFrameConstructionItems(aState, child, aSuppressWhiteSpaceOptimizations,
5114 *aComputedStyle, insertion, aItems, aFlags);
5115 }
5116 aItems.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
5117
5118 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5119 *aComputedStyle, PseudoStyleType::After, aItems);
5120 return;
5121 }
5122
5123 nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
5124 if (ShouldSuppressFrameForSelect(parent, *aContent)) {
5125 return;
5126 }
5127
5128 if (aContent->IsHTMLElement(nsGkAtoms::legend) && aParentFrame) {
5129 const nsFieldSetFrame* const fs = GetFieldSetFrameFor(aParentFrame);
5130 if (fs && !fs->GetLegend() && !aState.mHasRenderedLegend &&
5131 !aComputedStyle->StyleDisplay()->IsFloatingStyle() &&
5132 !aComputedStyle->StyleDisplay()->IsAbsolutelyPositionedStyle()) {
5133 aState.mHasRenderedLegend = true;
5134 aFlags += ItemFlag::IsForRenderedLegend;
5135 }
5136 }
5137
5138 const FrameConstructionData* const data =
5139 FindDataForContent(*aContent, *aComputedStyle, aParentFrame, aFlags);
5140 if (!data) {
5141 return;
5142 }
5143 const uint32_t bits = data->mBits;
5144 if (bits & FCDATA_SUPPRESS_FRAME0x40) {
5145 return;
5146 }
5147 // Create our shadow tree lazily if needed.
5148 // NOTE(emilio): This is rather hacky, we should ideally remove this and make
5149 // shadow tree creation faster, see bug 2017005.
5150 if (const RefPtr input = HTMLInputElement::FromNode(aContent)) {
5151 if (auto* sr = input->CreateShadowTreeFromLayoutIfNeeded()) {
5152 StyleNewChildRange(sr->GetFirstChild(), nullptr);
5153 }
5154 }
5155
5156 const bool canHavePageBreak =
5157 aFlags.contains(ItemFlag::AllowPageBreak) &&
5158 aState.mPresContext->IsPaginated() &&
5159 !display.IsAbsolutelyPositionedStyle() &&
5160 !(aParentFrame && aParentFrame->IsFlexOrGridContainer()) &&
5161 !(bits & FCDATA_IS_TABLE_PART0x800) && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5162 if (canHavePageBreak && display.BreakBefore()) {
5163 AppendPageBreakItem(aContent, aItems);
5164 }
5165
5166 if (!item) {
5167 item = aItems.AppendItem(this, data, aContent, do_AddRef(aComputedStyle),
5168 aSuppressWhiteSpaceOptimizations);
5169 if (aFlags.contains(ItemFlag::IsForRenderedLegend)) {
5170 item->mIsRenderedLegend = true;
5171 }
5172 }
5173 item->mIsText = !aContent->IsElement();
5174 item->mIsGeneratedContent = isGeneratedContent;
5175 item->mIsSharedGeneratedContent =
5176 isGeneratedContent && aState.mCreatingExtraFrames;
5177 if (isGeneratedContent) {
5178 // We need to keep this alive until the frame takes ownership.
5179 // This corresponds to the Release in ConstructFramesFromItem.
5180 item->mContent->AddRef();
5181 }
5182
5183 if (canHavePageBreak && display.BreakAfter()) {
5184 AppendPageBreakItem(aContent, aItems);
5185 }
5186
5187 if (bits & FCDATA_IS_INLINE0x1000) {
5188 // To correctly set item->mIsAllInline we need to build up our child items
5189 // right now.
5190 BuildInlineChildItems(aState, *item,
5191 aFlags.contains(ItemFlag::IsWithinSVGText),
5192 aFlags.contains(ItemFlag::AllowTextPathChild));
5193 item->mIsBlock = false;
5194 } else {
5195 // Compute a boolean isInline which is guaranteed to be false for blocks
5196 // (but may also be false for some inlines).
5197 const bool isInline =
5198 // Table-internal things are inline-outside if and only if they're kids
5199 // of inlines, since they'll trigger construction of inline-table
5200 // pseudos.
5201 ((bits & FCDATA_IS_TABLE_PART0x800) &&
5202 (!aParentFrame || // No aParentFrame means inline
5203 aParentFrame->StyleDisplay()->IsInlineFlow())) ||
5204 // Things that are inline-outside but aren't inline frames are inline
5205 display.IsInlineOutsideStyle();
5206
5207 // Set mIsAllInline conservatively. It just might be that even an inline
5208 // that has mIsAllInline false doesn't need an {ib} split. So this is just
5209 // an optimization to keep from doing too much work in cases when we can
5210 // show that mIsAllInline is true..
5211 item->mIsAllInline =
5212 isInline ||
5213 // Figure out whether we're guaranteed this item will be out of flow.
5214 // This is not a precise test, since one of our ancestor inlines might
5215 // add an absolute containing block (if it's relatively positioned) when
5216 // there wasn't such a containing block before. But it's conservative
5217 // in the sense that anything that will really end up as an in-flow
5218 // non-inline will test false here. In other words, if this test is
5219 // true we're guaranteed to be inline; if it's false we don't know what
5220 // we'll end up as.
5221 //
5222 // If we make this test precise, we can remove some of the code dealing
5223 // with the imprecision in ConstructInline and adjust the comments on
5224 // mIsAllInline and mIsBlock in the header.
5225 (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
5226 aState.GetGeometricParent(display, nullptr));
5227
5228 // Set mIsBlock conservatively. It's OK to set it false for some real
5229 // blocks, but not OK to set it true for things that aren't blocks. Since
5230 // isOutOfFlow might be false even in cases when the frame will end up
5231 // out-of-flow, we can't use it here. But we _can_ say that the frame will
5232 // for sure end up in-flow if it's not floated or absolutely positioned.
5233 item->mIsBlock = !isInline && !display.IsAbsolutelyPositionedStyle() &&
5234 !display.IsFloatingStyle() && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5235 }
5236
5237 if (item->mIsAllInline) {
5238 aItems.InlineItemAdded();
5239 } else if (item->mIsBlock) {
5240 aItems.BlockItemAdded();
5241 }
5242}
5243
5244/**
5245 * Return true if the frame construction item pointed to by aIter will
5246 * create a frame adjacent to a line boundary in the frame tree, and that
5247 * line boundary is induced by a content node adjacent to the frame's
5248 * content node in the content tree. The latter condition is necessary so
5249 * that ContentAppended/ContentInserted/ContentWillBeRemoved can easily find any
5250 * text nodes that were suppressed here.
5251 */
5252bool nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) {
5253 if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5254 return false;
5255 }
5256
5257 if (aIter.AtStart()) {
5258 if (aIter.List()->HasLineBoundaryAtStart() &&
5259 !aIter.item().mContent->GetPreviousSibling()) {
5260 return true;
5261 }
5262 } else {
5263 FCItemIterator prev = aIter;
5264 prev.Prev();
5265 if (prev.item().IsLineBoundary() &&
5266 !prev.item().mSuppressWhiteSpaceOptimizations &&
5267 aIter.item().mContent->GetPreviousSibling() == prev.item().mContent) {
5268 return true;
5269 }
5270 }
5271
5272 FCItemIterator next = aIter;
5273 next.Next();
5274 if (next.IsDone()) {
5275 if (aIter.List()->HasLineBoundaryAtEnd() &&
5276 !aIter.item().mContent->GetNextSibling()) {
5277 return true;
5278 }
5279 } else {
5280 if (next.item().IsLineBoundary() &&
5281 !next.item().mSuppressWhiteSpaceOptimizations &&
5282 aIter.item().mContent->GetNextSibling() == next.item().mContent) {
5283 return true;
5284 }
5285 }
5286
5287 return false;
5288}
5289
5290void nsCSSFrameConstructor::ConstructFramesFromItem(
5291 nsFrameConstructorState& aState, FCItemIterator& aIter,
5292 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
5293 FrameConstructionItem& item = aIter.item();
5294 ComputedStyle* computedStyle = item.mComputedStyle;
5295 if (item.mIsText) {
5296 // If this is collapsible whitespace next to a line boundary,
5297 // don't create a frame. item.IsWhitespace() also sets the
5298 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5299 // end up creating a frame, nsTextFrame::Init will clear the flag.)
5300 // We don't do this for generated content, because some generated
5301 // text content is empty text nodes that are about to be initialized.
5302 // (We check mAdditionalStateBits because only the generated content
5303 // container's frame construction item is marked with
5304 // mIsGeneratedContent, and we might not have an aParentFrame.)
5305 // We don't do it for content that may have Shadow DOM siblings / insertion
5306 // points, because they make it difficult to correctly create the frame due
5307 // to dynamic changes.
5308 // We don't do it for SVG text, since we might need to position and
5309 // measure the white space glyphs due to x/y/dx/dy attributes.
5310 if (AtLineBoundary(aIter) &&
5311 !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
5312 aIter.List()->ParentHasNoShadowDOM() &&
5313 !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
5314 (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) &&
5315 !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT0x80000) &&
5316 !mAlwaysCreateFramesForIgnorableWhitespace &&
5317 item.IsWhitespace(aState)) {
5318 return;
5319 }
5320
5321 ConstructTextFrame(item.mFCData, aState, item.mContent, aParentFrame,
5322 computedStyle, aFrameList);
5323 return;
5324 }
5325
5326 AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
5327 if (item.mIsGeneratedContent) {
5328 // Ensure that frames created here are all tagged with
5329 // NS_FRAME_GENERATED_CONTENT.
5330 aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
5331 }
5332
5333 // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5334 ConstructFrameFromItemInternal(item, aState, aParentFrame, aFrameList);
5335
5336 if (item.mIsGeneratedContent) {
5337 // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
5338 // The frame owns the generated content now.
5339 item.mContent->Release();
5340
5341 // Now that we've passed ownership of item.mContent to the frame, unset
5342 // our generated content flag so we don't release or unbind it ourselves.
5343 item.mIsGeneratedContent = false;
5344 }
5345}
5346
5347nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
5348 nsIFrame* aFrame, ContainingBlockType aType) {
5349 // Starting with aFrame, look for a frame that is absolutely positioned or
5350 // relatively positioned (and transformed, if aType is FIXED)
5351 for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
5352 if (frame->IsMathMLFrame()) {
5353 // If it's mathml, bail out -- no absolute positioning out from inside
5354 // mathml frames. Note that we don't make this part of the loop
5355 // condition because of the stuff at the end of this method...
5356 return nullptr;
5357 }
5358
5359 // Look for the ICB.
5360 if (aType == FIXED_POS &&
5361 (frame->IsViewportFrame() || frame->IsPageContentFrame())) {
5362 return static_cast<nsContainerFrame*>(frame);
5363 }
5364
5365 // If the frame is positioned, we will probably return it as the containing
5366 // block (see the exceptions below). Otherwise, we'll start looking at the
5367 // parent frame, unless we're dealing with a scrollframe.
5368 // Scrollframes are special since they're not positioned, but their
5369 // scrolledframe might be. So, we need to check this special case to return
5370 // the correct containing block (the scrolledframe) in that case.
5371 // If we're looking for a fixed-pos containing block and the frame is
5372 // not transformed, skip it.
5373 if (!frame->IsAbsPosContainingBlock()) {
5374 continue;
5375 }
5376 if (aType == FIXED_POS && !frame->IsFixedPosContainingBlock()) {
5377 continue;
5378 }
5379 nsIFrame* absPosCBCandidate = frame;
5380 if (absPosCBCandidate->IsFieldSetFrame()) {
5381 absPosCBCandidate =
5382 static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
5383 if (!absPosCBCandidate) {
5384 continue;
5385 }
5386 }
5387 if (absPosCBCandidate->IsScrollContainerFrame()) {
5388 ScrollContainerFrame* scrollContainerFrame =
5389 do_QueryFrame(absPosCBCandidate);
5390 absPosCBCandidate = scrollContainerFrame->GetScrolledFrame();
5391 if (!absPosCBCandidate) {
5392 continue;
5393 }
5394 }
5395 // Only first continuations or first IB-split siblings can be containing
5396 // blocks.
5397 absPosCBCandidate =
5398 nsLayoutUtils::FirstContinuationOrIBSplitSibling(absPosCBCandidate);
5399 // Is the frame really an absolute container?
5400 if (!absPosCBCandidate->IsAbsoluteContainer()) {
5401 continue;
5402 }
5403
5404 // For tables, skip the inner frame and consider the table wrapper frame.
5405 if (absPosCBCandidate->IsTableFrame()) {
5406 continue;
5407 }
5408 // For table wrapper frames, we can just return absPosCBCandidate.
5409 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", 5410
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5410); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5410 "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", 5410
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5410); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5411 return static_cast<nsContainerFrame*>(absPosCBCandidate);
5412 }
5413
5414 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"
, 5414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aType != FIXED_POS"
") (" "no ICB in this frame tree?" ")"); do { MOZ_CrashSequence
(__null, 5414); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5415
5416 // It is possible for the search for the containing block to fail, because
5417 // no absolute container can be found in the parent chain. In those cases,
5418 // we fall back to the document element's containing block.
5419 return mDocElementContainingBlock;
5420}
5421
5422nsContainerFrame* nsCSSFrameConstructor::GetFloatContainingBlock(
5423 nsIFrame* aFrame) {
5424 // Starting with aFrame, look for a frame that is a float containing block.
5425 // If we hit a frame which prevents its descendants from floating, bail out.
5426 // The logic here needs to match the logic in MaybePushFloatContainingBlock().
5427 for (nsIFrame* containingBlock = aFrame;
5428 containingBlock && !ShouldSuppressFloatingOfDescendants(containingBlock);
5429 containingBlock = containingBlock->GetParent()) {
5430 if (containingBlock->IsFloatContainingBlock()) {
5431 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", 5432
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5432); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5432 "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", 5432
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5432); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5433 return static_cast<nsContainerFrame*>(containingBlock);
5434 }
5435 }
5436
5437 // If we didn't find a containing block, then there just isn't
5438 // one.... return null
5439 return nullptr;
5440}
5441
5442/**
5443 * Finds the right parent frame to append content to aParentFrame.
5444 *
5445 * Cannot return or receive null.
5446 */
5447static nsContainerFrame* ContinuationToAppendTo(
5448 nsContainerFrame* aParentFrame) {
5449 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"
, 5449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 5449); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5450
5451 if (IsFramePartOfIBSplit(aParentFrame)) {
5452 // If the frame we are manipulating is a ib-split frame (that is, one that's
5453 // been created as a result of a block-in-inline situation) then we need to
5454 // append to the last ib-split sibling, not to the frame itself.
5455 //
5456 // Always make sure to look at the last continuation of the frame for the
5457 // {ib} case, even if that continuation is empty.
5458 //
5459 // We don't do this for the non-ib-split-frame case, since in the other
5460 // cases appending to the last nonempty continuation is fine and in fact not
5461 // doing that can confuse code that doesn't know to pull kids from
5462 // continuations other than its next one.
5463 return static_cast<nsContainerFrame*>(
5464 GetLastIBSplitSibling(aParentFrame)->LastContinuation());
5465 }
5466
5467 return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
5468}
5469
5470/**
5471 * This function will get the next sibling for a frame insert operation given
5472 * the parent and previous sibling. aPrevSibling may be null.
5473 */
5474static nsIFrame* GetInsertNextSibling(nsIFrame* aParentFrame,
5475 nsIFrame* aPrevSibling) {
5476 if (aPrevSibling) {
5477 return aPrevSibling->GetNextSibling();
5478 }
5479
5480 return aParentFrame->PrincipalChildList().FirstChild();
5481}
5482
5483void nsCSSFrameConstructor::AppendFramesToParent(
5484 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
5485 nsFrameList& aFrameList, nsIFrame* aPrevSibling, bool aIsRecursiveCall) {
5486 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"
, 5489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5487 !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"
, 5489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5488 !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"
, 5489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5489 "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"
, 5489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5490 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"
, 5491); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5491); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5491 "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"
, 5491); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5491); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5492 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"
, 5496); 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, 5496); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5493 !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"
, 5496); 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, 5496); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5494 !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"
, 5496); 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, 5496); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5495 "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"
, 5496); 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, 5496); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5496 "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"
, 5496); 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, 5496); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
5497
5498 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
5499
5500 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", 5505); MOZ_PretendNoReturn
(); } } while (0)
5501 !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", 5505); MOZ_PretendNoReturn
(); } } while (0)
5502 ->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", 5505); MOZ_PretendNoReturn
(); } } while (0)
5503 .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", 5505); MOZ_PretendNoReturn
(); } } while (0)
5504 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", 5505); MOZ_PretendNoReturn
(); } } while (0)
5505 "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", 5505); MOZ_PretendNoReturn
(); } } while (0)
;
5506 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", 5511); MOZ_PretendNoReturn
(); } } while (0)
5507 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", 5511); MOZ_PretendNoReturn
(); } } while (0)
5508 (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", 5511); MOZ_PretendNoReturn
(); } } while (0)
5509 !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", 5511); MOZ_PretendNoReturn
(); } } while (0)
5510 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", 5511); MOZ_PretendNoReturn
(); } } while (0)
5511 "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", 5511); MOZ_PretendNoReturn
(); } } while (0)
;
5512
5513 // If we're inserting a list of frames at the end of the trailing inline
5514 // of an {ib} split, we may need to create additional {ib} siblings to parent
5515 // them.
5516 if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
5517 // When we get here, our frame list might start with a block. If it does
5518 // so, and aParentFrame is an inline, and it and all its previous
5519 // continuations have no siblings, then put the initial blocks from the
5520 // frame list into the previous block of the {ib} split. Note that we
5521 // didn't want to stop at the block part of the split when figuring out
5522 // initial parent, because that could screw up float parenting; it's easier
5523 // to do this little fixup here instead.
5524 if (aFrameList.NotEmpty() && aFrameList.FirstChild()->IsBlockOutside()) {
5525 // See whether our trailing inline is empty
5526 nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
5527 if (firstContinuation->PrincipalChildList().IsEmpty()) {
5528 // Our trailing inline is empty. Collect our starting blocks from
5529 // aFrameList, get the right parent frame for them, and put them in.
5530 nsFrameList blockKids =
5531 aFrameList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
5532 NS_ASSERTION(blockKids.NotEmpty(), "No blocks?")do { if (!(blockKids.NotEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "No blocks?", "blockKids.NotEmpty()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5532); MOZ_PretendNoReturn(); } } while (0)
;
5533
5534 nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
5535 prevBlock =
5536 static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
5537 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"
, 5537); MOZ_PretendNoReturn(); } } while (0)
;
5538
5539 MoveChildrenTo(aParentFrame, prevBlock, blockKids);
5540 }
5541 }
5542
5543 // We want to put some of the frames into this inline frame.
5544 nsFrameList inlineKids =
5545 aFrameList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
5546
5547 if (!inlineKids.IsEmpty()) {
5548 AppendFrames(aParentFrame, FrameChildListID::Principal,
5549 std::move(inlineKids));
5550 }
5551
5552 if (!aFrameList.IsEmpty()) {
5553 nsFrameList ibSiblings;
5554 CreateIBSiblings(aState, aParentFrame,
5555 aParentFrame->IsAbsPosContainingBlock(), aFrameList,
5556 ibSiblings);
5557
5558 // Make sure to trigger reflow of the inline that used to be our
5559 // last one and now isn't anymore, since its GetSkipSides() has
5560 // changed.
5561 mPresShell->FrameNeedsReflow(aParentFrame,
5562 IntrinsicDirty::FrameAndAncestors,
5563 NS_FRAME_HAS_DIRTY_CHILDREN);
5564
5565 // Recurse so we create new ib siblings as needed for aParentFrame's
5566 // parent
5567 return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
5568 aParentFrame, true);
5569 }
5570 return;
5571 }
5572
5573 // If we're appending a list of frames to the last continuations of a
5574 // ::-moz-column-content, we may need to create column-span siblings for them.
5575 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
5576 // Extract any initial non-column-span kids, and append them to
5577 // ::-moz-column-content's child list.
5578 nsFrameList initialNonColumnSpanKids =
5579 aFrameList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
5580 AppendFrames(aParentFrame, FrameChildListID::Principal,
5581 std::move(initialNonColumnSpanKids));
5582
5583 if (aFrameList.IsEmpty()) {
5584 // No more kids to process (there weren't any column-span kids).
5585 return;
5586 }
5587
5588 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
5589 aState, aParentFrame, aFrameList,
5590 // Column content should never be a absolute/fixed positioned containing
5591 // block. Pass nullptr as aPositionedFrame.
5592 nullptr);
5593
5594 nsContainerFrame* columnSetWrapper = aParentFrame->GetParent();
5595 while (!columnSetWrapper->IsColumnSetWrapperFrame()) {
5596 columnSetWrapper = columnSetWrapper->GetParent();
5597 }
5598 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", 5599
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5599); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5599 "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", 5599
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5599); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5600
5601 FinishBuildingColumns(aState, columnSetWrapper, aParentFrame,
5602 columnSpanSiblings);
5603
5604 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", 5605
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5605); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5605 "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", 5605
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5605); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5606 return;
5607 }
5608
5609 // Insert the frames after our aPrevSibling
5610 InsertFrames(aParentFrame, FrameChildListID::Principal, aPrevSibling,
5611 std::move(aFrameList));
5612}
5613
5614template <nsCSSFrameConstructor::SiblingDirection aDirection>
5615nsIFrame* nsCSSFrameConstructor::FindSiblingInternal(
5616 FlattenedChildIterator& aIter) {
5617 auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
5618 return aDirection == SiblingDirection::Forward ? aIter.GetNextChild()
5619 : aIter.GetPreviousChild();
5620 };
5621
5622 auto getInsideMarkerFrame = [](const nsIContent* aContent) -> nsIFrame* {
5623 auto* marker = nsLayoutUtils::GetMarkerFrame(aContent);
5624 const bool isInsideMarker =
5625 marker && marker->GetInFlowParent()->StyleList()->mListStylePosition ==
5626 StyleListStylePosition::Inside;
5627 return isInsideMarker ? marker : nullptr;
5628 };
5629
5630 auto getNearPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5631 if (aDirection == SiblingDirection::Forward) {
5632 if (auto* backdrop = nsLayoutUtils::GetBackdropFrame(aContent)) {
5633 return backdrop;
5634 }
5635 if (auto* marker = getInsideMarkerFrame(aContent)) {
5636 return marker;
5637 }
5638 return nsLayoutUtils::GetBeforeFrame(aContent);
5639 }
5640 return nsLayoutUtils::GetAfterFrame(aContent);
5641 };
5642
5643 auto getFarPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5644 if (aDirection == SiblingDirection::Forward) {
5645 if (auto* pickerIcon = nsLayoutUtils::GetPickerIconFrame(aContent)) {
5646 return pickerIcon;
5647 }
5648 return nsLayoutUtils::GetAfterFrame(aContent);
5649 }
5650 if (auto* before = nsLayoutUtils::GetBeforeFrame(aContent)) {
5651 return before;
5652 }
5653 if (auto* marker = getInsideMarkerFrame(aContent)) {
5654 return marker;
5655 }
5656 return nsLayoutUtils::GetBackdropFrame(aContent);
5657 };
5658
5659 while (nsIContent* sibling = nextDomSibling(aIter)) {
5660 // NOTE(emilio): It's important to check GetPrimaryFrame() before
5661 // IsDisplayContents to get the correct insertion point when multiple
5662 // siblings go from display: non-none to display: contents.
5663 if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
5664 // XXX the GetContent() == sibling check is needed due to bug 135040.
5665 // Remove it once that's fixed.
5666 // The rendered legend check is needed because it is conceptually out of
5667 // flow. There can only be one rendered legend at a time, and we reframe
5668 // when that changes, so this is ok. Table captions are a similar case,
5669 // but there can be multiple of them and they instead get pulled out (and
5670 // the sibling fixed up) after building the frame list.
5671 if (primaryFrame->GetContent() == sibling &&
5672 !primaryFrame->IsRenderedLegend()) [[likely]] {
5673 return primaryFrame;
5674 }
5675 }
5676
5677 if (IsDisplayContents(sibling)) {
5678 if (nsIFrame* frame = getNearPseudo(sibling)) {
5679 return frame;
5680 }
5681
5682 const bool startFromBeginning = aDirection == SiblingDirection::Forward;
5683 FlattenedChildIterator iter(sibling, startFromBeginning);
5684 nsIFrame* sibling = FindSiblingInternal<aDirection>(iter);
5685 if (sibling) {
5686 return sibling;
5687 }
5688 }
5689 }
5690
5691 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"
, 5691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.ParentNode()->IsContent()"
")"); do { MOZ_CrashSequence(__null, 5691); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5692 return getFarPseudo(aIter.ParentNode()->AsContent());
5693}
5694
5695nsIFrame* nsCSSFrameConstructor::AdjustSiblingFrame(
5696 nsIFrame* aSibling, SiblingDirection aDirection) {
5697 if (!aSibling) {
5698 return nullptr;
5699 }
5700
5701 if (aSibling->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
5702 aSibling = aSibling->GetPlaceholderFrame();
5703 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"
, 5703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSibling" ")"
); do { MOZ_CrashSequence(__null, 5703); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5704 }
5705
5706 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"
, 5706); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aSibling->GetPrevContinuation()"
") (" "How?" ")"); do { MOZ_CrashSequence(__null, 5706); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5707 if (aDirection == SiblingDirection::Backward) {
5708 // The frame may be a ib-split frame (a split inline frame that contains a
5709 // block). Get the last part of that split.
5710 if (IsFramePartOfIBSplit(aSibling)) {
5711 aSibling = GetLastIBSplitSibling(aSibling);
5712 }
5713
5714 // The frame may have a continuation. If so, we want the last
5715 // non-overflow-container continuation as our previous sibling.
5716 aSibling = aSibling->GetTailContinuation();
5717 }
5718
5719 return aSibling;
5720}
5721
5722nsIFrame* nsCSSFrameConstructor::FindPreviousSibling(
5723 const FlattenedChildIterator& aIter) {
5724 return AdjustSiblingFrame(FindSibling<SiblingDirection::Backward>(aIter),
5725 SiblingDirection::Backward);
5726}
5727
5728nsIFrame* nsCSSFrameConstructor::FindNextSibling(
5729 const FlattenedChildIterator& aIter) {
5730 return AdjustSiblingFrame(FindSibling<SiblingDirection::Forward>(aIter),
5731 SiblingDirection::Forward);
5732}
5733
5734template <nsCSSFrameConstructor::SiblingDirection aDirection>
5735nsIFrame* nsCSSFrameConstructor::FindSibling(
5736 const FlattenedChildIterator& aIter) {
5737 FlattenedChildIterator siblingIter = aIter;
5738 nsIFrame* sibling = FindSiblingInternal<aDirection>(siblingIter);
5739 if (sibling) {
5740 return sibling;
5741 }
5742
5743 // Our siblings (if any) do not have a frame to guide us. The frame for the
5744 // target content should be inserted whereever a frame for the container would
5745 // be inserted. This is needed when inserting into display: contents nodes.
5746 const nsIContent* current = aIter.ParentNode()->AsContent();
5747 while (IsDisplayContents(current)) {
5748 const nsIContent* parent = current->GetFlattenedTreeParent();
5749 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", 5749
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "No display: contents on the root"
")"); do { MOZ_CrashSequence(__null, 5749); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5750
5751 FlattenedChildIterator iter(parent);
5752 iter.Seek(current);
5753 sibling = FindSiblingInternal<aDirection>(iter);
5754 if (sibling) {
5755 return sibling;
5756 }
5757
5758 current = parent;
5759 }
5760
5761 return nullptr;
5762}
5763
5764nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
5765 InsertionPoint* aInsertion, nsIContent* aChild, bool* aIsAppend) {
5766 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"
, 5766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInsertion->mParentFrame"
") (" "Must have parent frame to start with" ")"); do { MOZ_CrashSequence
(__null, 5766); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5767
5768 *aIsAppend = false;
5769
5770 // Find the frame that precedes the insertion point.
5771 FlattenedChildIterator iter(aInsertion->mContainer);
5772 if (!aChild->IsRootOfNativeAnonymousSubtree()) {
5773 // The check for IsRootOfNativeAnonymousSubtree() is because editor is
5774 // severely broken and calls us directly for native anonymous
5775 // nodes that it creates.
5776 iter.Seek(aChild);
5777 } else {
5778 // Prime the iterator for the call to FindPreviousSibling.
5779 (void)iter.GetNextChild();
5780 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"
, 5782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5782); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5781 "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"
, 5782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5782); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5782 "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"
, 5782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5782); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5783 }
5784
5785 // Note that FindPreviousSibling is passed the iterator by value, so that
5786 // the later usage of the iterator starts from the same place.
5787 nsIFrame* prevSibling = FindPreviousSibling(iter);
5788
5789 // Now, find the geometric parent so that we can handle continuations
5790 // properly. Use the prev sibling if we have it; otherwise use the next
5791 // sibling.
5792 if (prevSibling) {
5793 aInsertion->mParentFrame =
5794 prevSibling->GetParent()->GetContentInsertionFrame();
5795
5796 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5797 // Special-case anonymous flex / grid items: Elements are blockified
5798 // inside those containers, so the anonymous item is unlikely to be the
5799 // right parent unless we're inserting a non-whitespace text-node.
5800 //
5801 // If we guess wrong, we catch this in WipeContainingBlock, but with a
5802 // performance penalty (and sometimes correctness too, see bug 2014986).
5803 //
5804 // TODO(emilio): Are there other situations where this is worth doing
5805 // (some table anon boxes or something?). Seems hard to do at this stage
5806 // where we still don't _quite_ know the details of what aChild is (in or
5807 // out of flow, display inside or outside...). Maybe WipeContainingBlock
5808 // should be able to fix-up the insertion point at the last minute? But
5809 // that seems more sketchy since some code does rely on looking at the
5810 // insertion point to decide what to construct.
5811 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5812 if (!prevSibling->GetNextSibling() &&
5813 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5814 prevSibling = aInsertion->mParentFrame->GetTailContinuation();
5815 aInsertion->mParentFrame = prevSibling->GetParent();
5816 }
5817 }
5818
5819 *aIsAppend =
5820 !::GetInsertNextSibling(aInsertion->mParentFrame, prevSibling) &&
5821 !nsLayoutUtils::GetNextContinuationOrIBSplitSibling(
5822 aInsertion->mParentFrame) &&
5823 !IsWrapperPseudo(aInsertion->mParentFrame);
5824 } else if (nsIFrame* nextSibling = FindNextSibling(iter)) {
5825 // If there is no previous sibling, then find the frame that follows
5826 aInsertion->mParentFrame =
5827 nextSibling->GetParent()->GetContentInsertionFrame();
5828 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5829 // See the prevSibling special-case above.
5830 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5831 if (!nextSibling->GetPrevSibling() &&
5832 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5833 aInsertion->mParentFrame =
5834 aInsertion->mParentFrame->FirstContinuation()->GetParent();
5835 }
5836 }
5837 } else {
5838 // No previous or next sibling, so treat this like an appended frame.
5839 *aIsAppend = true;
5840
5841 aInsertion->mParentFrame =
5842 ::ContinuationToAppendTo(aInsertion->mParentFrame);
5843
5844 prevSibling = aInsertion->mParentFrame->PrincipalChildList().LastChild();
5845 }
5846
5847 return prevSibling;
5848}
5849
5850nsContainerFrame* nsCSSFrameConstructor::GetContentInsertionFrameFor(
5851 nsIContent* aContent) {
5852 nsIFrame* frame;
5853 while (!(frame = aContent->GetPrimaryFrame())) {
5854 if (!IsDisplayContents(aContent)) {
5855 return nullptr;
5856 }
5857
5858 aContent = aContent->GetFlattenedTreeParent();
5859 if (!aContent) {
5860 return nullptr;
5861 }
5862 }
5863
5864 // If the content of the frame is not the desired content then this is not
5865 // really a frame for the desired content.
5866 // XXX This check is needed due to bug 135040. Remove it once that's fixed.
5867 if (frame->GetContent() != aContent) {
5868 return nullptr;
5869 }
5870
5871 nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
5872
5873 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", 5875); MOZ_PretendNoReturn
(); } } while (0)
5874 "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", 5875); MOZ_PretendNoReturn
(); } } while (0)
5875 "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", 5875); MOZ_PretendNoReturn
(); } } while (0)
;
5876
5877 return insertionFrame;
5878}
5879
5880static bool IsSpecialFramesetChild(nsIContent* aContent) {
5881 // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
5882 return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
5883}
5884
5885static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode);
5886
5887void nsCSSFrameConstructor::AddTextItemIfNeeded(
5888 nsFrameConstructorState& aState, const ComputedStyle& aParentStyle,
5889 const InsertionPoint& aInsertion, nsIContent* aPossibleTextContent,
5890 FrameConstructionItemList& aItems) {
5891 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"
, 5891); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleTextContent"
") (" "Must have node" ")"); do { MOZ_CrashSequence(__null, 5891
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5892 if (!aPossibleTextContent->IsText() ||
5893 !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5894 aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
5895 // Not text, or not suppressed due to being all-whitespace (if it were being
5896 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5897 // going to be reframed anyway.
5898 return;
5899 }
5900 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", 5901
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5901); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5901 "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", 5901
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5901); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5902 AddFrameConstructionItems(aState, aPossibleTextContent, false, aParentStyle,
5903 aInsertion, aItems);
5904}
5905
5906void nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent) {
5907 if (!aContent->IsText() ||
5908 !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5909 aContent->HasFlag(NODE_NEEDS_FRAME)) {
5910 // Not text, or not suppressed due to being all-whitespace (if it were being
5911 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5912 // going to be reframed anyway.
5913 return;
5914 }
5915 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", 5916
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5916); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5916 "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", 5916
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5916); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5917 ContentInserted(aContent, InsertionKind::Async);
5918}
5919
5920#ifdef DEBUG1
5921void nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(
5922 nsIContent* aParent) {
5923 // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
5924 // we want to assert, but leaf frames that process their own children and may
5925 // ignore anonymous children (eg framesets) make this complicated. So we set
5926 // these two booleans if we encounter these situations and unset them if we
5927 // hit a node with a leaf frame.
5928 //
5929 // It's fine if one of node without primary frame is in a display:none
5930 // subtree.
5931 //
5932 // Also, it's fine if one of the nodes without primary frame is a display:
5933 // contents node.
5934 bool noPrimaryFrame = false;
5935 bool needsFrameBitSet = false;
5936 nsIContent* content = aParent;
5937 while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
5938 if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
5939 noPrimaryFrame = needsFrameBitSet = false;
5940 }
5941 if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
5942 noPrimaryFrame = !IsDisplayContents(content);
5943 }
5944 if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
5945 needsFrameBitSet = true;
5946 }
5947
5948 content = content->GetFlattenedTreeParent();
5949 }
5950 if (content && content->GetPrimaryFrame() &&
5951 content->GetPrimaryFrame()->IsLeaf()) {
5952 noPrimaryFrame = needsFrameBitSet = false;
5953 }
5954 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", 5956
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5956); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5955 "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", 5956
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5956); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5956 "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", 5956
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5956); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5957 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", 5959
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5958 "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", 5959
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5959 "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", 5959
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5959); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5960}
5961#endif
5962
5963// Returns true if this operation can be lazy, false if not.
5964//
5965// NOTE(emilio): This function assumes that the flattened tree
5966// parent of all the appended children is the same, which holds because this
5967// gets called after GetRangeInsertionPoint which notifies individually.
5968void nsCSSFrameConstructor::ConstructLazily(nsIContent* aStartChild,
5969 nsIContent* aEndChild) {
5970 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", 5970); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStartChild->GetParent()" ")"); do { MOZ_CrashSequence
(__null, 5970); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5971
5972 // We can construct lazily; just need to set suitable bits in the content
5973 // tree.
5974 Element* parent = aStartChild->GetFlattenedTreeParentElement();
5975 if (!parent) {
5976 // Not part of the flat tree, nothing to do.
5977 return;
5978 }
5979
5980 if (Servo_Element_IsDisplayNone(parent)) {
5981 // Nothing to do either.
5982 //
5983 // FIXME(emilio): This should be an assert, except for weird <frameset>
5984 // stuff that does its own frame construction. Such an assert would fire in
5985 // layout/style/crashtests/1411478.html, for example.
5986 return;
5987 }
5988
5989 // Set NODE_NEEDS_FRAME on the new nodes.
5990 for (nsIContent* child = aStartChild; child != aEndChild;
5991 child = child->GetNextSibling()) {
5992 NS_ASSERTION(!child->GetPrimaryFrame() ||do { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
5993 child->GetPrimaryFrame()->GetContent() != child,do { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
5994 // XXX the child->GetPrimaryFrame()->GetContent() != childdo { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
5995 // check is needed due to bug 135040. Remove it once that'sdo { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
5996 // fixed.do { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
5997 "setting NEEDS_FRAME on a node that already has a frame?")do { if (!(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "setting NEEDS_FRAME on a node that already has a frame?", "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 5997); MOZ_PretendNoReturn
(); } } while (0)
;
5998 child->SetFlags(NODE_NEEDS_FRAME);
5999 }
6000
6001 CheckBitsForLazyFrameConstruction(parent);
6002 parent->NoteDescendantsNeedFramesForServo();
6003}
6004
6005void nsCSSFrameConstructor::IssueSingleInsertNofications(
6006 nsIContent* aStartChild, nsIContent* aEndChild,
6007 InsertionKind aInsertionKind) {
6008 for (nsIContent* child = aStartChild; child != aEndChild;
6009 child = child->GetNextSibling()) {
6010 // XXX the GetContent() != child check is needed due to bug 135040.
6011 // Remove it once that's fixed.
6012 MOZ_ASSERT(!child->GetPrimaryFrame() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6013); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
")"); do { MOZ_CrashSequence(__null, 6013); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6013 child->GetPrimaryFrame()->GetContent() != child)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 6013); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
")"); do { MOZ_CrashSequence(__null, 6013); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6014
6015 // Call ContentRangeInserted with this node.
6016 ContentRangeInserted(child, child->GetNextSibling(), aInsertionKind);
6017 }
6018}
6019
6020nsCSSFrameConstructor::InsertionPoint
6021nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
6022 nsIContent* aEndChild,
6023 InsertionKind aInsertionKind) {
6024 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"
, 6024); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
")"); do { MOZ_CrashSequence(__null, 6024); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6025 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"
, 6025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 6025); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6026
6027 // If the children of the container may be distributed to different insertion
6028 // points, insert them separately and bail out, letting ContentInserted handle
6029 // the mess.
6030 if (aStartChild->GetParentNode()->GetShadowRoot()) {
6031 IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6032 return {};
6033 }
6034
6035#ifdef DEBUG1
6036 {
6037 nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
6038 for (nsIContent* child = aStartChild->GetNextSibling(); child;
6039 child = child->GetNextSibling()) {
6040 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"
, 6040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetFlattenedTreeParent() == expectedParent"
")"); do { MOZ_CrashSequence(__null, 6040); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6041 }
6042 }
6043#endif
6044
6045 // Now the flattened tree parent of all the siblings is the same, just use the
6046 // same insertion point.
6047 return GetInsertionPoint(aStartChild);
6048}
6049
6050bool nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6051 nsIContent* aStartChild,
6052 nsIContent* aEndChild) {
6053 if (aParentFrame->IsFrameSetFrame()) {
6054 // Check whether we have any kids we care about.
6055 for (nsIContent* cur = aStartChild; cur != aEndChild;
6056 cur = cur->GetNextSibling()) {
6057 if (IsSpecialFramesetChild(cur)) {
6058 // Just reframe the parent, since framesets are weird like that.
6059 RecreateFramesForContent(aParentFrame->GetContent(),
6060 InsertionKind::Async);
6061 return true;
6062 }
6063 }
6064 }
6065 return false;
6066}
6067
6068void nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
6069 nsIContent* aEndChild) {
6070 for (nsIContent* child = aStartChild; child != aEndChild;
6071 child = child->GetNextSibling()) {
6072 if (child->IsElement()) {
6073 child->AsElement()->NoteDirtyForServo();
6074 }
6075 }
6076}
6077
6078#ifdef DEBUG1
6079static bool IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild) {
6080 FlattenedChildIterator iter(aParent);
6081 for (nsIContent* node = iter.GetNextChild(); node;
6082 node = iter.GetNextChild()) {
6083 if (node == aChild) {
6084 return true;
6085 }
6086 }
6087 return false;
6088}
6089#endif
6090
6091void nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
6092 nsIContent* aEndChild) {
6093 ServoStyleSet* styleSet = mPresShell->StyleSet();
6094
6095 for (nsIContent* child = aStartChild; child != aEndChild;
6096 child = child->GetNextSibling()) {
6097 if (!child->IsElement()) {
6098 continue;
6099 }
6100
6101 Element* childElement = child->AsElement();
6102
6103 // We only come in here from non-lazy frame construction, so the children
6104 // should be unstyled.
6105 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"
, 6105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childElement->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 6105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6106
6107#ifdef DEBUG1
6108 {
6109 // Furthermore, all of them should have the same flattened tree parent
6110 // (GetRangeInsertionPoint ensures it). And that parent should be styled,
6111 // otherwise we would've never found an insertion point at all.
6112 Element* parent = childElement->GetFlattenedTreeParentElement();
6113 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"
, 6113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ")"
); do { MOZ_CrashSequence(__null, 6113); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6114 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", 6114); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parent->HasServoData()" ")"); do { MOZ_CrashSequence
(__null, 6114); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6115 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", 6117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6117); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6116 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", 6117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6117); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6117 "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", 6117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6117); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6118 }
6119#endif
6120
6121 styleSet->StyleNewSubtree(childElement);
6122 }
6123}
6124
6125// This is a bit slow, but sometimes we need it.
6126static bool ParentIsWrapperAnonBox(nsIFrame* aParent) {
6127 nsIFrame* maybeAnonBox = aParent;
6128 if (maybeAnonBox->Style()->GetPseudoType() ==
6129 PseudoStyleType::MozCellContent) {
6130 // The thing that would maybe be a wrapper anon box is the cell.
6131 maybeAnonBox = maybeAnonBox->GetParent();
6132 }
6133 return maybeAnonBox->Style()->IsWrapperAnonBox();
6134}
6135
6136void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
6137 InsertionKind aInsertionKind) {
6138 return ContentRangeInserted(aFirstNewContent, nullptr, aInsertionKind);
6139}
6140
6141void nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
6142 InsertionKind aInsertionKind) {
6143 ContentRangeInserted(aChild, aChild->GetNextSibling(), aInsertionKind);
6144}
6145
6146// It's very likely that we don't have any existing captions (because we only
6147// render one of them, see bug 144517). We also don't fragment table captions.
6148// So, prefer just walking the existing captions and searching it, rather than
6149// adding a special GetInsertionPrevSibling() version that skips everything but
6150// table captions.
6151static nsIFrame* FindCaptionPrevSibling(nsTableWrapperFrame* aTable,
6152 nsIContent* aCaptionContent) {
6153 nsIFrame* prevSibling = aTable->InnerTableFrame();
6154 if (nsIFrame* firstCaption = prevSibling->GetNextSibling()) {
6155 nsContentUtils::NodeIndexCache cache;
6156 for (auto* caption = firstCaption; caption;
6157 caption = caption->GetNextSibling()) {
6158 if (nsContentUtils::CompareTreePosition<TreeKind::Flat>(
6159 caption->GetContent(), aCaptionContent, nullptr, &cache) >= 0) {
6160 break;
6161 }
6162 prevSibling = caption;
6163 }
6164 }
6165 return prevSibling;
6166}
6167
6168// ContentRangeInserted handles creating frames for a range of nodes that
6169// might not be at the end of their childlist. ContentRangeInserted isn't a real
6170// content notification, but rather it handles regular ContentInserted calls
6171// for a single node as well as the lazy construction of frames for a range of
6172// nodes when called from CreateNeededFrames. For a range of nodes to be
6173// suitable to have its frames constructed all at once they must meet the same
6174// conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6175// these), plus more.
6176void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
6177 nsIContent* aEndChild,
6178 InsertionKind aInsertionKind) {
6179 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRangeInserted",mozilla::AutoProfilerLabelHot raiiObject6180( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6180 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6180( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6181 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6182
6183 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"
, 6183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
") (" "must always pass a child" ")"); do { MOZ_CrashSequence
(__null, 6183); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6184
6185#ifdef DEBUG1
6186 if (gNoisyContentUpdates) {
6187 printf(
6188 "nsCSSFrameConstructor::ContentRangeInserted container=%p "
6189 "start-child=%p end-child=%p lazy=%d\n",
6190 aStartChild->GetParent(), aStartChild, aEndChild,
6191 aInsertionKind == InsertionKind::Async);
6192 if (gReallyNoisyContentUpdates) {
6193 if (aStartChild->GetParent()) {
6194 aStartChild->GetParent()->List(stdoutstdout, 0);
6195 } else {
6196 aStartChild->List(stdoutstdout, 0);
6197 }
6198 }
6199 }
6200
6201 for (nsIContent* child = aStartChild; child != aEndChild;
6202 child = child->GetNextSibling()) {
6203 // XXX the GetContent() != child check is needed due to bug 135040.
6204 // Remove it once that's fixed.
6205 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
" (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6208
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6208); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6206 !child->GetPrimaryFrame() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
" (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6208
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6208); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6207 child->GetPrimaryFrame()->GetContent() != child,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
" (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6208
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6208); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6208 "asked to construct a frame for a node that already has a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || child->GetPrimaryFrame
()->GetContent() != child)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!child->GetPrimaryFrame()
|| child->GetPrimaryFrame()->GetContent() != child))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
" (" "asked to construct a frame for a node that already has a frame"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 6208
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
") (" "asked to construct a frame for a node that already has a frame"
")"); do { MOZ_CrashSequence(__null, 6208); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6209 }
6210#endif
6211
6212 // If we have a null parent, then this must be the document element being
6213 // inserted, or some other child of the document in the DOM (might be a
6214 // processing instruction or comment).
6215 if (!aStartChild->GetParent()) {
6216 Element* docElement = mDocument->GetRootElement();
6217 const bool foundRoot = [&] {
6218 for (nsIContent* cur = aStartChild; cur != aEndChild;
6219 cur = cur->GetNextSibling()) {
6220 if (cur == docElement) {
6221 return true;
6222 }
6223 }
6224 return false;
6225 }();
6226
6227 if (!foundRoot) {
6228 // Not the root element (could be e.g. a comment), just bail out
6229 return;
6230 }
6231
6232 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"
, 6232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "root element frame already created" ")"); do { MOZ_CrashSequence
(__null, 6232); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6233 if (aInsertionKind == InsertionKind::Async) {
6234 docElement->SetFlags(NODE_NEEDS_FRAME);
6235 LazilyStyleNewChildRange(docElement, nullptr);
6236 return;
6237 }
6238
6239 // Create frames for the document element and its child elements
6240 if (ConstructDocElementFrame(docElement)) {
6241 InvalidateCanvasIfNeeded(mPresShell, docElement);
6242#ifdef DEBUG1
6243 if (gReallyNoisyContentUpdates) {
6244 printf(
6245 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6246 "model:\n");
6247 mRootElementFrame->List(stdoutstdout);
6248 }
6249#endif
6250 }
6251
6252#ifdef ACCESSIBILITY1
6253 if (nsAccessibilityService* accService = GetAccService()) {
6254 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6255 }
6256#endif
6257 return;
6258 }
6259
6260 const bool isSingleInsert = aStartChild->GetNextSibling() == aEndChild;
6261 InsertionPoint insertion;
6262 if (isSingleInsert) {
6263 // See if we have a Shadow DOM insertion point. If so, then that's our real
6264 // parent frame; if not, then the frame hasn't been built yet and we just
6265 // bail.
6266 insertion = GetInsertionPoint(aStartChild);
6267 } else {
6268 // Get our insertion point. If we need to issue single ContentInserteds
6269 // GetRangeInsertionPoint will take care of that for us.
6270 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6271 insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
6272 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6273 }
6274
6275 if (!insertion.mParentFrame) {
6276 // We're punting on frame construction because there's no container frame.
6277 // The Servo-backed style system handles this case like the lazy frame
6278 // construction case, except when we're already constructing frames, in
6279 // which case we shouldn't need to do anything else.
6280 if (aInsertionKind == InsertionKind::Async) {
6281 LazilyStyleNewChildRange(aStartChild, aEndChild);
6282 }
6283 return;
6284 }
6285
6286 if (aInsertionKind == InsertionKind::Async) {
6287 ConstructLazily(aStartChild, aEndChild);
6288 LazilyStyleNewChildRange(aStartChild, aEndChild);
6289 return;
6290 }
6291
6292 bool isAppend;
6293 nsIFrame* prevSibling =
6294 GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6295
6296 LayoutFrameType frameType = insertion.mParentFrame->Type();
6297 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6298 if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild,
6299 aEndChild)) {
6300 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6301 return;
6302 }
6303 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6304
6305 // Don't construct kids of leaves
6306 if (insertion.mParentFrame->IsLeaf()) {
6307 // Clear lazy bits so we don't try to construct again.
6308 ClearLazyBits(aStartChild, aEndChild);
6309 return;
6310 }
6311
6312 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6313 if (WipeInsertionParent(insertion.mParentFrame)) {
6314 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6315 return;
6316 }
6317 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6318
6319 nsFrameConstructorState state(
6320 mPresShell, GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
6321 GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
6322 GetFloatContainingBlock(insertion.mParentFrame));
6323
6324 // Recover state for the containing block - we need to know if
6325 // it has :first-letter or :first-line style applied to it. The
6326 // reason we care is that the internal structure in these cases
6327 // is not the normal structure and requires custom updating
6328 // logic.
6329 nsContainerFrame* containingBlock = state.mFloatedList.mContainingBlock;
6330 bool haveFirstLetterStyle = false;
6331 bool haveFirstLineStyle = false;
6332
6333 // In order to shave off some cycles, we only dig up the
6334 // containing block haveFirst* flags if the parent frame where
6335 // the insertion/append is occurring is an inline or block
6336 // container. For other types of containers this isn't relevant.
6337 StyleDisplayInside parentDisplayInside =
6338 insertion.mParentFrame->StyleDisplay()->DisplayInside();
6339
6340 // Examine the insertion.mParentFrame where the insertion is taking
6341 // place. If it's a certain kind of container then some special
6342 // processing is done.
6343 if (StyleDisplayInside::Flow == parentDisplayInside) {
6344 // Recover the special style flags for the containing block
6345 if (containingBlock) {
6346 haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
6347 haveFirstLineStyle = ShouldHaveFirstLineStyle(
6348 containingBlock->GetContent(), containingBlock->Style());
6349 }
6350
6351 if (haveFirstLetterStyle) {
6352 // If our current insertion.mParentFrame is a Letter frame, use its parent
6353 // as our new parent hint
6354 if (insertion.mParentFrame->IsLetterFrame()) {
6355 // If insertion.mParentFrame is out of flow, then we actually want the
6356 // parent of the placeholder frame.
6357 if (insertion.mParentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6358 nsPlaceholderFrame* placeholderFrame =
6359 insertion.mParentFrame->GetPlaceholderFrame();
6360 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"
, 6360); MOZ_PretendNoReturn(); } } while (0)
;
6361 insertion.mParentFrame = placeholderFrame->GetParent();
6362 } else {
6363 insertion.mParentFrame = insertion.mParentFrame->GetParent();
6364 }
6365 }
6366
6367 // Remove the old letter frames before doing the insertion
6368 RemoveLetterFrames(mPresShell, state.mFloatedList.mContainingBlock);
6369
6370 // Removing the letterframes messes around with the frame tree, removing
6371 // and creating frames. We need to reget our prevsibling, parent frame,
6372 // etc.
6373 prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6374 frameType = insertion.mParentFrame->Type();
6375 }
6376 }
6377
6378 // This handles fallback to 'list-style-type' when a 'list-style-image' fails
6379 // to load.
6380 if (aStartChild->IsInNativeAnonymousSubtree() &&
6381 aStartChild->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
6382 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", 6382); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "isSingleInsert" ")"); do { MOZ_CrashSequence
(__null, 6382); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6383 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"
, 6385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6385); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6384 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"
, 6385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6385); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6385 "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"
, 6385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6385); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6386 nsIContent* const nextSibling = aStartChild->GetNextSibling();
6387 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", 6388
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6388); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6388 "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", 6388
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6388); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6389 DestroyContext context(mPresShell);
6390 RemoveFrame(context, FrameChildListID::Principal,
6391 nextSibling->GetPrimaryFrame());
6392 auto* const container = aStartChild->GetParent()->AsElement();
6393 nsIContent* firstNewChild = nullptr;
6394 auto InsertChild = [this, container, nextSibling,
6395 &firstNewChild](RefPtr<nsIContent>&& aChild) {
6396 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
6397 // here; it would get set under AppendChildTo. But AppendChildTo might
6398 // think that we're going from not being anonymous to being anonymous and
6399 // do some extra work; setting the flag here avoids that.
6400 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
6401 container->InsertChildBefore(aChild, nextSibling, false, IgnoreErrors());
6402 if (auto* childElement = Element::FromNode(aChild)) {
6403 // If we created any children elements, Servo needs to traverse them,
6404 // but the root is already set up.
6405 mPresShell->StyleSet()->StyleNewSubtree(childElement);
6406 }
6407 if (!firstNewChild) {
6408 firstNewChild = aChild;
6409 }
6410 };
6411 CreateGeneratedContentFromListStyleType(
6412 state, *insertion.mContainer->AsElement(),
6413 *insertion.mParentFrame->Style(), InsertChild);
6414 if (!firstNewChild) {
6415 // No fallback content - we're done.
6416 return;
6417 }
6418 aStartChild = firstNewChild;
6419 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"
, 6420); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6420); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6420 "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"
, 6420); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6420); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6421 }
6422
6423 AutoFrameConstructionItemList items(this);
6424 RefPtr<ComputedStyle> parentStyle =
6425 ResolveComputedStyle(insertion.mContainer);
6426 ParentType parentType = GetParentType(frameType);
6427 FlattenedChildIterator iter(insertion.mContainer);
6428 const bool haveNoShadowDOM =
6429 !iter.ShadowDOMInvolved() || !iter.GetNextChild();
6430 if (aStartChild->GetPreviousSibling() && parentType == eTypeBlock &&
6431 haveNoShadowDOM) {
6432 // If there's a text node in the normal content list just before the
6433 // new nodes, and it has no frame, make a frame construction item for
6434 // it, because it might need a frame now. No need to do this if our
6435 // parent type is not block, though, since WipeContainingBlock
6436 // already handles that situation.
6437 AddTextItemIfNeeded(state, *parentStyle, insertion,
6438 aStartChild->GetPreviousSibling(), items);
6439 }
6440
6441 const bool suppressWhiteSpaceOptimizations =
6442 isSingleInsert && aStartChild->IsRootOfNativeAnonymousSubtree();
6443 for (nsIContent* child = aStartChild; child != aEndChild;
6444 child = child->GetNextSibling()) {
6445 AddFrameConstructionItems(state, child, suppressWhiteSpaceOptimizations,
6446 *parentStyle, insertion, items);
6447 }
6448
6449 if (aEndChild && parentType == eTypeBlock && haveNoShadowDOM) {
6450 // If there's a text node in the normal content list just after the
6451 // new nodes, and it has no frame, make a frame construction item for
6452 // it, because it might need a frame now. No need to do this if our
6453 // parent type is not block, though, since WipeContainingBlock
6454 // already handles that situation.
6455 AddTextItemIfNeeded(state, *parentStyle, insertion, aEndChild, items);
6456 }
6457
6458 // Perform special check for diddling around with the frames in a special
6459 // inline frame. If we're appending before :after content, then we're not
6460 // really appending, so let WipeContainingBlock know that.
6461 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6462 if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
6463 isAppend, prevSibling)) {
6464 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6465 return;
6466 }
6467 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6468
6469 // If the parent is a block frame, and we're not in a special case
6470 // where frames can be moved around, determine if the list is for the
6471 // start or end of the block.
6472 if (insertion.mParentFrame->IsBlockFrameOrSubclass() &&
6473 !haveFirstLetterStyle && !haveFirstLineStyle &&
6474 !IsFramePartOfIBSplit(insertion.mParentFrame)) {
6475 items.SetLineBoundaryAtStart(!prevSibling ||
6476 !prevSibling->IsInlineOutside() ||
6477 prevSibling->IsBrFrame());
6478 auto* nextSibling =
6479 ::GetInsertNextSibling(insertion.mParentFrame, prevSibling);
6480 items.SetLineBoundaryAtEnd(!nextSibling ||
6481 !nextSibling->IsInlineOutside() ||
6482 nextSibling->IsBrFrame());
6483 }
6484 // To suppress whitespace-only text frames, we have to verify that
6485 // our container's DOM child list matches its flattened tree child list.
6486 items.SetParentHasNoShadowDOM(haveNoShadowDOM);
6487
6488 nsFrameConstructorSaveState floatSaveState;
6489 state.MaybePushFloatContainingBlock(insertion.mParentFrame, floatSaveState);
6490
6491 if (state.mPresContext->IsPaginated()) {
6492 // Because this function can be called outside frame construction, we need
6493 // to set state.mAutoPageNameValue based on what the parent frame's auto
6494 // value is.
6495 // Calling this from outside the frame constructor can violate many of the
6496 // expectations in AutoFrameConstructionPageName, and unlike during frame
6497 // construction we already have an auto value from parentFrame, so we do
6498 // not use AutoFrameConstructionPageName here.
6499 state.mAutoPageNameValue = insertion.mParentFrame->GetAutoPageValue();
6500#ifdef DEBUG1
6501 insertion.mParentFrame->mWasVisitedByAutoFrameConstructionPageName = true;
6502#endif
6503 }
6504
6505 // If the container is a table and a caption will be appended, it needs to be
6506 // put in the table wrapper frame's additional child list.
6507 // We make no attempt here to set flags to indicate whether the list
6508 // will be at the start or end of a block. It doesn't seem worthwhile.
6509 nsFrameList frameList, captionList;
6510 ConstructFramesFromItemList(state, items, insertion.mParentFrame,
6511 ParentIsWrapperAnonBox(insertion.mParentFrame),
6512 frameList);
6513
6514 if (frameList.NotEmpty()) {
6515 for (nsIContent* child = aStartChild; child != aEndChild;
6516 child = child->GetNextSibling()) {
6517 InvalidateCanvasIfNeeded(mPresShell, child);
6518 }
6519
6520 if (LayoutFrameType::Table == frameType ||
6521 LayoutFrameType::TableWrapper == frameType) {
6522 PullOutCaptionFrames(frameList, captionList);
6523 if (prevSibling && prevSibling->IsTableCaption()) {
6524 // This can happen, but only if the table is empty (otherwise
6525 // SafeToInsertPseudoNeedingChildren bails).
6526 prevSibling = nullptr;
6527 }
6528 }
6529 }
6530
6531 if (haveFirstLineStyle && insertion.mParentFrame == containingBlock &&
6532 isAppend) {
6533 // It's possible that the new frame goes into a first-line
6534 // frame. Look at it and see...
6535 AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
6536 frameList);
6537 } else if (insertion.mParentFrame->Style()->IsInFirstLineSubtree()) {
6538 CheckForFirstLineInsertion(insertion.mParentFrame, frameList);
6539 CheckForFirstLineInsertion(insertion.mParentFrame, captionList);
6540 }
6541
6542 // We might have captions; put them into the principal child list of the table
6543 // wrapper frame.
6544 if (captionList.NotEmpty()) {
6545 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", 6547); MOZ_PretendNoReturn
(); } } while (0)
6546 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", 6547); MOZ_PretendNoReturn
(); } } while (0)
6547 "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", 6547); MOZ_PretendNoReturn
(); } } while (0)
;
6548 // We need to determine where to put the caption items; start with the
6549 // the parent frame that has already been determined and get the insertion
6550 // prevsibling of the first caption item.
6551 nsContainerFrame* outerTable = insertion.mParentFrame->IsTableFrame()
6552 ? insertion.mParentFrame->GetParent()
6553 : insertion.mParentFrame;
6554
6555 // If the parent is not a table wrapper frame we will try to add frames
6556 // to a named child list that the parent does not honor and the frames
6557 // will get lost.
6558 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", 6560); 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, 6560); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6559 "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", 6560); 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, 6560); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6560 "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", 6560); 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, 6560); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6561
6562 nsIFrame* captionPrevSibling =
6563 FindCaptionPrevSibling(static_cast<nsTableWrapperFrame*>(outerTable),
6564 captionList.FirstChild()->GetContent());
6565 captionList.ApplySetParent(outerTable);
6566 if (!captionPrevSibling->GetNextSibling()) {
6567 AppendFrames(outerTable, FrameChildListID::Principal,
6568 std::move(captionList));
6569 } else {
6570 InsertFrames(outerTable, FrameChildListID::Principal, captionPrevSibling,
6571 std::move(captionList));
6572 }
6573 }
6574
6575 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6576 if (MaybeRecreateForColumnSpan(state, insertion.mParentFrame, frameList,
6577 prevSibling)) {
6578 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6579 return;
6580 }
6581 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6582
6583 if (frameList.NotEmpty()) {
6584 // Notify the parent frame
6585 if (isAppend) {
6586 AppendFramesToParent(state, insertion.mParentFrame, frameList,
6587 prevSibling);
6588 } else {
6589 InsertFrames(insertion.mParentFrame, FrameChildListID::Principal,
6590 prevSibling, std::move(frameList));
6591 }
6592 }
6593
6594 if (haveFirstLetterStyle) {
6595 // Recover the letter frames for the containing block when
6596 // it has first-letter style.
6597 RecoverLetterFrames(state.mFloatedList.mContainingBlock);
6598 }
6599
6600#ifdef DEBUG1
6601 if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
6602 printf(
6603 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6604 "model:\n");
6605 insertion.mParentFrame->List(stdoutstdout);
6606 }
6607#endif
6608
6609#ifdef ACCESSIBILITY1
6610 if (nsAccessibilityService* accService = GetAccService()) {
6611 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6612 }
6613#endif
6614}
6615
6616static bool IsWhitespaceFrame(const nsIFrame* aFrame) {
6617 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", 6617
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 6617); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6618 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
6619}
6620
6621static bool IsSyntheticColGroup(const nsIFrame* aFrame) {
6622 return aFrame->IsTableColGroupFrame() &&
6623 static_cast<const nsTableColGroupFrame*>(aFrame)->IsSynthetic();
6624}
6625
6626static bool IsOnlyNonWhitespaceFrameInList(
6627 const nsFrameList& aFrameList, const nsIFrame* aFrame,
6628 const nsIFrame* aIgnoreFrame = nullptr) {
6629 for (const nsIFrame* f : aFrameList) {
6630 if (f == aIgnoreFrame) {
6631 continue;
6632 }
6633 if (f == aFrame) {
6634 // If we have continuations, ignore them too.
6635 aFrame = aFrame->GetNextContinuation();
6636 } else if (!IsWhitespaceFrame(f) && !IsSyntheticColGroup(f)) {
6637 // Synthetic colgroups get created unconditionally, so let's not consider
6638 // them as giving us a non-whitespace frame.
6639 return false;
6640 }
6641 }
6642 return true;
6643}
6644
6645static bool AllChildListsAreEffectivelyEmpty(nsIFrame* aFrame) {
6646 for (auto& [list, listID] : aFrame->ChildLists()) {
6647 if (list.IsEmpty()) {
6648 continue;
6649 }
6650 // We have some existing frame, usually that would be considered as making
6651 // this list nonempty. But let's make an exception for the synthetic
6652 // colgroup that tables have, since that gets created unconditionally.
6653 if (listID == FrameChildListID::Principal && aFrame->IsTableFrame()) {
6654 if (nsIFrame* f = list.OnlyChild(); f && IsSyntheticColGroup(f)) {
6655 continue;
6656 }
6657 }
6658 return false;
6659 }
6660 return true;
6661}
6662
6663static bool SafeToInsertPseudoNeedingChildren(nsIFrame* aFrame) {
6664 return AllChildListsAreEffectivelyEmpty(aFrame);
6665}
6666
6667// Returns true if aFrame is the only meaningful child of aParent (which is
6668// known to be a wrapper-pseudo). This lets us determine whether aParent can be
6669// removed, as a result of aFrame being removed.
6670static bool IsOnlyMeaningfulChildOfWrapperPseudo(nsIFrame* aFrame,
6671 nsIFrame* aParent) {
6672 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", 6672); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsWrapperPseudo(aParent)" ")"); do { MOZ_CrashSequence
(__null, 6672); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6673 // Handle a few special cases with tables and colgroups / captions.
6674 if (aParent->IsTableFrame()) {
6675 auto* wrapper = aParent->GetParent();
6676 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"
, 6676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper" ")"
); do { MOZ_CrashSequence(__null, 6676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6677 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"
, 6677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6677); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6678 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", 6679
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6679); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6679 "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", 6679
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6679); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6680 // We can't remove the table if there are any captions present (captions are
6681 // never anonymous themselves), because table wrapper always relies on
6682 // having a table frame.
6683 if (!wrapper->PrincipalChildList().OnlyChild()) {
6684 return false;
6685 }
6686 }
6687 if (aFrame->IsTableCaption()) {
6688 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"
, 6688); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6688); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6689 auto* table = static_cast<nsTableWrapperFrame*>(aParent)->InnerTableFrame();
6690 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"
, 6690); AnnotateMozCrashReason("MOZ_ASSERT" "(" "table" ")")
; do { MOZ_CrashSequence(__null, 6690); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6691 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame,
6692 /* aIgnoreFrame = */ table) &&
6693 // This checks for both colgroups and the principal list of the table
6694 // frame.
6695 AllChildListsAreEffectivelyEmpty(table);
6696 }
6697 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame);
6698}
6699
6700static bool CanRemoveWrapperPseudoForChildRemoval(nsIFrame* aFrame,
6701 nsIFrame* aParent) {
6702 if (!IsOnlyMeaningfulChildOfWrapperPseudo(aFrame, aParent)) {
6703 return false;
6704 }
6705 if (aParent->GetPrevContinuation() || aParent->GetNextContinuation()) {
6706 // If our parent is fragmented we're not really the only meaningful child.
6707 return false;
6708 }
6709 if (aParent->IsRubyBaseContainerFrame()) {
6710 // We can't remove the first ruby base container of a ruby frame unless
6711 // it has no siblings. See CreateNeededPseudoSiblings.
6712 return aParent->GetPrevSibling() || !aParent->GetNextSibling();
6713 }
6714 return true;
6715}
6716
6717bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild,
6718 RemovalKind aKind) {
6719 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"
, 6719); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 6719); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6720 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"
, 6722); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6722); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6721 !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"
, 6722); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6722); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6722 "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"
, 6722); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6722); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6723 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentWillBeRemoved",mozilla::AutoProfilerLabelHot raiiObject6724( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6724 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6724( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6725 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6726 nsPresContext* presContext = mPresShell->GetPresContext();
6727 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"
, 6727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Our presShell should have a valid presContext" ")"); do
{ MOZ_CrashSequence(__null, 6727); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6728
6729 const bool wasRemovingContent = mRemovingContent;
6730 auto _ = MakeScopeExit([&] { mRemovingContent = wasRemovingContent; });
6731 mRemovingContent = true;
6732
6733 // We want to detect when the viewport override element stored in the
6734 // prescontext is in the subtree being removed. Except in fullscreen cases
6735 // (which are handled in Element::UnbindFromTree and do not get stored on the
6736 // prescontext), the override element is always either the root element or a
6737 // <body> child of the root element. So we can only be removing the stored
6738 // override element if the thing being removed is either the override element
6739 // itself or the root element (which can be a parent of the override element).
6740 //
6741 // The !wasRemovingContent check makes sure that we don't re-enter here from
6742 // other ContentWillBeRemoved calls, as that'd be useless work, and we don't
6743 // want to incorrectly pick aChild again as our viewport scroll style element
6744 // if it's getting removed from the DOM.
6745 if ((aChild == presContext->GetViewportScrollStylesOverrideElement() ||
6746 aChild->IsRootElement()) &&
6747 !wasRemovingContent) {
6748 // We might be removing the element that we propagated viewport scrollbar
6749 // styles from. Recompute those. (This clause covers two of the three
6750 // possible scrollbar-propagation sources: the <body> [as aChild or a
6751 // descendant] and the root node. The other possible scrollbar-propagation
6752 // source is a fullscreen element, and we have code elsewhere to update
6753 // scrollbars after fullscreen elements are removed -- specifically, it's
6754 // part of the fullscreen cleanup code called by Element::UnbindFromTree.
6755 // We don't handle the fullscreen case here, because it doesn't change the
6756 // scrollbar styles override element stored on the prescontext.)
6757 const Element* removingElement =
6758 aKind == RemovalKind::Dom ? aChild->AsElement() : nullptr;
6759 Element* newOverrideElement =
6760 presContext->UpdateViewportScrollStylesOverride(removingElement);
6761
6762 // If aChild is the root, then we don't need to do any reframing of
6763 // newOverrideElement, because we're about to tear down the whole frame tree
6764 // anyway. And we need to make sure we don't do any such reframing, because
6765 // reframing the <body> can trigger a reframe of the <html> and then reenter
6766 // here.
6767 //
6768 // But if aChild is not the root, and if newOverrideElement is not the root
6769 // and isn't aChild (which it could be if all we're doing here is reframing
6770 // the current override element), it needs reframing. In particular, it
6771 // used to have a scrollframe (because its overflow was not "visible"), but
6772 // now it will propagate its overflow to the viewport, so it should not need
6773 // a scrollframe anymore.
6774 if (aChild->GetParent() && newOverrideElement &&
6775 newOverrideElement->GetParent() && newOverrideElement != aChild) {
6776 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6777 RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
6778 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6779 }
6780 }
6781
6782#ifdef DEBUG1
6783 if (gNoisyContentUpdates) {
6784 printf(
6785 "nsCSSFrameConstructor::ContentWillBeRemoved container=%p child=%p\n",
6786 aChild->GetParent(), aChild);
6787 if (gReallyNoisyContentUpdates) {
6788 aChild->GetParent()->List(stdoutstdout, 0);
6789 }
6790 }
6791#endif
6792
6793 nsIFrame* childFrame = aChild->GetPrimaryFrame();
6794 if (!childFrame || childFrame->GetContent() != aChild) {
6795 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
6796 // Remove it once that's fixed.
6797 childFrame = nullptr;
6798 }
6799
6800 // If we're removing the root, then make sure to remove things starting at
6801 // the viewport's child instead of the primary frame (which might even be
6802 // null if the root was display:none, even though the frames above it got
6803 // created). Detecting removal of a root is a little exciting; in particular,
6804 // having no parent is necessary but NOT sufficient.
6805 //
6806 // Due to how we process reframes, the content node might not even be in our
6807 // document by now. So explicitly check whether the viewport's first kid's
6808 // content node is aChild.
6809 //
6810 // FIXME(emilio): I think the "might not be in our document" bit is impossible
6811 // now.
6812 bool isRoot = false;
6813 if (!aChild->GetParent()) {
6814 if (nsIFrame* viewport = GetRootFrame()) {
6815 nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
6816 if (firstChild && firstChild->GetContent() == aChild) {
6817 isRoot = true;
6818 childFrame = firstChild;
6819 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", 6819); MOZ_PretendNoReturn
(); } } while (0)
;
6820 }
6821 }
6822 }
6823
6824 // We need to be conservative about when to determine whether something has
6825 // display: contents or not because at this point our actual display may be
6826 // different.
6827 //
6828 // Consider the case of:
6829 //
6830 // <div id="A" style="display: contents"><div id="B"></div></div>
6831 //
6832 // If we reconstruct A because its display changed to "none", we still need to
6833 // cleanup the frame on B, but A's display is now "none", so we can't poke at
6834 // the style of it.
6835 //
6836 // FIXME(emilio, bug 1450366): We can make this faster without adding much
6837 // complexity for the display: none -> other case, which right now
6838 // unnecessarily walks the content tree down.
6839 auto CouldHaveBeenDisplayContents = [aKind](nsIContent* aContent) -> bool {
6840 return aContent->IsElement() && (aKind != RemovalKind::Dom ||
6841 IsDisplayContents(aContent->AsElement()));
6842 };
6843
6844 if (!childFrame) {
6845 if (CouldHaveBeenDisplayContents(aChild)) {
6846 // NOTE(emilio): We may iterate through ::before and ::after here and they
6847 // may be gone after the respective ContentWillBeRemoved call. Right now
6848 // StyleChildrenIterator handles that properly, so it's not an issue.
6849 StyleChildrenIterator iter(aChild);
6850 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
6851 if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(c)) {
6852 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6853 bool didReconstruct = ContentWillBeRemoved(c, aKind);
6854 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6855 if (didReconstruct) {
6856 return true;
6857 }
6858 }
6859 }
6860 }
6861 return false;
6862 }
6863
6864 InvalidateCanvasIfNeeded(mPresShell, aChild);
6865
6866 // See whether we need to remove more than just childFrame
6867 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6868 if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
6869 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6870 return true;
6871 }
6872 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6873
6874 // Get the childFrame's parent frame
6875 nsIFrame* parentFrame = childFrame->GetParent();
6876 LayoutFrameType parentType = parentFrame->Type();
6877
6878 if (parentType == LayoutFrameType::FrameSet &&
6879 IsSpecialFramesetChild(aChild)) {
6880 // Just reframe the parent, since framesets are weird like that.
6881 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6882 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6883 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6884 return true;
6885 }
6886
6887 // If we're a child of MathML, then we should reframe the MathML content.
6888 // If we're non-MathML, then we would be wrapped in a block so we need to
6889 // check our grandparent in that case.
6890 nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
6891 ? parentFrame->GetParent()
6892 : parentFrame;
6893 if (possibleMathMLAncestor->IsMathMLFrame()) {
6894 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6895 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6896 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6897 return true;
6898 }
6899
6900#ifdef ACCESSIBILITY1
6901 if (aKind != RemovalKind::ForReconstruction) {
6902 if (nsAccessibilityService* accService = GetAccService()) {
6903 accService->ContentRemoved(mPresShell, aChild);
6904 }
6905 }
6906#endif
6907
6908 // Examine the containing-block for the removed content and see if
6909 // :first-letter style applies.
6910 nsIFrame* inflowChild = childFrame;
6911 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6912 inflowChild = childFrame->GetPlaceholderFrame();
6913 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"
, 6913); MOZ_PretendNoReturn(); } } while (0)
;
6914 }
6915 nsContainerFrame* containingBlock =
6916 GetFloatContainingBlock(inflowChild->GetParent());
6917 bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
6918 if (haveFLS) {
6919 // Trap out to special routine that handles adjusting a blocks
6920 // frame tree when first-letter style is present.
6921#ifdef NOISY_FIRST_LETTER
6922 printf("ContentWillBeRemoved: containingBlock=");
6923 containingBlock->ListTag(stdoutstdout);
6924 printf(" parentFrame=");
6925 parentFrame->ListTag(stdoutstdout);
6926 printf(" childFrame=");
6927 childFrame->ListTag(stdoutstdout);
6928 printf("\n");
6929#endif
6930
6931 // First update the containing blocks structure by removing the
6932 // existing letter frames. This makes the subsequent logic
6933 // simpler.
6934 RemoveLetterFrames(mPresShell, containingBlock);
6935
6936 // Recover childFrame and parentFrame
6937 childFrame = aChild->GetPrimaryFrame();
6938 if (!childFrame || childFrame->GetContent() != aChild) {
6939 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
6940 // Remove it once that's fixed.
6941 return false;
6942 }
6943 parentFrame = childFrame->GetParent();
6944 parentType = parentFrame->Type();
Value stored to 'parentType' is never read
6945
6946#ifdef NOISY_FIRST_LETTER
6947 printf(" ==> revised parentFrame=");
6948 parentFrame->ListTag(stdoutstdout);
6949 printf(" childFrame=");
6950 childFrame->ListTag(stdoutstdout);
6951 printf("\n");
6952#endif
6953 }
6954
6955#ifdef DEBUG1
6956 if (gReallyNoisyContentUpdates) {
6957 printf("nsCSSFrameConstructor::ContentWillBeRemoved: childFrame=");
6958 childFrame->ListTag(stdoutstdout);
6959 putchar('\n');
6960 parentFrame->List(stdoutstdout);
6961 }
6962#endif
6963
6964 // Notify the parent frame that it should delete the frame
6965 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6966 childFrame = childFrame->GetPlaceholderFrame();
6967 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"
, 6967); MOZ_PretendNoReturn(); } } while (0)
;
6968 parentFrame = childFrame->GetParent();
6969 }
6970
6971 // Take care of wrapper anonymous boxes that we might need to remove while
6972 // at it. Note that MaybeRecreateContainerForFrameRemoval takes care of
6973 // harder cases (merging sibling anonymous boxes etc).
6974 while (IsWrapperPseudo(parentFrame) &&
6975 CanRemoveWrapperPseudoForChildRemoval(childFrame, parentFrame)) {
6976 childFrame = parentFrame;
6977 parentFrame = childFrame->GetParent();
6978 }
6979
6980 const bool canSkipWhitespaceFixup = [&] {
6981 if (aKind == RemovalKind::ForReconstruction) {
6982 // If we're just reconstructing frames for the element, then the
6983 // following ContentInserted notification on the element will
6984 // take care of fixing up any adjacent white-space text nodes.
6985 return true;
6986 }
6987 switch (parentFrame->Type()) {
6988 case LayoutFrameType::Table:
6989 case LayoutFrameType::TableRow:
6990 case LayoutFrameType::TableRowGroup:
6991 case LayoutFrameType::TableCol:
6992 case LayoutFrameType::TableColGroup:
6993 case LayoutFrameType::TableWrapper: {
6994 // Tables ignore all whitespace within their wrappers, so we can avoid
6995 // reconstructing adjacent whitespace if the table is not anonymous.
6996 if (!IsInAnonymousTable(parentFrame)) {
6997 return true;
6998 }
6999 // If the table is anonymous and the child is at the edges, we might
7000 // need to create whitespace at the edges of the table that wasn't
7001 // there before, so we can only skip the check if childFrame has frames
7002 // around. Captions are extra-special here, because they're siblings
7003 // with the main table frame, so we can't count that as a relevant
7004 // sibling for our purposes.
7005 auto* prevSibling = childFrame->GetPrevSibling();
7006 return prevSibling && !prevSibling->IsTableFrame() &&
7007 childFrame->GetNextSibling();
7008 }
7009 case LayoutFrameType::GridContainer:
7010 case LayoutFrameType::FlexContainer:
7011 // Flex and grid containers similarly skip whitespace and wrap
7012 // non-whitespace in anonymous flex items, so any change to
7013 // white-space that could matter would have triggered the
7014 // reconstruction of the container itself due to merging anonymous
7015 // grid / flex items.
7016 return true;
7017 default:
7018 break;
7019 }
7020 return false;
7021 }();
7022 DestroyContext context(mPresShell);
7023 RemoveFrame(context, nsLayoutUtils::GetChildListNameFor(childFrame),
7024 childFrame);
7025
7026 // NOTE(emilio): aChild could be dead here already if it is a ::before or
7027 // ::after pseudo-element (since in that case it was owned by childFrame,
7028 // which we just destroyed).
7029
7030 if (isRoot) {
7031 mRootElementFrame = nullptr;
7032 mRootElementStyleFrame = nullptr;
7033 mDocElementContainingBlock = nullptr;
7034 mCanvasFrame = nullptr;
7035 mPageSequenceFrame = nullptr;
7036 }
7037
7038 if (haveFLS && mRootElementFrame) {
7039 RecoverLetterFrames(containingBlock);
7040 }
7041
7042 if (!canSkipWhitespaceFixup) {
7043 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"
, 7044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7044); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7044 "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"
, 7044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7044); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7045 // Adjacent whitespace-only text nodes might have been suppressed if
7046 // this node does not have inline ends. Create frames for them now
7047 // if necessary.
7048 // Reframe any text node just before the node being removed, if there is
7049 // one, and if it's not the last child or the first child. If a whitespace
7050 // textframe was being suppressed and it's now the last child or first
7051 // child then it can stay suppressed since the parent must be a block
7052 // and hence it's adjacent to a block end.
7053 // If aOldNextSibling is null, then the text node before the node being
7054 // removed is the last node, and we don't need to worry about it.
7055 nsIContent* prevSibling = aChild->GetPreviousSibling();
7056 if (prevSibling && prevSibling->GetPreviousSibling()) {
7057 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7058 ReframeTextIfNeeded(prevSibling);
7059 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7060 }
7061 // Reframe any text node just after the node being removed, if there is
7062 // one, and if it's not the last child or the first child.
7063 nsIContent* nextSibling = aChild->GetNextSibling();
7064 if (nextSibling && prevSibling && nextSibling->GetNextSibling()) {
7065 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7066 ReframeTextIfNeeded(nextSibling);
7067 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7068 }
7069 }
7070
7071#ifdef DEBUG1
7072 if (gReallyNoisyContentUpdates && parentFrame) {
7073 printf(
7074 "nsCSSFrameConstructor::ContentWillBeRemoved: resulting frame "
7075 "model:\n");
7076 parentFrame->List(stdoutstdout);
7077 }
7078#endif
7079
7080 return false;
7081}
7082
7083/**
7084 * This method invalidates the canvas when frames are removed or added for a
7085 * node that might have its background propagated to the canvas, i.e., a
7086 * document root node or an HTML BODY which is a child of the root node.
7087 *
7088 * @param aFrame a frame for a content node about to be removed or a frame that
7089 * was just created for a content node that was inserted.
7090 */
7091static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode) {
7092 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", 7092); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPresShell->GetRootFrame()" ") (" "What happened here?"
")"); do { MOZ_CrashSequence(__null, 7092); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7093 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"
, 7093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell->GetPresContext()"
") (" "Say what?" ")"); do { MOZ_CrashSequence(__null, 7093)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
7094
7095 // Note that both in ContentWillBeRemoved and ContentInserted the content
7096 // node will still have the right parent pointer, so looking at that is ok.
7097
7098 nsIContent* parent = aNode->GetParent();
7099 if (parent) {
7100 // Has a parent; might not be what we want
7101 nsIContent* grandParent = parent->GetParent();
7102 if (grandParent) {
7103 // Has a grandparent, so not what we want
7104 return;
7105 }
7106
7107 // Check whether it's an HTML body
7108 if (!aNode->IsHTMLElement(nsGkAtoms::body)) {
7109 return;
7110 }
7111 }
7112
7113 // At this point the node has no parent or it's an HTML <body> child of the
7114 // root. We might not need to invalidate in this case (eg we might be in
7115 // XHTML or something), but chances are we want to. Play it safe.
7116 // Invalidate the viewport.
7117
7118 nsIFrame* rootFrame = aPresShell->GetRootFrame();
7119 rootFrame->InvalidateFrameSubtree();
7120}
7121
7122bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
7123 CharacterData* aContent) {
7124 if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
7125 return false;
7126 }
7127
7128 if (mAlwaysCreateFramesForIgnorableWhitespace) {
7129 return false;
7130 }
7131
7132 // Text frame may have been suppressed. Disable suppression and signal that a
7133 // flush should be performed. We do this on a document-wide basis so that
7134 // pages that repeatedly query metrics for collapsed-whitespace text nodes
7135 // don't trigger pathological behavior.
7136 mAlwaysCreateFramesForIgnorableWhitespace = true;
7137 Element* root = mDocument->GetRootElement();
7138 if (!root) {
7139 return false;
7140 }
7141
7142 RestyleManager()->PostRestyleEvent(root, RestyleHint{0},
7143 nsChangeHint_ReconstructFrame);
7144 return true;
7145}
7146
7147void nsCSSFrameConstructor::CharacterDataChanged(
7148 nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
7149 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::CharacterDataChanged",mozilla::AutoProfilerLabelHot raiiObject7150( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
7150 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject7150( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
7151 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
7152
7153 if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
7154 !aContent->TextIsOnlyWhitespace()) ||
7155 (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
7156 aContent->TextIsOnlyWhitespace())) {
7157#ifdef DEBUG1
7158 nsIFrame* frame = aContent->GetPrimaryFrame();
7159 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"
, 7160); MOZ_PretendNoReturn(); } } while (0)
7160 "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"
, 7160); MOZ_PretendNoReturn(); } } while (0)
;
7161#endif
7162 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7163 RecreateFramesForContent(aContent, InsertionKind::Async);
7164 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7165 return;
7166 }
7167
7168 // It's possible the frame whose content changed isn't inserted into the
7169 // frame hierarchy yet, or that there is no frame that maps the content
7170 if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
7171#if 0
7172 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p"
, aContent, ContentTag(aContent, 0), aSubContent, frame); } }
while (0)
7173 ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p"
, aContent, ContentTag(aContent, 0), aSubContent, frame); } }
while (0)
7174 aContent, ContentTag(aContent, 0),do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p"
, aContent, ContentTag(aContent, 0), aSubContent, frame); } }
while (0)
7175 aSubContent, frame))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p"
, aContent, ContentTag(aContent, 0), aSubContent, frame); } }
while (0)
;
7176#endif
7177
7178 if (frame->HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI)) {
7179 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7180 RecreateFramesForContent(aContent, InsertionKind::Async);
7181 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7182 return;
7183 }
7184
7185 // Special check for text content that is a child of a letter frame. If
7186 // this happens, we should remove the letter frame, do whatever we're
7187 // planning to do with this notification, then put the letter frame back.
7188 // Note that this is basically what RecreateFramesForContent ends up doing;
7189 // the reason we dont' want to call that here is that our text content
7190 // could be native anonymous, in which case RecreateFramesForContent would
7191 // completely barf on it. And recreating the non-anonymous ancestor would
7192 // just lead us to come back into this notification (e.g. if quotes or
7193 // counters are involved), leading to a loop.
7194 nsContainerFrame* block = GetFloatContainingBlock(frame);
7195 bool haveFirstLetterStyle = false;
7196 if (block) {
7197 // See if the block has first-letter style applied to it.
7198 haveFirstLetterStyle = HasFirstLetterStyle(block);
7199 if (haveFirstLetterStyle) {
7200 RemoveLetterFrames(mPresShell, block);
7201 // Reget |frame|, since we might have killed it.
7202 // Do we really need to call CharacterDataChanged in this case, though?
7203 frame = aContent->GetPrimaryFrame();
7204 NS_ASSERTION(frame, "Should have frame here!")do { if (!(frame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have frame here!"
, "frame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7204); MOZ_PretendNoReturn(); } } while (0)
;
7205 }
7206 }
7207
7208 // Notify the first frame that maps the content. It will generate a reflow
7209 // command
7210 frame->CharacterDataChanged(aInfo);
7211
7212 if (haveFirstLetterStyle) {
7213 RecoverLetterFrames(block);
7214 }
7215 }
7216}
7217
7218void nsCSSFrameConstructor::RecalcQuotesAndCounters() {
7219 nsAutoScriptBlocker scriptBlocker;
7220
7221 if (mQuotesDirty) {
7222 mQuotesDirty = false;
7223 mContainStyleScopeManager.RecalcAllQuotes();
7224 }
7225
7226 if (mCountersDirty) {
7227 mCountersDirty = false;
7228 mContainStyleScopeManager.RecalcAllCounters();
7229 }
7230
7231 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"
, 7231); MOZ_PretendNoReturn(); } } while (0)
;
7232 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"
, 7232); MOZ_PretendNoReturn(); } } while (0)
;
7233}
7234
7235void nsCSSFrameConstructor::NotifyCounterStylesAreDirty() {
7236 mContainStyleScopeManager.SetAllCountersDirty();
7237 CountersDirty();
7238}
7239
7240void nsCSSFrameConstructor::WillDestroyFrameTree() {
7241#if defined(DEBUG_dbaron_off)
7242 mContainStyleScopeManager.DumpCounters();
7243#endif
7244
7245 // Prevent frame tree destruction from being O(N^2)
7246 mContainStyleScopeManager.Clear();
7247 nsFrameManager::Destroy();
7248}
7249
7250// STATIC
7251
7252// XXXbz I'd really like this method to go away. Once we have inline-block and
7253// I can just use that for sized broken images, that can happen, maybe.
7254//
7255// NOTE(emilio): This needs to match MozAltContent handling.
7256void nsCSSFrameConstructor::GetAlternateTextFor(const Element& aElement,
7257 nsAString& aAltText) {
7258 // The "alt" attribute specifies alternate text that is rendered
7259 // when the image can not be displayed.
7260 if (aElement.GetAttr(nsGkAtoms::alt, aAltText)) {
7261 return;
7262 }
7263
7264 if (aElement.IsHTMLElement(nsGkAtoms::input)) {
7265 // If there's no "alt" attribute, and aElement is an input element, then use
7266 // the value of the "value" attribute.
7267 if (aElement.GetAttr(nsGkAtoms::value, aAltText)) {
7268 return;
7269 }
7270
7271 // If there's no "value" attribute either, then use the localized string for
7272 // "Submit" as the alternate text.
7273 nsContentUtils::GetMaybeLocalizedString(PropertiesFile::FORMS_PROPERTIES,
7274 "Submit", aElement.OwnerDoc(),
7275 aAltText);
7276 }
7277}
7278
7279nsIFrame* nsCSSFrameConstructor::CreateContinuingOuterTableFrame(
7280 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7281 ComputedStyle* aComputedStyle) {
7282 nsTableWrapperFrame* newFrame =
7283 NS_NewTableWrapperFrame(mPresShell, aComputedStyle);
7284
7285 newFrame->Init(aContent, aParentFrame, aFrame);
7286
7287 // Create a continuing inner table frame. Note we don't replicate the
7288 // captions: a comment used to hint at that, but the code dealing with that
7289 // never worked and was removed in bug 309322.
7290 nsFrameList newChildFrames;
7291
7292 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"
, 7292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 7292); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7293 if (nsTableFrame* childFrame =
7294 static_cast<nsTableWrapperFrame*>(aFrame)->InnerTableFrame()) {
7295 nsIFrame* continuingTableFrame =
7296 CreateContinuingFrame(childFrame, newFrame);
7297 newChildFrames.AppendFrame(nullptr, continuingTableFrame);
7298 }
7299
7300 // Set the table wrapper's initial child list
7301 newFrame->SetInitialChildList(FrameChildListID::Principal,
7302 std::move(newChildFrames));
7303
7304 return newFrame;
7305}
7306
7307nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
7308 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7309 ComputedStyle* aComputedStyle) {
7310 nsTableFrame* newFrame = NS_NewTableFrame(mPresShell, aComputedStyle);
7311
7312 newFrame->Init(aContent, aParentFrame, aFrame);
7313
7314 // Replicate any header/footer frames
7315 nsFrameList childFrames;
7316 for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
7317 // See if it's a header/footer, possibly wrapped in a scroll frame.
7318 nsTableRowGroupFrame* rowGroupFrame =
7319 static_cast<nsTableRowGroupFrame*>(childFrame);
7320 // If the row group was continued, then don't replicate it.
7321 nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
7322 if (rgNextInFlow) {
7323 rowGroupFrame->SetRepeatable(false);
7324 } else if (rowGroupFrame->IsRepeatable()) {
7325 // Replicate the header/footer frame.
7326 nsTableRowGroupFrame* headerFooterFrame;
7327 nsFrameList childList;
7328
7329 nsFrameConstructorState state(
7330 mPresShell, GetAbsoluteContainingBlock(newFrame, FIXED_POS),
7331 GetAbsoluteContainingBlock(newFrame, ABS_POS), nullptr);
7332 state.mCreatingExtraFrames = true;
7333
7334 ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
7335 headerFooterFrame = static_cast<nsTableRowGroupFrame*>(
7336 NS_NewTableRowGroupFrame(mPresShell, headerFooterComputedStyle));
7337
7338 nsIContent* headerFooter = rowGroupFrame->GetContent();
7339 headerFooterFrame->Init(headerFooter, newFrame, nullptr);
7340 if (rowGroupFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT)) {
7341 headerFooterFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
7342 state.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
7343 }
7344
7345 nsFrameConstructorSaveState absoluteSaveState;
7346 MakeTablePartAbsoluteContainingBlock(state, absoluteSaveState,
7347 headerFooterFrame);
7348
7349 nsFrameConstructorSaveState floatSaveState;
7350 state.MaybePushFloatContainingBlock(headerFooterFrame, floatSaveState);
7351
7352 ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
7353 headerFooterFrame, true, childList, false, nullptr);
7354 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", 7354); MOZ_PretendNoReturn
(); } } while (0)
;
7355 headerFooterFrame->SetInitialChildList(FrameChildListID::Principal,
7356 std::move(childList));
7357 headerFooterFrame->SetRepeatable(true);
7358
7359 // Table specific initialization
7360 headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
7361
7362 // XXX Deal with absolute and fixed frames...
7363 childFrames.AppendFrame(nullptr, headerFooterFrame);
7364 }
7365 }
7366
7367 // Set the table frame's initial child list
7368 newFrame->SetInitialChildList(FrameChildListID::Principal,
7369 std::move(childFrames));
7370
7371 return newFrame;
7372}
7373
7374nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
7375 nsIFrame* aFrame, nsContainerFrame* aParentFrame, bool aIsFluid) {
7376 ComputedStyle* computedStyle = aFrame->Style();
7377 nsIFrame* newFrame = nullptr;
7378 nsIFrame* nextContinuation = aFrame->GetNextContinuation();
7379 nsIFrame* nextInFlow = aFrame->GetNextInFlow();
7380
7381 // Use the frame type to determine what type of frame to create
7382 LayoutFrameType frameType = aFrame->Type();
7383 nsIContent* content = aFrame->GetContent();
7384
7385 if (LayoutFrameType::Text == frameType) {
7386 newFrame = NS_NewContinuingTextFrame(mPresShell, computedStyle);
7387 newFrame->Init(content, aParentFrame, aFrame);
7388 } else if (LayoutFrameType::Inline == frameType) {
7389 newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
7390 newFrame->Init(content, aParentFrame, aFrame);
7391 } else if (LayoutFrameType::Block == frameType) {
7392 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", 7393
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7393); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7393 "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", 7393
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7393); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7394 newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
7395 newFrame->Init(content, aParentFrame, aFrame);
7396 } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
7397 newFrame = NS_NewColumnSetWrapperFrame(mPresShell, computedStyle,
7398 NS_FRAME_STATE_NONE);
7399 newFrame->Init(content, aParentFrame, aFrame);
7400 } else if (LayoutFrameType::ColumnSet == frameType) {
7401 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", 7402
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7402); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7402 "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", 7402
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7402); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7403 newFrame =
7404 NS_NewColumnSetFrame(mPresShell, computedStyle, NS_FRAME_STATE_NONE);
7405 newFrame->Init(content, aParentFrame, aFrame);
7406 } else if (LayoutFrameType::PrintedSheet == frameType) {
7407 newFrame = ConstructPrintedSheetFrame(mPresShell, aParentFrame, aFrame);
7408 } else if (LayoutFrameType::Page == frameType) {
7409 nsCanvasFrame* canvasFrame; // (unused outparam for ConstructPageFrame)
7410 newFrame =
7411 ConstructPageFrame(mPresShell, aParentFrame, aFrame, canvasFrame);
7412 } else if (LayoutFrameType::TableWrapper == frameType) {
7413 newFrame = CreateContinuingOuterTableFrame(aFrame, aParentFrame, content,
7414 computedStyle);
7415 } else if (LayoutFrameType::Table == frameType) {
7416 newFrame = CreateContinuingTableFrame(aFrame, aParentFrame, content,
7417 computedStyle);
7418 } else if (LayoutFrameType::TableRowGroup == frameType) {
7419 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
7420 newFrame->Init(content, aParentFrame, aFrame);
7421 } else if (LayoutFrameType::TableRow == frameType) {
7422 nsTableRowFrame* rowFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
7423
7424 rowFrame->Init(content, aParentFrame, aFrame);
7425
7426 // Create a continuing frame for each table cell frame
7427 nsFrameList newChildList;
7428 nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
7429 while (cellFrame) {
7430 // See if it's a table cell frame
7431 if (cellFrame->IsTableCellFrame()) {
7432 nsIFrame* continuingCellFrame =
7433 CreateContinuingFrame(cellFrame, rowFrame);
7434 newChildList.AppendFrame(nullptr, continuingCellFrame);
7435 }
7436 cellFrame = cellFrame->GetNextSibling();
7437 }
7438
7439 rowFrame->SetInitialChildList(FrameChildListID::Principal,
7440 std::move(newChildList));
7441 newFrame = rowFrame;
7442
7443 } else if (LayoutFrameType::TableCell == frameType) {
7444 // Warning: If you change this and add a wrapper frame around table cell
7445 // frames, make sure Bug 368554 doesn't regress!
7446 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
7447 nsTableFrame* tableFrame =
7448 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
7449 nsTableCellFrame* cellFrame =
7450 NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
7451
7452 cellFrame->Init(content, aParentFrame, aFrame);
7453
7454 // Create a continuing area frame
7455 nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
7456 nsIFrame* continuingBlockFrame =
7457 CreateContinuingFrame(blockFrame, cellFrame);
7458
7459 SetInitialSingleChild(cellFrame, continuingBlockFrame);
7460 newFrame = cellFrame;
7461 } else if (LayoutFrameType::Line == frameType) {
7462 newFrame = NS_NewFirstLineFrame(mPresShell, computedStyle);
7463 newFrame->Init(content, aParentFrame, aFrame);
7464 } else if (LayoutFrameType::Letter == frameType) {
7465 newFrame = NS_NewFirstLetterFrame(mPresShell, computedStyle);
7466 newFrame->Init(content, aParentFrame, aFrame);
7467 } else if (LayoutFrameType::Image == frameType) {
7468 auto* imageFrame = static_cast<nsImageFrame*>(aFrame);
7469 newFrame = imageFrame->CreateContinuingFrame(mPresShell, computedStyle);
7470 newFrame->Init(content, aParentFrame, aFrame);
7471 } else if (LayoutFrameType::ImageControl == frameType) {
7472 newFrame = NS_NewImageControlFrame(mPresShell, computedStyle);
7473 newFrame->Init(content, aParentFrame, aFrame);
7474 } else if (LayoutFrameType::FieldSet == frameType) {
7475 newFrame = NS_NewFieldSetFrame(mPresShell, computedStyle);
7476 newFrame->Init(content, aParentFrame, aFrame);
7477 } else if (LayoutFrameType::FlexContainer == frameType) {
7478 newFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
7479 newFrame->Init(content, aParentFrame, aFrame);
7480 } else if (LayoutFrameType::GridContainer == frameType) {
7481 newFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
7482 newFrame->Init(content, aParentFrame, aFrame);
7483 } else if (LayoutFrameType::Ruby == frameType) {
7484 newFrame = NS_NewRubyFrame(mPresShell, computedStyle);
7485 newFrame->Init(content, aParentFrame, aFrame);
7486 } else if (LayoutFrameType::RubyBaseContainer == frameType) {
7487 newFrame = NS_NewRubyBaseContainerFrame(mPresShell, computedStyle);
7488 newFrame->Init(content, aParentFrame, aFrame);
7489 } else if (LayoutFrameType::RubyTextContainer == frameType) {
7490 newFrame = NS_NewRubyTextContainerFrame(mPresShell, computedStyle);
7491 newFrame->Init(content, aParentFrame, aFrame);
7492 } else {
7493 MOZ_CRASH("unexpected frame type")do { do { } while (false); MOZ_ReportCrash("" "unexpected frame type"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7493); AnnotateMozCrashReason
("MOZ_CRASH(" "unexpected frame type" ")"); do { MOZ_CrashSequence
(__null, 7493); __attribute__((nomerge)) ::abort(); } while (
false); } while (false)
;
7494 }
7495
7496 // Init() set newFrame to be a fluid continuation of aFrame.
7497 // If we want a non-fluid continuation, we need to call SetPrevContinuation()
7498 // to reset NS_FRAME_IS_FLUID_CONTINUATION.
7499 if (!aIsFluid) {
7500 newFrame->SetPrevContinuation(aFrame);
7501 }
7502
7503 // If a continuing frame needs to carry frame state bits from its previous
7504 // continuation or parent, set them in nsIFrame::Init(), or in any derived
7505 // frame class's Init() if the bits are belong to specific group.
7506
7507 if (nextInFlow) {
7508 nextInFlow->SetPrevInFlow(newFrame);
7509 newFrame->SetNextInFlow(nextInFlow);
7510 } else if (nextContinuation) {
7511 nextContinuation->SetPrevContinuation(newFrame);
7512 newFrame->SetNextContinuation(nextContinuation);
7513 }
7514
7515 // aFrame cannot be a dynamic reflow root because it has a continuation now.
7516 aFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
7517
7518 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", 7518); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!newFrame->GetNextSibling()" ") (" "unexpected sibling"
")"); do { MOZ_CrashSequence(__null, 7518); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7519 return newFrame;
7520}
7521
7522void nsCSSFrameConstructor::MaybeSetNextPageContentFramePageName(
7523 const nsIFrame* aFrame) {
7524 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", 7524
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Frame should not be null"
")"); do { MOZ_CrashSequence(__null, 7524); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7525 // No parent means the root frame, which isn't what this funciton is for.
7526 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"
, 7528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7528); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7527 "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"
, 7528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7528); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7528 "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"
, 7528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7528); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
7529 if (mNextPageContentFramePageName) {
7530 return;
7531 }
7532 const nsAtom* const autoValue = aFrame->GetParent()->GetAutoPageValue();
7533 mNextPageContentFramePageName = aFrame->ComputePageValue(autoValue);
7534}
7535
7536nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
7537 nsPageContentFrame* aParentFrame) {
7538 // Now deal with fixed-pos things.... They should appear on all pages,
7539 // so we want to move over the placeholders when processing the child
7540 // of the pageContentFrame.
7541
7542 nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
7543 if (!prevPageContentFrame) {
7544 return NS_OK;
7545 }
7546 nsContainerFrame* canvasFrame =
7547 do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
7548 nsIFrame* prevCanvasFrame =
7549 prevPageContentFrame->PrincipalChildList().FirstChild();
7550 if (!canvasFrame || !prevCanvasFrame) {
7551 // document's root element frame missing
7552 return NS_ERROR_UNEXPECTED;
7553 }
7554
7555 nsFrameList fixedPlaceholders;
7556 nsIFrame* firstFixed =
7557 prevPageContentFrame->GetChildList(FrameChildListID::Absolute)
7558 .FirstChild();
7559 if (!firstFixed) {
7560 return NS_OK;
7561 }
7562
7563 // Don't allow abs-pos descendants of the fixed content to escape the content.
7564 // This should not normally be possible (because fixed-pos elements should
7565 // be absolute containers) but fixed-pos tables currently aren't abs-pos
7566 // containers.
7567 nsFrameConstructorState state(mPresShell, aParentFrame, nullptr,
7568 mRootElementFrame);
7569 state.mCreatingExtraFrames = true;
7570
7571 // We can't use an ancestor filter here, because we're not going to
7572 // be usefully recurring down the tree. This means that other
7573 // places in frame construction can't assume a filter is
7574 // initialized!
7575
7576 // Iterate across fixed frames and replicate each whose placeholder is a
7577 // descendant of aFrame. (We don't want to explicitly copy placeholders that
7578 // are within fixed frames, because that would cause duplicates on the new
7579 // page - bug 389619)
7580 for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
7581 nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
7582 if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(
7583 prevCanvasFrame, prevPlaceholder)) {
7584 // We want to use the same style as the primary style frame for
7585 // our content
7586 nsIContent* content = fixed->GetContent();
7587 ComputedStyle* computedStyle =
7588 nsLayoutUtils::GetStyleFrame(content)->Style();
7589 ItemFlags flags{ItemFlag::AllowPageBreak};
7590 if (fixed->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT)) {
7591 flags += ItemFlag::IsGeneratedContent;
7592 }
7593 AutoFrameConstructionItemList items(this);
7594 AddFrameConstructionItemsInternal(state, content, canvasFrame, true,
7595 computedStyle, flags, items);
7596 ConstructFramesFromItemList(state, items, canvasFrame,
7597 /* aParentIsWrapperAnonBox = */ false,
7598 fixedPlaceholders);
7599 }
7600 }
7601
7602 // Add the placeholders to our primary child list.
7603 // XXXbz this is a little screwed up, since the fixed frames will have
7604 // broken auto-positioning. Oh, well.
7605 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"
, 7606); MOZ_PretendNoReturn(); } } while (0)
7606 "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"
, 7606); MOZ_PretendNoReturn(); } } while (0)
;
7607 canvasFrame->SetInitialChildList(FrameChildListID::Principal,
7608 std::move(fixedPlaceholders));
7609 return NS_OK;
7610}
7611
7612nsCSSFrameConstructor::InsertionPoint nsCSSFrameConstructor::GetInsertionPoint(
7613 nsIContent* aChild) {
7614 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"
, 7614); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 7614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7615 nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
7616 if (!insertionElement) {
7617 // The element doesn't belong in the flattened tree, and thus we don't want
7618 // to render it.
7619 return {};
7620 }
7621
7622 return {GetContentInsertionFrameFor(insertionElement), insertionElement};
7623}
7624
7625static bool IsWhitespaceFrame(nsIFrame* aFrame) {
7626 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", 7626
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 7626); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7627 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
7628}
7629
7630static nsIFrame* FindNextNonWhitespaceSibling(nsIFrame* aFrame) {
7631 nsIFrame* f = aFrame;
7632 do {
7633 f = f->GetNextSibling();
7634 } while (f && IsWhitespaceFrame(f));
7635 return f;
7636}
7637
7638static nsIFrame* FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) {
7639 nsIFrame* f = aFrame;
7640 do {
7641 f = f->GetPrevSibling();
7642 } while (f && IsWhitespaceFrame(f));
7643 return f;
7644}
7645
7646// Returns whether aFrame is inside a table that is fragmented across pages.
7647// Such tables can't deal with removals (see nsTableCellMap::Synchronize and
7648// CreateContinuingTableFrame).
7649static bool IsInFragmentedTable(nsIFrame* aFrame) {
7650 for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
7651 if (f->IsTableFrame() && (f->GetPrevInFlow() || f->GetNextInFlow())) {
7652 return true;
7653 }
7654 }
7655 return false;
7656}
7657
7658static nsIFrame* CheckRubyContainers(nsIFrame* aFrame, nsIFrame* aParent) {
7659 auto* ancestor = aParent;
7660 auto* ancestorChild = aFrame;
7661 while (ancestor && IsWrapperPseudo(ancestor) &&
7662 CanRemoveWrapperPseudoForChildRemoval(ancestorChild, ancestor)) {
7663 ancestorChild = ancestor;
7664 ancestor = ancestorChild->GetParent();
7665 }
7666 if (!ancestor) {
7667 return nullptr;
7668 }
7669 const auto ancestorType = ancestor->Type();
7670 if (ancestorType != LayoutFrameType::Ruby &&
7671 !RubyUtils::IsRubyContainerBox(ancestorType)) {
7672 return nullptr;
7673 }
7674 return ancestor;
7675}
7676
7677bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
7678 nsIFrame* aFrame) {
7679#define TRACE(reason) \
7680 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)
7681 {}, 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)
7682 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", 7682
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have a frame"
")"); do { MOZ_CrashSequence(__null, 7682); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7683 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"
, 7683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame shouldn't be root" ")"); do { MOZ_CrashSequence
(__null, 7683); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7684 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"
, 7685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7685); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7685 "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"
, 7685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7685); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7686
7687 nsIFrame* inFlowFrame = aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
7688 ? aFrame->GetPlaceholderFrame()
7689 : aFrame;
7690 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"
, 7690); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 7690); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
7691 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", 7692
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7692); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7692 "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", 7692
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7692); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7693 nsIFrame* parent = inFlowFrame->GetParent();
7694
7695 if (inFlowFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
7696 nsIFrame* grandparent = parent->GetParent();
7697 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"
, 7697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "grandparent"
")"); do { MOZ_CrashSequence(__null, 7697); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7698
7699 bool needsReframe =
7700 // 1. Removing a column-span may lead to an empty
7701 // ::-moz-column-span-wrapper.
7702 inFlowFrame->IsColumnSpan() ||
7703 // 2. Removing a frame which has any column-span siblings may also
7704 // lead to an empty ::-moz-column-span-wrapper subtree. The
7705 // column-span siblings were the frame's children, but later become
7706 // the frame's siblings after CreateColumnSpanSiblings().
7707 inFlowFrame->HasColumnSpanSiblings() ||
7708 // 3. Removing the only child of a ::-moz-column-content, whose
7709 // ColumnSet grandparent has a previous column-span sibling, requires
7710 // reframing since we might connect the ColumnSet's next column-span
7711 // sibling (if there's one). Note that this isn't actually needed if
7712 // the ColumnSet is at the end of ColumnSetWrapper since we create
7713 // empty ones at the end anyway, but we're not worried about
7714 // optimizing that case.
7715 (parent->Style()->GetPseudoType() ==
7716 PseudoStyleType::MozColumnContent &&
7717 // The only child in ::-moz-column-content (might be tall enough to
7718 // split across columns)
7719 !inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7720 // That ::-moz-column-content is the first column.
7721 !parent->GetPrevInFlow() &&
7722 // The ColumnSet grandparent has a previous sibling that is a
7723 // column-span.
7724 grandparent->GetPrevSibling());
7725
7726 if (needsReframe) {
7727 nsContainerFrame* containingBlock =
7728 GetMultiColumnContainingBlockFor(inFlowFrame);
7729
7730#ifdef DEBUG1
7731 if (IsFramePartOfIBSplit(inFlowFrame)) {
7732 nsIFrame* ibContainingBlock = GetIBContainingBlockFor(inFlowFrame);
7733 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"
, 7737); 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, 7737); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7734 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"
, 7737); 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, 7737); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7735 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"
, 7737); 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, 7737); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7736 "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"
, 7737); 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, 7737); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7737 "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"
, 7737); 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, 7737); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7738 }
7739#endif
7740
7741 TRACE("Multi-column");
7742 RecreateFramesForContent(containingBlock->GetContent(),
7743 InsertionKind::Async);
7744 return true;
7745 }
7746 }
7747
7748 if (aFrame->PresContext()->IsPaginated() &&
7749 aFrame->GetContent() != mDocument->GetRootElement() &&
7750 (IsInFragmentedTable(inFlowFrame) ||
7751 aFrame->IsInReplicatedFixedPosTree())) {
7752 // Fragmented tables and replicated fixed-pos frames on subsequent pages
7753 // can't deal with removals. Rebuild the whole document instead, which also
7754 // makes sure that the new frames get reflowed, since paginated documents
7755 // don't do incremental reflow (see nsPageSequenceFrame::Reflow).
7756 TRACE("Paginated fragmented content");
7757 RecreateFramesForContent(mDocument->GetRootElement(), InsertionKind::Async);
7758 return true;
7759 }
7760
7761 if (IsFramePartOfIBSplit(aFrame)) {
7762 // The removal functions can't handle removal of an {ib} split directly; we
7763 // need to rebuild the containing block.
7764 TRACE("IB split removal");
7765 ReframeContainingBlock(aFrame);
7766 return true;
7767 }
7768
7769 if (inFlowFrame->IsRenderedLegend()) {
7770 TRACE("Fieldset / Legend");
7771 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7772 return true;
7773 }
7774
7775 // Might need to reconstruct things if this frame's nextSibling is a table
7776 // or ruby pseudo, since removal of this frame might mean that this pseudo
7777 // needs to get merged with the frame's prevSibling if that's also a table
7778 // or ruby pseudo.
7779 nsIFrame* nextSibling =
7780 FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
7781 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"
, 7782); MOZ_PretendNoReturn(); } } while (0)
7782 "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"
, 7782); MOZ_PretendNoReturn(); } } while (0)
;
7783 // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
7784 // need to be checked here, since all other types of such frames will have
7785 // a ruby container parent, and be catched by "Check ruby containers" below.
7786 if (nextSibling && IsWrapperPseudo(nextSibling)) {
7787 nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
7788 if (prevSibling && IsWrapperPseudo(prevSibling)) {
7789 TRACE("Pseudo sibling");
7790 // Good enough to recreate frames for aFrame's parent's content; even if
7791 // aFrame's parent is a pseudo, that'll be the right content node.
7792 // FIXME(emilio): Consider doing a more subtle check here like, only if
7793 // prevSibling and nextSibling share frame type. Or even consider just
7794 // moving the frames around and destroying nextSibling?
7795 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7796 return true;
7797 }
7798 }
7799
7800 // Check ruby containers
7801 if (const auto* ancestor = CheckRubyContainers(inFlowFrame, parent)) {
7802 // In ruby containers, pseudo frames may be created from
7803 // whitespaces or even nothing. There are two cases we actually
7804 // need to handle here, but hard to check exactly:
7805 // 1. Status of spaces beside the frame may vary, and related
7806 // frames may be constructed or destroyed accordingly.
7807 // 2. The type of the first child of a ruby frame determines
7808 // whether a pseudo ruby base container should exist.
7809 TRACE("Ruby container");
7810 RecreateFramesForContent(ancestor->GetContent(), InsertionKind::Async);
7811 return true;
7812 }
7813
7814 // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
7815 // a non-fluid continuation, i.e. it was split by bidi resolution
7816 if (!inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7817 ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
7818 (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
7819 TRACE("Removing last child of non-fluid split parent");
7820 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7821 return true;
7822 }
7823
7824 // We might still need to reconstruct things if the parent of inFlowFrame is
7825 // ib-split, since in that case the removal of aFrame might affect the
7826 // splitting of its parent.
7827 if (!IsFramePartOfIBSplit(parent)) {
7828 return false;
7829 }
7830
7831 // If inFlowFrame is not the only in-flow child of |parent|, then removing
7832 // it will change nothing about the {ib} split.
7833 if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
7834 inFlowFrame->LastContinuation()->GetNextSibling()) {
7835 return false;
7836 }
7837
7838 // If the parent is the first or last part of the {ib} split, then
7839 // removing one of its kids will have no effect on the splitting.
7840 // Get the first continuation up front so we don't have to do it twice.
7841 nsIFrame* parentFirstContinuation = parent->FirstContinuation();
7842 if (!GetIBSplitSibling(parentFirstContinuation) ||
7843 !GetIBSplitPrevSibling(parentFirstContinuation)) {
7844 return false;
7845 }
7846
7847 TRACE("IB split parent");
7848 ReframeContainingBlock(parent);
7849 return true;
7850#undef TRACE
7851}
7852
7853void nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent) {
7854 nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
7855
7856 // It's possible that this warning could fire if some other style change
7857 // simultaneously changes the 'display' of the element and makes it no
7858 // longer be a table cell.
7859 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"
, 7859); } } while (false)
;
7860
7861 if (cellFrame) {
7862 cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
7863 }
7864}
7865
7866static nsIContent* GetTopmostMathMLElement(nsIContent* aMathMLContent) {
7867 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"
, 7867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->IsMathMLElement()"
")"); do { MOZ_CrashSequence(__null, 7867); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7868 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"
, 7868); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()"
")"); do { MOZ_CrashSequence(__null, 7868); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7869 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"
, 7869); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()->IsMathMLFrame()"
")"); do { MOZ_CrashSequence(__null, 7869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7870 nsIContent* root = aMathMLContent;
7871
7872 for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent(); parent;
7873 parent = parent->GetFlattenedTreeParent()) {
7874 nsIFrame* frame = parent->GetPrimaryFrame();
7875 if (!frame || !frame->IsMathMLFrame()) {
7876 break;
7877 }
7878 root = parent;
7879 }
7880
7881 return root;
7882}
7883
7884// We don't know how to re-insert an anonymous subtree root, so recreate the
7885// closest non-generated ancestor instead, except for a few special cases...
7886static bool ShouldRecreateContainerForNativeAnonymousContentRoot(
7887 nsIContent* aContent) {
7888 if (!aContent->IsRootOfNativeAnonymousSubtree()) {
7889 return false;
7890 }
7891 if (ManualNACPtr::IsManualNAC(aContent)) {
7892 // Editor NAC, would enter an infinite loop, and we sorta get away with it
7893 // because it's all abspos.
7894 return false;
7895 }
7896 if (auto* el = Element::FromNode(aContent)) {
7897 if (el->GetPseudoElementType() ==
7898 PseudoStyleType::MozSnapshotContainingBlock) {
7899 // Much like above, all abspos and on its own top layer so insertion order
7900 // wouldn't really matter anyways.
7901 return false;
7902 }
7903 if (auto* classes = el->GetClasses()) {
7904 if (classes->Contains(nsGkAtoms::mozCustomContentContainer,
7905 eCaseMatters)) {
7906 // Canvas anonymous content (like the custom content container) is also
7907 // fine, because its only sibling is a tooltip which is also abspos, so
7908 // relative insertion order doesn't really matter.
7909 //
7910 // This is important because the inspector uses it, and we don't want
7911 // inspecting the page to change behavior heavily (and reframing
7912 // unfortunately has side-effects sometimes, even though they're bugs).
7913 return false;
7914 }
7915 }
7916 }
7917
7918 return true;
7919}
7920
7921void nsCSSFrameConstructor::RecreateFramesForContent(
7922 nsIContent* aContent, InsertionKind aInsertionKind) {
7923 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"
, 7923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { MOZ_CrashSequence(__null, 7923); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7924
7925 // If there is no document, we don't want to recreate frames for it. (You
7926 // shouldn't generally be giving this method content without a document
7927 // anyway).
7928 // Rebuilding the frame tree can have bad effects, especially if it's the
7929 // frame tree for chrome (see bug 157322).
7930 if (NS_WARN_IF(!aContent->GetComposedDoc())NS_warn_if_impl(!aContent->GetComposedDoc(), "!aContent->GetComposedDoc()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7930)
) {
7931 return;
7932 }
7933
7934 // TODO(emilio): We technically can find the right insertion point nowadays
7935 // using StyleChildrenIterator rather than FlattenedChildIterator. But we'd
7936 // need to tweak the setup to insert into replaced elements to filter which
7937 // anonymous roots can be allowed, and which can't.
7938 //
7939 // TODO(emilio, 2022): Is this true? If we have a replaced element we wouldn't
7940 // have generated e.g., a ::before/::after pseudo-element to begin with (which
7941 // is what this code is about, so maybe we can just remove this piece of code
7942 // altogether).
7943 if (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent)) {
7944 do {
7945 aContent = aContent->GetParent();
7946 } while (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent));
7947 return RecreateFramesForContent(aContent, InsertionKind::Async);
7948 }
7949
7950 nsIFrame* frame = aContent->GetPrimaryFrame();
7951 if (frame && frame->IsMathMLFrame()) {
7952 // Reframe the topmost MathML element to prevent exponential blowup
7953 // (see bug 397518).
7954 aContent = GetTopmostMathMLElement(aContent);
7955 frame = aContent->GetPrimaryFrame();
7956 }
7957
7958 if (frame) {
7959 nsIFrame* parent = frame->GetParent();
7960 nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
7961 // If the parent frame is a leaf then the subsequent insert will fail to
7962 // create a frame, so we need to recreate the parent content. This happens
7963 // with native anonymous content from the editor.
7964 if (parent && parent->IsLeaf() && parentContent &&
7965 parentContent != aContent) {
7966 return RecreateFramesForContent(parentContent, InsertionKind::Async);
7967 }
7968 }
7969
7970 if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
7971 return;
7972 }
7973
7974 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"
, 7974); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 7974); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7975 const auto removalKind = [&] {
7976 if (aInsertionKind == InsertionKind::Sync && aContent->IsElement() &&
7977 Servo_Element_IsDisplayNone(aContent->AsElement())) {
7978 // If we know we're not going to have frames after reconstructing, it's
7979 // more efficient to do some of that work (a11y notifications, fixing-up
7980 // text nodes) earlier.
7981 return RemovalKind::ForDisplayNoneChange;
7982 }
7983 return RemovalKind::ForReconstruction;
7984 }();
7985 const bool didReconstruct = ContentWillBeRemoved(aContent, removalKind);
7986 if (didReconstruct || removalKind == RemovalKind::ForDisplayNoneChange) {
7987 // If ContentWillBeRemoved triggered reconstruction, then we don't need to
7988 // do anything else because the frames will already have been built.
7989 return;
7990 }
7991 if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
7992 // FIXME(emilio, bug 1397239): There's nothing removing the frame state
7993 // for elements that go away before we come back to the frame constructor.
7994 //
7995 // Also, it'd be nice to just use the `ContentRangeInserted` path for
7996 // both elements and non-elements, but we need to make lazy frame
7997 // construction to apply to all elements first.
7998 //
7999 // TODO(emilio): I think lazy frame construction works everywhere now, so
8000 // maybe we can remove this altogether?
8001 RestyleManager()->PostRestyleEvent(aContent->AsElement(), RestyleHint{0},
8002 nsChangeHint_ReconstructFrame);
8003 return;
8004 }
8005 // Now, recreate the frames associated with this content object.
8006 ContentRangeInserted(aContent, aContent->GetNextSibling(), aInsertionKind);
8007}
8008
8009bool nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent) {
8010 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", 8010); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContent && aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 8010); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8011 return ContentWillBeRemoved(aContent, RemovalKind::ForReconstruction);
8012}
8013
8014//////////////////////////////////////////////////////////////////////
8015
8016// Block frame construction code
8017
8018already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLetterStyle(
8019 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8020 if (aContent) {
8021 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
8022 *aContent->AsElement(), PseudoStyleType::FirstLetter, nullptr,
8023 aComputedStyle);
8024 }
8025 return nullptr;
8026}
8027
8028already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLineStyle(
8029 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8030 if (aContent) {
8031 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
8032 *aContent->AsElement(), PseudoStyleType::FirstLine, nullptr,
8033 aComputedStyle);
8034 }
8035 return nullptr;
8036}
8037
8038// Predicate to see if a given content (block element) has
8039// first-letter style applied to it.
8040bool nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(
8041 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8042 return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
8043 PseudoStyleType::FirstLetter,
8044 mPresShell->GetPresContext());
8045}
8046
8047bool nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) {
8048 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"
, 8048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBlockFrame"
") (" "Need a frame" ")"); do { MOZ_CrashSequence(__null, 8048
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8049 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", 8049); MOZ_PretendNoReturn
(); } } while (0)
;
8050 return aBlockFrame->HasAnyStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
8051}
8052
8053bool nsCSSFrameConstructor::ShouldHaveFirstLineStyle(
8054 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8055 bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(
8056 aContent, aComputedStyle, PseudoStyleType::FirstLine,
8057 mPresShell->GetPresContext());
8058 return hasFirstLine &&
8059 !aContent->IsAnyOfHTMLElements(nsGkAtoms::fieldset, nsGkAtoms::input,
8060 nsGkAtoms::textarea);
8061}
8062
8063void nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(
8064 nsIContent* aContent, ComputedStyle* aComputedStyle,
8065 bool* aHaveFirstLetterStyle, bool* aHaveFirstLineStyle) {
8066 *aHaveFirstLetterStyle = ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
8067 *aHaveFirstLineStyle = ShouldHaveFirstLineStyle(aContent, aComputedStyle);
8068}
8069
8070/* static */
8071const nsCSSFrameConstructor::PseudoParentData
8072 nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
8073 // Cell
8074 {{&nsCSSFrameConstructor::ConstructTableCell,
8075 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8076 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8077 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28)},
8078 PseudoStyleType::MozTableCell},
8079 // Row
8080 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8081 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8082 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8083 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28)},
8084 PseudoStyleType::MozTableRow},
8085 // Row group
8086 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8087 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8088 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8089 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8090 PseudoStyleType::MozTableRowGroup},
8091 // Column group
8092 {{ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
8093 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 |
8094 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_USE_CHILD_ITEMS0x10000 |
8095 FCDATA_SKIP_ABSPOS_PUSH0x200 |
8096 // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
8097 // restyle these: they have non-inheriting styles.
8098 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8099 PseudoStyleType::MozTableColumnGroup},
8100 // Table
8101 {{&nsCSSFrameConstructor::ConstructTable,
8102 FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8103 FCDATA_IS_WRAPPER_ANON_BOX0x400000},
8104 PseudoStyleType::MozTable},
8105 // Ruby
8106 {{ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
,
8107 FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_USE_CHILD_ITEMS0x10000 |
8108 FCDATA_IS_WRAPPER_ANON_BOX0x400000 | FCDATA_SKIP_FRAMESET0x1},
8109 PseudoStyleType::MozRuby},
8110 // Ruby Base
8111 {{ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
8112 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8113 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8114 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28) |
8115 FCDATA_SKIP_FRAMESET0x1},
8116 PseudoStyleType::MozRubyBase},
8117 // Ruby Base Container
8118 {{ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
8119 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8120 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8121 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8122 FCDATA_SKIP_FRAMESET0x1},
8123 PseudoStyleType::MozRubyBaseContainer},
8124 // Ruby Text
8125 {{ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
8126 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8127 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8128 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28) |
8129 FCDATA_SKIP_FRAMESET0x1},
8130 PseudoStyleType::MozRubyText},
8131 // Ruby Text Container
8132 {{ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
8133 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8134 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8135 FCDATA_SKIP_FRAMESET0x1},
8136 PseudoStyleType::MozRubyTextContainer}};
8137
8138void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
8139 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8140 nsIFrame* aParentFrame) {
8141 if (aItems.IsEmpty()) {
8142 return;
8143 }
8144
8145 if (!aParentFrame->IsFlexOrGridContainer()) {
8146 return;
8147 }
8148
8149 const bool isLegacyWebKitBox =
8150 IsFlexContainerForLegacyWebKitBox(aParentFrame);
8151 FCItemIterator iter(aItems);
8152 do {
8153 // Advance iter past children that don't want to be wrapped
8154 if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState,
8155 isLegacyWebKitBox)) {
8156 // Hit the end of the items without finding any remaining children that
8157 // need to be wrapped. We're finished!
8158 return;
8159 }
8160
8161 // If our next potentially-wrappable child is whitespace, then see if
8162 // there's anything wrappable immediately after it. If not, we just drop
8163 // the whitespace and move on. (We're not supposed to create any anonymous
8164 // flex/grid items that _only_ contain whitespace).
8165 // (BUT if this is generated content, then we don't give whitespace nodes
8166 // any special treatment, because they're probably not really whitespace --
8167 // they're just temporarily empty, waiting for their generated text.)
8168 // XXXdholbert If this node's generated text will *actually end up being
8169 // entirely whitespace*, then we technically should still skip over it, per
8170 // the CSS grid & flexbox specs. I'm not bothering with that at this point,
8171 // since it's a pretty extreme edge case.
8172 if (!aParentFrame->IsGeneratedContentFrame() &&
8173 iter.item().IsWhitespace(aState)) {
8174 FCItemIterator afterWhitespaceIter(iter);
8175 bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
8176 bool nextChildNeedsAnonItem =
8177 !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(
8178 aState, isLegacyWebKitBox);
8179
8180 if (!nextChildNeedsAnonItem) {
8181 // There's nothing after the whitespace that we need to wrap, so we
8182 // just drop this run of whitespace.
8183 iter.DeleteItemsTo(this, afterWhitespaceIter);
8184 if (hitEnd) {
8185 // Nothing left to do -- we're finished!
8186 return;
8187 }
8188 // else, we have a next child and it does not want to be wrapped. So,
8189 // we jump back to the beginning of the loop to skip over that child
8190 // (and anything else non-wrappable after it)
8191 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"
, 8193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8193); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8192 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"
, 8193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8193); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8193 "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"
, 8193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8193); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8194 continue;
8195 }
8196 }
8197
8198 // Now |iter| points to the first child that needs to be wrapped in an
8199 // anonymous flex/grid item. Now we see how many children after it also want
8200 // to be wrapped in an anonymous flex/grid item.
8201 FCItemIterator endIter(iter); // iterator to find the end of the group
8202 endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox);
8203
8204 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", 8205); MOZ_PretendNoReturn
(); } } while (0)
8205 "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", 8205); MOZ_PretendNoReturn
(); } } while (0)
;
8206
8207 // Now, we create the anonymous flex or grid item to contain the children
8208 // between |iter| and |endIter|.
8209 nsIContent* parentContent = aParentFrame->GetContent();
8210 RefPtr<ComputedStyle> wrapperStyle =
8211 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8212 PseudoStyleType::MozAnonymousItem, aParentFrame->Style());
8213
8214 static constexpr FrameConstructionData sBlockFCData(
8215 ToCreationFunc(NS_NewBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewBlockFrame(aPs, aStyle); }
, FCDATA_SKIP_FRAMESET0x1 |
8216 FCDATA_USE_CHILD_ITEMS0x10000 |
8217 FCDATA_IS_WRAPPER_ANON_BOX0x400000);
8218
8219 // Use the content of our parent frame
8220 auto* newItem = new (this) FrameConstructionItem(
8221 &sBlockFCData, parentContent, wrapperStyle.forget(), true);
8222
8223 newItem->mIsAllInline =
8224 newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
8225 newItem->mIsBlock = !newItem->mIsAllInline;
8226
8227 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"
, 8230); 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, 8230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8228 "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"
, 8230); 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, 8230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8229 "(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"
, 8230); 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, 8230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8230 "'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"
, 8230); 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, 8230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8231
8232 // Anonymous flex and grid items induce line boundaries around their
8233 // contents.
8234 newItem->mChildItems.SetLineBoundaryAtStart(true);
8235 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8236 // The parent of the items in aItems is also the parent of the items
8237 // in mChildItems
8238 newItem->mChildItems.SetParentHasNoShadowDOM(aItems.ParentHasNoShadowDOM());
8239
8240 // Eat up all items between |iter| and |endIter| and put them in our
8241 // wrapper. This advances |iter| to point to |endIter|.
8242 iter.AppendItemsToList(this, endIter, newItem->mChildItems);
8243
8244 iter.InsertItem(newItem);
8245 } while (!iter.IsDone());
8246}
8247
8248/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8249nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
8250 StyleDisplay aNextDisplay) {
8251 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"
, 8251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevDisplay.IsRuby() && aNextDisplay.IsRuby()"
")"); do { MOZ_CrashSequence(__null, 8251); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8252 if (aPrevDisplay == aNextDisplay &&
8253 (aPrevDisplay == StyleDisplay::RubyBase ||
8254 aPrevDisplay == StyleDisplay::RubyText)) {
8255 return eRubyInterLeafWhitespace;
8256 }
8257 if (aNextDisplay == StyleDisplay::RubyText ||
8258 aNextDisplay == StyleDisplay::RubyTextContainer) {
8259 return eRubyInterLevelWhitespace;
8260 }
8261 return eRubyInterSegmentWhitespace;
8262}
8263
8264/**
8265 * This function checks the content from |aStartIter| to |aEndIter|,
8266 * determines whether it contains only whitespace, and if yes,
8267 * interprets the type of whitespace. This method does not change
8268 * any of the iters.
8269 */
8270/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8271nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
8272 const FCItemIterator& aStartIter,
8273 const FCItemIterator& aEndIter) {
8274 if (!aStartIter.item().IsWhitespace(aState)) {
8275 return eRubyNotWhitespace;
8276 }
8277
8278 FCItemIterator spaceEndIter(aStartIter);
8279 spaceEndIter.SkipWhitespace(aState);
8280 if (spaceEndIter != aEndIter) {
8281 return eRubyNotWhitespace;
8282 }
8283
8284 // Any leading or trailing whitespace in non-pseudo ruby box
8285 // should have been trimmed, hence there should not be any
8286 // whitespace at the start or the end.
8287 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", 8287); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aStartIter.AtStart() && !aEndIter.IsDone()"
")"); do { MOZ_CrashSequence(__null, 8287); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8288 FCItemIterator prevIter(aStartIter);
8289 prevIter.Prev();
8290 return ComputeRubyWhitespaceType(
8291 prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
8292 aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
8293}
8294
8295/**
8296 * This function eats up consecutive items which do not want the current
8297 * parent into either a ruby base box or a ruby text box. When it
8298 * returns, |aIter| points to the first item it doesn't wrap.
8299 */
8300void nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
8301 FCItemIterator& aIter, ComputedStyle* aParentStyle,
8302 nsIContent* aParentContent) {
8303 StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
8304 ParentType parentType, wrapperType;
8305 if (parentDisplay == StyleDisplay::RubyTextContainer) {
8306 parentType = eTypeRubyTextContainer;
8307 wrapperType = eTypeRubyText;
8308 } else {
8309 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", 8309); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentDisplay == StyleDisplay::RubyBaseContainer"
")"); do { MOZ_CrashSequence(__null, 8309); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8310 parentType = eTypeRubyBaseContainer;
8311 wrapperType = eTypeRubyBase;
8312 }
8313
8314 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"
, 8315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8315 "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"
, 8315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8316
8317 FCItemIterator endIter(aIter);
8318 endIter.SkipItemsNotWantingParentType(parentType);
8319
8320 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8321 endIter);
8322}
8323
8324/**
8325 * This function eats up consecutive items into a ruby level container.
8326 * It may create zero or one level container. When it returns, |aIter|
8327 * points to the first item it doesn't wrap.
8328 */
8329void nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
8330 nsFrameConstructorState& aState, FCItemIterator& aIter,
8331 ComputedStyle* aParentStyle, nsIContent* aParentContent) {
8332 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"
, 8333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8333); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8333 "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"
, 8333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8333); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8334
8335 FrameConstructionItem& firstItem = aIter.item();
8336 ParentType wrapperType = firstItem.DesiredParentType();
8337 if (wrapperType != eTypeRubyTextContainer) {
8338 // If the first item is not ruby text,
8339 // it should be in a base container.
8340 wrapperType = eTypeRubyBaseContainer;
8341 }
8342
8343 FCItemIterator endIter(aIter);
8344 do {
8345 if (endIter.SkipItemsWantingParentType(wrapperType) ||
8346 // If the skipping above stops at some item which wants a
8347 // different ruby parent, then we have finished.
8348 IsRubyParentType(endIter.item().DesiredParentType())) {
8349 // No more items need to be wrapped in this level container.
8350 break;
8351 }
8352
8353 FCItemIterator contentEndIter(endIter);
8354 contentEndIter.SkipItemsNotWantingRubyParent();
8355 // endIter must be on something doesn't want a ruby parent.
8356 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", 8356); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentEndIter != endIter" ")"); do { MOZ_CrashSequence
(__null, 8356); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8357
8358 // InterpretRubyWhitespace depends on the fact that any leading or
8359 // trailing whitespace described in the spec have been trimmed at
8360 // this point. With this precondition, it is safe not to check
8361 // whether contentEndIter has been done.
8362 RubyWhitespaceType whitespaceType =
8363 InterpretRubyWhitespace(aState, endIter, contentEndIter);
8364 if (whitespaceType == eRubyInterLevelWhitespace) {
8365 // Remove inter-level whitespace.
8366 bool atStart = (aIter == endIter);
8367 endIter.DeleteItemsTo(this, contentEndIter);
8368 if (atStart) {
8369 aIter = endIter;
8370 }
8371 } else if (whitespaceType == eRubyInterSegmentWhitespace) {
8372 // If this level container starts with inter-segment whitespaces,
8373 // wrap them. Break at contentEndIter. Otherwise, leave it here.
8374 // Break at endIter. They will be wrapped when we are here again.
8375 if (aIter == endIter) {
8376 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", 8377); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8377); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8377 "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", 8377); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8377); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8378 endIter = contentEndIter;
8379 }
8380 break;
8381 } else if (wrapperType == eTypeRubyTextContainer &&
8382 whitespaceType != eRubyInterLeafWhitespace) {
8383 // Misparented inline content that's not inter-annotation
8384 // whitespace doesn't belong in a pseudo ruby text container.
8385 // Break at endIter.
8386 break;
8387 } else {
8388 endIter = contentEndIter;
8389 }
8390 } while (!endIter.IsDone());
8391
8392 // It is possible that everything our parent wants us to wrap is
8393 // simply an inter-level whitespace, which has been trimmed, or
8394 // an inter-segment whitespace, which will be wrapped later.
8395 // In those cases, don't create anything.
8396 if (aIter != endIter) {
8397 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8398 endIter);
8399 }
8400}
8401
8402/**
8403 * This function trims leading and trailing whitespaces
8404 * in the given item list.
8405 */
8406void nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
8407 nsFrameConstructorState& aState, FrameConstructionItemList& aItems) {
8408 FCItemIterator iter(aItems);
8409 if (!iter.IsDone() && iter.item().IsWhitespace(aState)) {
8410 FCItemIterator spaceEndIter(iter);
8411 spaceEndIter.SkipWhitespace(aState);
8412 iter.DeleteItemsTo(this, spaceEndIter);
8413 }
8414
8415 iter.SetToEnd();
8416 if (!iter.AtStart()) {
8417 FCItemIterator spaceEndIter(iter);
8418 do {
8419 iter.Prev();
8420 if (iter.AtStart()) {
8421 // It's fine to not check the first item, because we
8422 // should have trimmed leading whitespaces above.
8423 break;
8424 }
8425 } while (iter.item().IsWhitespace(aState));
8426 iter.Next();
8427 if (iter != spaceEndIter) {
8428 iter.DeleteItemsTo(this, spaceEndIter);
8429 }
8430 }
8431}
8432
8433/**
8434 * This function walks through the child list (aItems) and creates
8435 * needed pseudo ruby boxes to wrap misparented children.
8436 */
8437void nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
8438 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8439 nsIFrame* aParentFrame) {
8440 const ParentType ourParentType = GetParentType(aParentFrame);
8441 if (!IsRubyParentType(ourParentType) ||
8442 aItems.AllWantParentType(ourParentType)) {
8443 return;
8444 }
8445
8446 if (!IsRubyPseudo(aParentFrame) ||
8447 ourParentType == eTypeRuby /* for 'display:block ruby' */) {
8448 // Normally, ruby pseudo frames start from and end at some elements,
8449 // which means they don't have leading and trailing whitespaces at
8450 // all. But there are two cases where they do actually have leading
8451 // or trailing whitespaces:
8452 // 1. It is an inter-segment whitespace which in an individual ruby
8453 // base container.
8454 // 2. The pseudo frame starts from or ends at consecutive inline
8455 // content, which is not pure whitespace, but includes some.
8456 // In either case, the whitespaces are not the leading or trailing
8457 // whitespaces defined in the spec, and thus should not be trimmed.
8458 TrimLeadingAndTrailingWhitespaces(aState, aItems);
8459 }
8460
8461 FCItemIterator iter(aItems);
8462 nsIContent* parentContent = aParentFrame->GetContent();
8463 ComputedStyle* parentStyle = aParentFrame->Style();
8464 while (!iter.IsDone()) {
8465 if (!iter.SkipItemsWantingParentType(ourParentType)) {
8466 if (ourParentType == eTypeRuby) {
8467 WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
8468 parentContent);
8469 } else {
8470 WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
8471 }
8472 }
8473 }
8474}
8475
8476/*
8477 * This function works as follows: we walk through the child list (aItems) and
8478 * find items that cannot have aParentFrame as their parent. We wrap
8479 * continuous runs of such items into a FrameConstructionItem for a frame that
8480 * gets them closer to their desired parents. For example, a run of non-row
8481 * children of a row-group will get wrapped in a row. When we later construct
8482 * the frame for this wrapper (in this case for the row), it'll be the correct
8483 * parent for the cells in the set of items we wrapped or we'll wrap cells
8484 * around everything else. At the end of this method, aItems is guaranteed to
8485 * contain only items for frames that can be direct kids of aParentFrame.
8486 */
8487void nsCSSFrameConstructor::CreateNeededPseudoContainers(
8488 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8489 nsIFrame* aParentFrame) {
8490 ParentType ourParentType = GetParentType(aParentFrame);
8491 if (IsRubyParentType(ourParentType) ||
8492 aItems.AllWantParentType(ourParentType)) {
8493 // Nothing to do here
8494 return;
8495 }
8496
8497 FCItemIterator iter(aItems);
8498 do {
8499 if (iter.SkipItemsWantingParentType(ourParentType)) {
8500 // Nothing else to do here; we're finished
8501 return;
8502 }
8503
8504 // Now we're pointing to the first child that wants a different parent
8505 // type.
8506
8507 // Now try to figure out what kids we can group together. We can generally
8508 // group everything that has a different desired parent type from us. Two
8509 // exceptions to this:
8510 // 1) If our parent type is table, we can't group columns with anything
8511 // else other than whitespace.
8512 // 2) Whitespace that lies between two things we can group which both want
8513 // a non-block parent should be dropped, even if we can't group them
8514 // with each other and even if the whitespace wants a parent of
8515 // ourParentType. Ends of the list count as things that don't want a
8516 // block parent (so that for example we'll drop a whitespace-only list).
8517
8518 FCItemIterator endIter(iter); /* iterator to find the end of the group */
8519 ParentType groupingParentType = endIter.item().DesiredParentType();
8520 if (aItems.AllWantParentType(groupingParentType) &&
8521 groupingParentType != eTypeBlock) {
8522 // Just group them all and be done with it. We need the check for
8523 // eTypeBlock here to catch the "all the items are whitespace" case
8524 // described above.
8525 endIter.SetToEnd();
8526 } else {
8527 // Locate the end of the group.
8528
8529 // Keep track of the type the previous item wanted, in case we have to
8530 // deal with whitespace. Start it off with ourParentType, since that's
8531 // the last thing |iter| would have skipped over.
8532 ParentType prevParentType = ourParentType;
8533 do {
8534 // Walk an iterator past any whitespace that we might be able to drop
8535 // from the list
8536 FCItemIterator spaceEndIter(endIter);
8537 if (prevParentType != eTypeBlock &&
8538 !aParentFrame->IsGeneratedContentFrame() &&
8539 spaceEndIter.item().IsWhitespace(aState)) {
8540 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
8541
8542 // We drop the whitespace in the following cases:
8543 // 1) If these are not trailing spaces and the next item wants a table
8544 // or table-part parent
8545 // 2) If these are trailing spaces and aParentFrame is a
8546 // tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
8547 // (Being a tabular container pretty much means ourParentType is
8548 // not eTypeBlock besides the eTypeColGroup case, which won't
8549 // reach here.)
8550 if ((!trailingSpaces &&
8551 IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
8552 (trailingSpaces && ourParentType != eTypeBlock)) {
8553 bool updateStart = (iter == endIter);
8554 endIter.DeleteItemsTo(this, spaceEndIter);
8555 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", 8556); MOZ_PretendNoReturn
(); } } while (0)
8556 "These should match")do { if (!(trailingSpaces == endIter.IsDone())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "These should match", "trailingSpaces == endIter.IsDone()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8556); MOZ_PretendNoReturn
(); } } while (0)
;
8557
8558 if (updateStart) {
8559 iter = endIter;
8560 }
8561
8562 if (trailingSpaces) {
8563 break; /* Found group end */
8564 }
8565
8566 if (updateStart) {
8567 // Update groupingParentType, since it might have been eTypeBlock
8568 // just because of the whitespace.
8569 groupingParentType = iter.item().DesiredParentType();
8570 }
8571 }
8572 }
8573
8574 // Now endIter points to a non-whitespace item or a non-droppable
8575 // whitespace item. In the latter case, if this is the end of the group
8576 // we'll traverse this whitespace again. But it'll all just be quick
8577 // DesiredParentType() checks which will match ourParentType (that's
8578 // what it means that this is the group end), so it's OK.
8579 // However, when we are grouping a ruby parent, and endIter points to
8580 // a non-droppable whitespace, if the next non-whitespace item also
8581 // wants a ruby parent, the whitespace should also be included into
8582 // the current ruby container.
8583 prevParentType = endIter.item().DesiredParentType();
8584 if (prevParentType == ourParentType &&
8585 (endIter == spaceEndIter || spaceEndIter.IsDone() ||
8586 !IsRubyParentType(groupingParentType) ||
8587 !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
8588 // End the group at endIter.
8589 break;
8590 }
8591
8592 if (ourParentType == eTypeTable &&
8593 (prevParentType == eTypeColGroup) !=
8594 (groupingParentType == eTypeColGroup)) {
8595 // Either we started with columns and now found something else, or
8596 // vice versa. In any case, end the grouping.
8597 break;
8598 }
8599
8600 // If we have some whitespace that we were not able to drop and there is
8601 // an item after the whitespace that is already properly parented, then
8602 // make sure to include the spaces in our group but stop the group after
8603 // that.
8604 if (spaceEndIter != endIter && !spaceEndIter.IsDone() &&
8605 ourParentType == spaceEndIter.item().DesiredParentType()) {
8606 endIter = spaceEndIter;
8607 break;
8608 }
8609
8610 // Include the whitespace we didn't drop (if any) in the group.
8611 endIter = spaceEndIter;
8612 prevParentType = endIter.item().DesiredParentType();
8613
8614 endIter.Next();
8615 } while (!endIter.IsDone());
8616 }
8617
8618 if (iter == endIter) {
8619 // Nothing to wrap here; just skipped some whitespace
8620 continue;
8621 }
8622
8623 if (ourParentType == eTypeColGroup) {
8624 // Suppress non-col items of colgroups.
8625 iter.DeleteItemsTo(this, endIter);
8626 continue;
8627 }
8628
8629 // Now group together all the items between iter and endIter. The right
8630 // parent type to use depends on ourParentType.
8631 ParentType wrapperType;
8632 switch (ourParentType) {
8633 case eTypeRow:
8634 // The parent type for a cell is eTypeBlock, since that's what a cell
8635 // looks like to its kids.
8636 wrapperType = eTypeBlock;
8637 break;
8638 case eTypeRowGroup:
8639 wrapperType = eTypeRow;
8640 break;
8641 case eTypeTable:
8642 // Either colgroup or rowgroup, depending on what we're grouping.
8643 wrapperType =
8644 groupingParentType == eTypeColGroup ? eTypeColGroup : eTypeRowGroup;
8645 break;
8646 case eTypeColGroup:
8647 MOZ_FALLTHROUGH_ASSERT("handled above")do { do { } while (false); MOZ_ReportCrash("" "MOZ_FALLTHROUGH_ASSERT: "
"handled above", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8647); AnnotateMozCrashReason("MOZ_CRASH(" "MOZ_FALLTHROUGH_ASSERT: "
"handled above" ")"); do { MOZ_CrashSequence(__null, 8647); __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
;
8648 default:
8649 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"
, 8649); MOZ_PretendNoReturn(); } } while (0)
;
8650 if (IsRubyParentType(groupingParentType)) {
8651 wrapperType = eTypeRuby;
8652 } else {
8653 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"
, 8654); MOZ_PretendNoReturn(); } } while (0)
8654 "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"
, 8654); MOZ_PretendNoReturn(); } } while (0)
;
8655 wrapperType = eTypeTable;
8656 }
8657 }
8658
8659 ComputedStyle* parentStyle = aParentFrame->Style();
8660 WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
8661 wrapperType, iter, endIter);
8662
8663 // Now |iter| points to the item that was the first one we didn't wrap;
8664 // loop and see whether we need to skip it or wrap it in something
8665 // different.
8666 } while (!iter.IsDone());
8667}
8668
8669/**
8670 * This method wraps frame construction item from |aIter| to
8671 * |aEndIter|. After it returns, aIter points to the first item
8672 * after the wrapper.
8673 */
8674void nsCSSFrameConstructor::WrapItemsInPseudoParent(
8675 nsIContent* aParentContent, ComputedStyle* aParentStyle,
8676 ParentType aWrapperType, FCItemIterator& aIter,
8677 const FCItemIterator& aEndIter) {
8678 const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
8679 PseudoStyleType pseudoType = pseudoData.mPseudoType;
8680 auto& parentDisplay = *aParentStyle->StyleDisplay();
8681 auto parentDisplayInside = parentDisplay.DisplayInside();
8682
8683 // XXXmats should we use IsInlineInsideStyle() here instead? seems odd to
8684 // exclude RubyBaseContainer/RubyTextContainer...
8685 if (pseudoType == PseudoStyleType::MozTable &&
8686 (parentDisplay.IsInlineFlow() ||
8687 parentDisplayInside == StyleDisplayInside::RubyBase ||
8688 parentDisplayInside == StyleDisplayInside::RubyText)) {
8689 pseudoType = PseudoStyleType::MozInlineTable;
8690 }
8691
8692 RefPtr<ComputedStyle> wrapperStyle;
8693 if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000) {
8694 wrapperStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8695 pseudoType, aParentStyle);
8696 } else {
8697 wrapperStyle =
8698 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
8699 pseudoType);
8700 }
8701
8702 // Use the content of our parent frame
8703 auto* newItem = new (this) FrameConstructionItem(
8704 &pseudoData.mFCData, aParentContent, wrapperStyle.forget(), true);
8705
8706 const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
8707 // Here we're cheating a tad... technically, table-internal items should be
8708 // inline if aParentFrame is inline, but they'll get wrapped in an
8709 // inline-table in the end, so it'll all work out. In any case, arguably
8710 // we don't need to maintain this state at this point... but it's better
8711 // to, I guess.
8712 newItem->mIsAllInline = disp->IsInlineOutsideStyle();
8713
8714 bool isRuby = disp->IsRubyDisplayType();
8715 if (!isRuby) {
8716 // Table pseudo frames always induce line boundaries around their
8717 // contents.
8718 newItem->mChildItems.SetLineBoundaryAtStart(true);
8719 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8720 }
8721 // The parent of the items in aItems is also the parent of the items
8722 // in mChildItems
8723 newItem->mChildItems.SetParentHasNoShadowDOM(
8724 aIter.List()->ParentHasNoShadowDOM());
8725
8726 // Eat up all items between |aIter| and |aEndIter| and put them in our
8727 // wrapper Advances |aIter| to point to |aEndIter|.
8728 aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
8729
8730 aIter.InsertItem(newItem);
8731}
8732
8733void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
8734 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8735 nsIFrame* aParentFrame) {
8736 if (aItems.IsEmpty() || GetParentType(aParentFrame) != eTypeRuby) {
8737 return;
8738 }
8739
8740 FCItemIterator iter(aItems);
8741 StyleDisplay firstDisplay =
8742 iter.item().mComputedStyle->StyleDisplay()->mDisplay;
8743 if (firstDisplay == StyleDisplay::RubyBaseContainer) {
8744 return;
8745 }
8746 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"
, 8747); MOZ_PretendNoReturn(); } } while (0)
8747 "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"
, 8747); MOZ_PretendNoReturn(); } } while (0)
;
8748
8749 const PseudoParentData& pseudoData =
8750 sPseudoParentData[eTypeRubyBaseContainer];
8751 RefPtr<ComputedStyle> pseudoStyle =
8752 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8753 pseudoData.mPseudoType, aParentFrame->Style());
8754 FrameConstructionItem* newItem = new (this) FrameConstructionItem(
8755 &pseudoData.mFCData,
8756 // Use the content of the parent frame
8757 aParentFrame->GetContent(), pseudoStyle.forget(), true);
8758 newItem->mIsAllInline = true;
8759 newItem->mChildItems.SetParentHasNoShadowDOM(true);
8760 iter.InsertItem(newItem);
8761}
8762
8763#ifdef DEBUG1
8764/**
8765 * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
8766 * rather than being a direct child of aContainerFrame.
8767 *
8768 * NOTE: aContainerFrame must be a flex or grid container - this function is
8769 * purely for sanity-checking the children of these container types.
8770 * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
8771 * logic (which operates a bit earlier, on FCData instead of frames).
8772 */
8773static bool FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
8774 const nsIFrame* aFrame) {
8775 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", 8775); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContainerFrame->IsFlexOrGridContainer()"
")"); do { MOZ_CrashSequence(__null, 8775); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8776
8777 // Any line-participant frames (e.g. text) definitely want to be wrapped in
8778 // an anonymous flex/grid item.
8779 if (aFrame->IsLineParticipant()) {
8780 return true;
8781 }
8782
8783 // If the container is a -webkit-{inline-}box container, then placeholders
8784 // also need to be wrapped, for compatibility.
8785 if (IsFlexContainerForLegacyWebKitBox(aContainerFrame) &&
8786 aFrame->IsPlaceholderFrame()) {
8787 return true;
8788 }
8789
8790 return false;
8791}
8792#endif
8793
8794static void VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
8795 const nsFrameList& aChildren) {
8796#ifdef DEBUG1
8797 if (!aParentFrame->IsFlexOrGridContainer()) {
8798 return;
8799 }
8800
8801 bool prevChildWasAnonItem = false;
8802 for (const nsIFrame* child : aChildren) {
8803 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", 8804
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8804); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8804 "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", 8804
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8804); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8805 if (IsAnonymousItem(child)) {
8806 AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
8807 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"
, 8807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!prevChildWasAnonItem"
") (" "two anon items in a row" ")"); do { MOZ_CrashSequence
(__null, 8807); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8808 nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
8809 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"
, 8809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstWrappedChild"
") (" "anonymous item shouldn't be empty" ")"); do { MOZ_CrashSequence
(__null, 8809); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8810 prevChildWasAnonItem = true;
8811 } else {
8812 prevChildWasAnonItem = false;
8813 }
8814 }
8815#endif
8816}
8817
8818static bool FrameHasOnlyPlaceholderPrevSiblings(const nsIFrame* aFrame) {
8819 // Check for prev siblings, ignoring placeholder frames.
8820 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", 8820
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8820); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8821 const nsIFrame* prevSibling = aFrame;
8822 do {
8823 prevSibling = prevSibling->GetPrevSibling();
8824 } while (prevSibling && prevSibling->IsPlaceholderFrame());
8825 return !prevSibling;
8826}
8827
8828static bool FrameHasOnlyPlaceholderNextSiblings(const nsIFrame* aFrame) {
8829 // Check for next siblings, ignoring placeholder frames.
8830 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", 8830
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8830); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8831 const nsIFrame* nextSibling = aFrame;
8832 do {
8833 nextSibling = nextSibling->GetNextSibling();
8834 } while (nextSibling && nextSibling->IsPlaceholderFrame());
8835 return !nextSibling;
8836}
8837
8838static void SetPageValues(nsIFrame* const aFrame,
8839 const nsAtom* const aAutoValue,
8840 const nsAtom* const aStartValue,
8841 const nsAtom* const aEndValue) {
8842 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", 8842
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAutoValue" ") ("
"Auto page value should never be null" ")"); do { MOZ_CrashSequence
(__null, 8842); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8843 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"
, 8843); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartValue || aEndValue"
") (" "Should not have called with no values" ")"); do { MOZ_CrashSequence
(__null, 8843); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8844 nsIFrame::PageValues* pageValues =
8845 aFrame->GetProperty(nsIFrame::PageValuesProperty());
8846
8847 if (aStartValue) {
8848 if (aStartValue == aAutoValue) {
8849 // If the page value struct already exists, set the start value to null
8850 // to indicate the auto value.
8851 if (pageValues) {
8852 pageValues->mStartPageValue = nullptr;
8853 }
8854 } else {
8855 // The start value is not auto, so we need to store it, creating the
8856 // page values struct if it does not already exist.
8857 if (!pageValues) {
8858 pageValues = new nsIFrame::PageValues();
8859 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8860 }
8861 pageValues->mStartPageValue = aStartValue;
8862 }
8863 }
8864 if (aEndValue) {
8865 if (aEndValue == aAutoValue) {
8866 // If the page value struct already exists, set the end value to null
8867 // to indicate the auto value.
8868 if (pageValues) {
8869 pageValues->mEndPageValue = nullptr;
8870 }
8871 } else {
8872 // The end value is not auto, so we need to store it, creating the
8873 // page values struct if it does not already exist.
8874 if (!pageValues) {
8875 pageValues = new nsIFrame::PageValues();
8876 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8877 }
8878 pageValues->mEndPageValue = aEndValue;
8879 }
8880 }
8881}
8882
8883inline void nsCSSFrameConstructor::ConstructFramesFromItemList(
8884 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8885 nsContainerFrame* aParentFrame, bool aParentIsWrapperAnonBox,
8886 nsFrameList& aFrameList) {
8887#ifdef DEBUG1
8888 // The assertion condition should match the logic in
8889 // MaybePushFloatContainingBlock().
8890 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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8891 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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8892 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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8893 "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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8894 "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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8895 "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"
, 8895); 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, 8895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8896 aState.mFloatCBCandidate = nullptr;
8897#endif
8898
8899 // Ensure aParentIsWrapperAnonBox is correct. We _could_ compute it directly,
8900 // but it would be a bit slow, which is why we pass it from callers, who have
8901 // that information offhand in many cases.
8902 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", 8902); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox"
")"); do { MOZ_CrashSequence(__null, 8902); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8903
8904 // Note: we explicitly exclude TableColGroupFrame because it doesn't
8905 // have the FCDATA_IS_WRAPPER_ANON_BOX on pseudos so aParentIsWrapperAnonBox
8906 // is false for such pseudos (see sPseudoParentData below).
8907 if (!aParentIsWrapperAnonBox && aState.mHasRenderedLegend &&
8908 aParentFrame->GetContent()->IsHTMLElement(nsGkAtoms::fieldset) &&
8909 !aParentFrame->IsTableColGroupFrame()) {
8910 DebugOnly<bool> found = false;
8911 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8912 if (iter.item().mIsRenderedLegend) {
8913 // This makes the rendered legend the first frame in the fieldset child
8914 // list which makes keyboard traversal follow the visual order.
8915 nsFieldSetFrame* fieldSetFrame = GetFieldSetFrameFor(aParentFrame);
8916 nsFrameList renderedLegend;
8917 ConstructFramesFromItem(aState, iter, fieldSetFrame, renderedLegend);
8918 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"
, 8919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8919); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8919 "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"
, 8919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8919); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8920 fieldSetFrame->InsertFrames(FrameChildListID::Principal, nullptr,
8921 nullptr, std::move(renderedLegend));
8922 FCItemIterator next = iter;
8923 next.Next();
8924 iter.DeleteItemsTo(this, next);
8925 found = true;
8926 break;
8927 }
8928 }
8929 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", 8929
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found" ") (" "should have found our rendered legend"
")"); do { MOZ_CrashSequence(__null, 8929); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8930 }
8931
8932 CreateNeededPseudoContainers(aState, aItems, aParentFrame);
8933 CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
8934 CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
8935 CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
8936
8937 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8938 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"
, 8940); 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, 8940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8939 "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"
, 8940); 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, 8940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8940 "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"
, 8940); 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, 8940); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8941 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", 8942); MOZ_PretendNoReturn
(); } } while (0)
8942 "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", 8942); MOZ_PretendNoReturn
(); } } while (0)
;
8943 ConstructFramesFromItem(aState, iter, aParentFrame, aFrameList);
8944 }
8945
8946 VerifyGridFlexContainerChildren(aParentFrame, aFrameList);
8947
8948 // Calculate and propagate page-name values for each frame in the frame list.
8949 // We do not want to compute and propagate page-name values from frames that
8950 // are children of any subclasses of block frames, but not actually a block
8951 // frame. The page-name property does not apply to frames which cannot create
8952 // class A breakpoints (currently no subclass of BlockFrame can). Because the
8953 // property does not apply, those children also cannot propagate page-name
8954 // values.
8955 // This assumption helps avoid unnecessarily handling page-names for frames
8956 // such as form controls, which also avoids bug 1819468.
8957 if (aState.mPresContext->IsPaginated() && aParentFrame->IsBlockFrame()) {
8958 // Set the start/end page values while iterating the frame list, to walk
8959 // up the frame tree only once after iterating the frame list.
8960 // This also avoids extra property lookups on these frames.
8961 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"
, 8963); 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, 8963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8962 "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"
, 8963); 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, 8963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8963 "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"
, 8963); 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, 8963); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8964 // Even though we store null for page values that equal the "auto" resolved
8965 // value on frames, we always want startPageValue/endPageValue to be the
8966 // actual atoms reflecting the start/end values. This is because when we
8967 // propagate the values up the frame tree, we will need to compare them to
8968 // the auto value for each ancestor. This value might be different than the
8969 // auto value for this frame.
8970 const nsAtom* startPageValue = nullptr;
8971 const nsAtom* endPageValue = nullptr;
8972 for (nsIFrame* f : aFrameList) {
8973 if (f->IsPlaceholderFrame()) {
8974 continue;
8975 }
8976 // Resolve auto against the parent frame's used page name, which has been
8977 // determined and set on aState.mAutoPageNameValue. If this item is not
8978 // block-level then we use the value that auto resolves to.
8979 //
8980 // This is to achieve the propagation behavior described in the spec:
8981 //
8982 // "A start page value and end page value is determined for each box as
8983 // the value (if any) propagated from its first or last child box
8984 // (respectively), else the used value on the box itself."
8985 //
8986 // "A child propagates its own start or end page value if and only if the
8987 // page property applies to it."
8988 //
8989 // The page property only applies to "boxes that create class A break
8990 // points". When taken together, this means that non block-level children
8991 // do not propagate start/end page values, and instead we use "the used
8992 // value on the box itself", the "box itself" being aParentFrame. This
8993 // value has been determined and saved as aState.mAutoPageNameValue
8994 //
8995 // https://www.w3.org/TR/css-page-3/#using-named-pages
8996 // https://www.w3.org/TR/css-break-3/#btw-blocks
8997 const StylePageName& pageName = f->StylePage()->mPage;
8998 const nsAtom* const pageNameAtom =
8999 (pageName.IsPageName() && f->IsBlockOutside())
9000 ? pageName.AsPageName().AsAtom()
9001 : aState.mAutoPageNameValue;
9002 nsIFrame::PageValues* pageValues =
9003 f->GetProperty(nsIFrame::PageValuesProperty());
9004 // If this frame has any children, it will already have had its page
9005 // values set at this point. However, if no page values have been set,
9006 // we must ensure that the appropriate PageValuesProperty value has been
9007 // set.
9008 // If the page name is equal to the auto value, then PageValuesProperty
9009 // should remain null to indicate that the start/end values are both
9010 // equal to the auto value.
9011 if (pageNameAtom != aState.mAutoPageNameValue && !pageValues) {
9012 pageValues = new nsIFrame::PageValues{pageNameAtom, pageNameAtom};
9013 f->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
9014 }
9015 // We don't want to use GetStartPageValue() or GetEndPageValue(), as each
9016 // requires a property lookup which we can avoid here.
9017 if (!startPageValue) {
9018 startPageValue = (pageValues && pageValues->mStartPageValue)
9019 ? pageValues->mStartPageValue.get()
9020 : aState.mAutoPageNameValue;
9021 }
9022 endPageValue = (pageValues && pageValues->mEndPageValue)
9023 ? pageValues->mEndPageValue.get()
9024 : aState.mAutoPageNameValue;
9025 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"
, 9026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 9026); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9026 "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"
, 9026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 9026); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9027 }
9028 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", 9029
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 9029); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9029 "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", 9029
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 9029); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9030 if (startPageValue) {
9031 // Walk up the frame tree from our parent frame, propagating start and
9032 // end page values.
9033 // As we go, if we find that, for a frame, we are not contributing one of
9034 // the start/end page values, then our subtree will not contribute this
9035 // value from that frame onward. startPageValue/endPageValue are set to
9036 // null to indicate this.
9037 // Stop iterating when we are not contributing either start or end
9038 // values, when we hit the root frame (no parent), or when we find a
9039 // frame that is not a block frame.
9040 for (nsContainerFrame* ancestorFrame = aParentFrame;
9041 (startPageValue || endPageValue) && ancestorFrame &&
9042 ancestorFrame->IsBlockFrame();
9043 ancestorFrame = ancestorFrame->GetParent()) {
9044 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", 9045
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9045); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9045 "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", 9045
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9045); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9046 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", 9048
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9048); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9047 "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", 9048
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9048); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9048 "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", 9048
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9048); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9049 {
9050 // Get what the auto value is, based on this frame's parent.
9051 // For the root frame, `auto` resolves to the empty atom.
9052 const nsContainerFrame* const parent = ancestorFrame->GetParent();
9053 const nsAtom* const parentAuto = MOZ_LIKELY(parent)(__builtin_expect(!!(parent), 1))
9054 ? parent->GetAutoPageValue()
9055 : nsGkAtoms::_empty;
9056 SetPageValues(ancestorFrame, parentAuto, startPageValue,
9057 endPageValue);
9058 }
9059 // Once we stop contributing start/end values, we know there is a
9060 // sibling subtree that contributed that value to our shared parent
9061 // instead of our starting frame's subtree. This means once
9062 // startPageValue/endPageValue becomes null, indicating that we are no
9063 // longer contributing that page value, it should stay null and we no
9064 // longer need to check for siblings in that direction.
9065 if (startPageValue &&
9066 !FrameHasOnlyPlaceholderPrevSiblings(ancestorFrame)) {
9067 startPageValue = nullptr;
9068 }
9069 if (endPageValue &&
9070 !FrameHasOnlyPlaceholderNextSiblings(ancestorFrame)) {
9071 endPageValue = nullptr;
9072 }
9073 }
9074 }
9075 }
9076
9077 if (aParentIsWrapperAnonBox) {
9078 for (nsIFrame* f : aFrameList) {
9079 f->SetParentIsWrapperAnonBox();
9080 }
9081 }
9082}
9083
9084void nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
9085 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
9086 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
9087 FrameConstructionItemList& aItemsToConstruct,
9088 const AutoFrameConstructionPageName&) {
9089 for (const auto& info : aAnonymousItems) {
9090 nsIContent* content = info.mContent;
9091 // Gecko-styled nodes should have no pending restyle flags.
9092 // Assert some things about this content
9093 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"
, 9095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9095); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9094 (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"
, 9095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9095); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9095 "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"
, 9095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9095); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9096 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", 9096
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!content->GetPrimaryFrame()"
") (" "Should have no existing frame" ")"); do { MOZ_CrashSequence
(__null, 9096); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9097 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", 9098); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9098); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9098 "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", 9098); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9098); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9099
9100 // Make sure we eagerly performed the servo cascade when the anonymous
9101 // nodes were created.
9102 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", 9102); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsElement() || content->AsElement()->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 9102); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9103
9104 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
9105
9106 AddFrameConstructionItemsInternal(aState, content, aFrame, true,
9107 computedStyle, {ItemFlag::AllowPageBreak},
9108 aItemsToConstruct);
9109 }
9110}
9111
9112void nsCSSFrameConstructor::ProcessChildren(
9113 nsFrameConstructorState& aState, nsIContent* aContent,
9114 ComputedStyle* aComputedStyle, nsContainerFrame* aFrame,
9115 const bool aCanHaveGeneratedContent, nsFrameList& aFrameList,
9116 const bool aAllowBlockStyles, nsIFrame* aPossiblyLeafFrame) {
9117 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", 9117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have parent frame here"
")"); do { MOZ_CrashSequence(__null, 9117); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9118 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", 9120
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9119 "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", 9120
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9120 "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", 9120
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9121
9122 const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH1026;
9123 static_assert(kMaxDepth <= UINT16_MAX(65535), "mCurrentDepth type is too narrow");
9124 AutoRestore<uint16_t> savedDepth(mCurrentDepth);
9125 if (mCurrentDepth != UINT16_MAX(65535)) {
9126 ++mCurrentDepth;
9127 }
9128
9129 if (!aPossiblyLeafFrame) {
9130 aPossiblyLeafFrame = aFrame;
9131 }
9132
9133 // XXXbz ideally, this would do all the pushing of various
9134 // containing blocks as needed, so callers don't have to do it...
9135
9136 // Check that our parent frame is a block before allowing ::first-letter/line.
9137 // E.g. <button style="display:grid"> should not allow it.
9138 const bool allowFirstPseudos =
9139 aAllowBlockStyles && aFrame->IsBlockFrameOrSubclass();
9140 bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
9141 if (allowFirstPseudos) {
9142 ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
9143 &haveFirstLineStyle);
9144 }
9145
9146 AutoFrameConstructionItemList itemsToConstruct(this);
9147 AutoFrameConstructionPageName pageNameTracker(aState, aFrame);
9148
9149 // If we have first-letter or first-line style then frames can get
9150 // moved around so don't set these flags.
9151 if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
9152 itemsToConstruct.SetLineBoundaryAtStart(true);
9153 itemsToConstruct.SetLineBoundaryAtEnd(true);
9154 }
9155
9156 // Create any anonymous frames we need here.
9157 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
9158 GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
9159#ifdef DEBUG1
9160 for (auto& item : anonymousItems) {
9161 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"
, 9162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9162); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9162 "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"
, 9162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9162); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9163 }
9164#endif
9165 AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
9166 itemsToConstruct, pageNameTracker);
9167
9168 // Generated content should have the same style parent as normal kids.
9169 //
9170 // Note that we don't use this style for looking up things like special
9171 // block styles because in some cases involving table pseudo-frames it has
9172 // nothing to do with the parent frame's desired behavior.
9173 auto* styleParentFrame =
9174 nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo);
9175 ComputedStyle* parentStyle = styleParentFrame->Style();
9176 if (parentStyle->StyleDisplay()->mTopLayer == StyleTopLayer::Auto &&
9177 !aContent->IsInNativeAnonymousSubtree()) {
9178 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9179 *parentStyle, PseudoStyleType::Backdrop,
9180 itemsToConstruct);
9181 }
9182
9183 nsBlockFrame* listItem = nullptr;
9184 bool isOutsideMarker = false;
9185 if (!aPossiblyLeafFrame->IsLeaf()) {
9186 if (aCanHaveGeneratedContent) {
9187 if (parentStyle->StyleDisplay()->IsListItem() &&
9188 (listItem = do_QueryFrame(aFrame)) &&
9189 !styleParentFrame->IsFieldSetFrame()) {
9190 isOutsideMarker = parentStyle->StyleList()->mListStylePosition ==
9191 StyleListStylePosition::Outside;
9192 ItemFlags extraFlags;
9193 if (isOutsideMarker) {
9194 extraFlags += ItemFlag::IsForOutsideMarker;
9195 }
9196 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9197 *parentStyle, PseudoStyleType::Marker,
9198 itemsToConstruct, extraFlags);
9199 }
9200 if (aContent->IsHTMLElement(nsGkAtoms::option)) {
9201 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9202 *parentStyle, PseudoStyleType::Checkmark,
9203 itemsToConstruct);
9204 }
9205 // Probe for generated content before
9206 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9207 *parentStyle, PseudoStyleType::Before,
9208 itemsToConstruct);
9209 }
9210
9211 const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth)(__builtin_expect(!!(mCurrentDepth < kMaxDepth), 1));
9212 if (!addChildItems) {
9213 NS_WARNING("ProcessChildren max depth exceeded")NS_DebugBreak(NS_DEBUG_WARNING, "ProcessChildren max depth exceeded"
, nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9213)
;
9214 }
9215
9216 FlattenedChildIterator iter(aContent);
9217 const InsertionPoint insertion(aFrame, aContent);
9218 for (nsIContent* child = iter.GetNextChild(); child;
9219 child = iter.GetNextChild()) {
9220 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"
, 9221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9221); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9221 "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"
, 9221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9221); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9222 if (addChildItems) {
9223 AddFrameConstructionItems(aState, child, iter.ShadowDOMInvolved(),
9224 *parentStyle, insertion, itemsToConstruct);
9225 } else {
9226 ClearLazyBits(child, child->GetNextSibling());
9227 }
9228 }
9229 itemsToConstruct.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
9230
9231 if (aCanHaveGeneratedContent) {
9232 // Probe for generated content after
9233 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9234 *parentStyle, PseudoStyleType::After,
9235 itemsToConstruct);
9236 if (aContent->IsHTMLElement(nsGkAtoms::select)) {
9237 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9238 *parentStyle, PseudoStyleType::PickerIcon,
9239 itemsToConstruct);
9240 }
9241 }
9242 } else {
9243 ClearLazyBits(aContent->GetFirstChild(), nullptr);
9244 }
9245
9246 ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
9247 /* aParentIsWrapperAnonBox = */ false,
9248 aFrameList);
9249
9250 if (listItem) {
9251 if (auto* markerFrame = nsLayoutUtils::GetMarkerFrame(aContent)) {
9252 for (auto* childFrame : aFrameList) {
9253 if (markerFrame == childFrame) {
9254 if (isOutsideMarker) {
9255 // SetMarkerFrameForListItem will add childFrame to the marker list.
9256 aFrameList.RemoveFrame(childFrame);
9257 auto* grandParent = listItem->GetParent()->GetParent();
9258 if (listItem->Style()->GetPseudoType() ==
9259 PseudoStyleType::MozColumnContent &&
9260 grandParent && grandParent->IsColumnSetWrapperFrame()) {
9261 listItem = do_QueryFrame(grandParent);
9262 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"
, 9264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9264); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9263 "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"
, 9264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9264); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9264 "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"
, 9264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9264); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9265 childFrame->SetParent(listItem);
9266 }
9267 }
9268 listItem->SetMarkerFrameForListItem(childFrame);
9269 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", 9269); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "listItem->HasOutsideMarker() == isOutsideMarker"
")"); do { MOZ_CrashSequence(__null, 9269); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9270#ifdef ACCESSIBILITY1
9271 if (nsAccessibilityService* accService = GetAccService()) {
9272 auto* marker = markerFrame->GetContent();
9273 accService->ContentRangeInserted(mPresShell, marker, nullptr);
9274 }
9275#endif
9276 break;
9277 }
9278 }
9279 }
9280 }
9281
9282 if (haveFirstLetterStyle) {
9283 WrapFramesInFirstLetterFrame(aFrame, aFrameList);
9284 }
9285 if (haveFirstLineStyle) {
9286 WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, aFrameList);
9287 }
9288}
9289
9290//----------------------------------------------------------------------
9291
9292// Support for :first-line style
9293
9294// Special routine to handle placing a list of frames into a block
9295// frame that has first-line style. The routine ensures that the first
9296// collection of inline frames end up in a first-line frame.
9297// NOTE: aState may have containing block information related to a
9298// different part of the frame tree than where the first line occurs.
9299// In particular aState may be set up for where ContentInserted or
9300// ContentAppended is inserting content, which may be some
9301// non-first-in-flow continuation of the block to which the first-line
9302// belongs. So this function needs to be careful about how it uses
9303// aState.
9304void nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9305 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9306 nsContainerFrame* aBlockFrame, nsFirstLineFrame* aLineFrame,
9307 nsFrameList& aFrameList) {
9308 // Extract any initial inline frames from aFrameList so we can put them
9309 // in the first-line.
9310 nsFrameList firstLineChildren =
9311 aFrameList.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
9312
9313 if (firstLineChildren.IsEmpty()) {
9314 // Nothing is supposed to go into the first-line; nothing to do
9315 return;
9316 }
9317
9318 if (!aLineFrame) {
9319 // Create line frame
9320 ComputedStyle* parentStyle = nsIFrame::CorrectStyleParentFrame(
9321 aBlockFrame, PseudoStyleType::FirstLine)
9322 ->Style();
9323 RefPtr<ComputedStyle> firstLineStyle =
9324 GetFirstLineStyle(aBlockContent, parentStyle);
9325
9326 aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
9327
9328 // Initialize the line frame
9329 InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
9330
9331 // The lineFrame will be the block's first child; the rest of the
9332 // frame list (after lastInlineFrame) will be the second and
9333 // subsequent children; insert lineFrame into aFrameList.
9334 aFrameList.InsertFrame(nullptr, nullptr, aLineFrame);
9335
9336 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", 9337); MOZ_PretendNoReturn
(); } } while (0)
9337 "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", 9337); MOZ_PretendNoReturn
(); } } while (0)
;
9338 }
9339
9340 // Give the inline frames to the lineFrame <b>after</b> reparenting them
9341 ReparentFrames(this, aLineFrame, firstLineChildren, true);
9342 if (aLineFrame->PrincipalChildList().IsEmpty() &&
9343 aLineFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
9344 aLineFrame->SetInitialChildList(FrameChildListID::Principal,
9345 std::move(firstLineChildren));
9346 } else {
9347 AppendFrames(aLineFrame, FrameChildListID::Principal,
9348 std::move(firstLineChildren));
9349 }
9350}
9351
9352// Special routine to handle appending a new frame to a block frame's
9353// child list. Takes care of placing the new frame into the right
9354// place when first-line style is present.
9355void nsCSSFrameConstructor::AppendFirstLineFrames(
9356 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9357 nsContainerFrame* aBlockFrame, nsFrameList& aFrameList) {
9358 // It's possible that aBlockFrame needs to have a first-line frame
9359 // created because it doesn't currently have any children.
9360 const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
9361 if (blockKids.IsEmpty()) {
9362 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, nullptr,
9363 aFrameList);
9364 return;
9365 }
9366
9367 // Examine the last block child - if it's a first-line frame then
9368 // appended frames need special treatment.
9369 nsIFrame* lastBlockKid = blockKids.LastChild();
9370 if (!lastBlockKid->IsLineFrame()) {
9371 // No first-line frame at the end of the list, therefore there is
9372 // an intervening block between any first-line frame the frames
9373 // we are appending. Therefore, we don't need any special
9374 // treatment of the appended frames.
9375 return;
9376 }
9377
9378 nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
9379 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, lineFrame,
9380 aFrameList);
9381}
9382
9383void nsCSSFrameConstructor::CheckForFirstLineInsertion(
9384 nsIFrame* aParentFrame, nsFrameList& aFrameList) {
9385 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"
, 9386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9386); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
9386 "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"
, 9386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9386); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
9387
9388 if (aFrameList.IsEmpty()) {
9389 // Happens often enough, with the caption stuff. No need to do the ancestor
9390 // walk here.
9391 return;
9392 }
9393
9394 class RestyleManager* restyleManager = RestyleManager();
9395
9396 // Check whether there's a ::first-line on the path up from aParentFrame.
9397 // Note that we can't stop until we've run out of ancestors with
9398 // pseudo-element data, because the first-letter might be somewhere way up the
9399 // tree; in particular it might be past our containing block.
9400 nsIFrame* ancestor = aParentFrame;
9401 while (ancestor) {
9402 if (!ancestor->Style()->IsInFirstLineSubtree()) {
9403 // We know we won't find a ::first-line now.
9404 return;
9405 }
9406
9407 if (!ancestor->IsLineFrame()) {
9408 ancestor = ancestor->GetParent();
9409 continue;
9410 }
9411
9412 if (!ancestor->Style()->IsPseudoElement()) {
9413 // This is a continuation lineframe, not the first line; no need to do
9414 // anything to the styles.
9415 return;
9416 }
9417
9418 // Fix up the styles of aFrameList for ::first-line.
9419 for (nsIFrame* f : aFrameList) {
9420 restyleManager->ReparentComputedStyleForFirstLine(f);
9421 }
9422 return;
9423 }
9424}
9425
9426//----------------------------------------------------------------------
9427
9428// First-letter support
9429
9430// Determine how many characters in the text fragment apply to the
9431// first letter
9432static int32_t FirstLetterCount(
9433 const CharacterDataBuffer* aCharacterDataBuffer) {
9434 int32_t count = 0;
9435 int32_t firstLetterLength = 0;
9436
9437 const uint32_t n = aCharacterDataBuffer->GetLength();
9438 for (uint32_t i = 0; i < n; i++) {
9439 const char16_t ch = aCharacterDataBuffer->CharAt(i);
9440 // FIXME: take content language into account when deciding whitespace.
9441 if (dom::IsSpaceCharacter(ch)) {
9442 if (firstLetterLength) {
9443 break;
9444 }
9445 count++;
9446 continue;
9447 }
9448 // XXX I18n
9449 if ((ch == '\'') || (ch == '\"')) {
9450 if (firstLetterLength) {
9451 break;
9452 }
9453 // keep looping
9454 firstLetterLength = 1;
9455 } else {
9456 count++;
9457 break;
9458 }
9459 }
9460
9461 return count;
9462}
9463
9464static bool NeedFirstLetterContinuation(Text* aText) {
9465 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", 9465); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aText" ") (" "null ptr" ")"); do { MOZ_CrashSequence
(__null, 9465); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9466 int32_t flc = FirstLetterCount(&aText->DataBuffer());
9467 int32_t tl = aText->TextDataLength();
9468 return flc < tl;
9469}
9470
9471static bool IsFirstLetterContent(Text* aText) {
9472 return aText->TextDataLength() && !aText->TextIsOnlyWhitespace();
9473}
9474
9475/**
9476 * Create a letter frame, only make it a floating frame.
9477 */
9478nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
9479 nsFrameConstructorState& aState, Text* aTextContent, nsIFrame* aTextFrame,
9480 nsContainerFrame* aParentFrame, ComputedStyle* aParentStyle,
9481 ComputedStyle* aComputedStyle, nsFrameList& aResult) {
9482 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"
, 9482); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentStyle"
")"); do { MOZ_CrashSequence(__null, 9482); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9483
9484 nsFirstLetterFrame* letterFrame =
9485 NS_NewFloatingFirstLetterFrame(mPresShell, aComputedStyle);
9486 // We don't want to use a text content for a non-text frame (because we want
9487 // its primary frame to be a text frame).
9488 nsIContent* letterContent = aParentFrame->GetContent();
9489 nsContainerFrame* containingBlock =
9490 aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
9491 InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
9492
9493 // Init the text frame to refer to the letter frame.
9494 //
9495 // Make sure we get a proper style for it (the one passed in is for the letter
9496 // frame and will have the float property set on it; the text frame shouldn't
9497 // have that set).
9498 ServoStyleSet* styleSet = mPresShell->StyleSet();
9499 RefPtr<ComputedStyle> textSC =
9500 styleSet->ResolveStyleForText(aTextContent, aComputedStyle);
9501 aTextFrame->SetComputedStyleWithoutNotification(textSC);
9502 InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
9503
9504 // And then give the text frame to the letter frame
9505 SetInitialSingleChild(letterFrame, aTextFrame);
9506
9507 // See if we will need to continue the text frame (does it contain
9508 // more than just the first-letter text or not?) If it does, then we
9509 // create (in advance) a continuation frame for it.
9510 nsIFrame* nextTextFrame = nullptr;
9511 if (NeedFirstLetterContinuation(aTextContent)) {
9512 // Create continuation
9513 nextTextFrame = CreateContinuingFrame(aTextFrame, aParentFrame);
9514 RefPtr<ComputedStyle> newSC =
9515 styleSet->ResolveStyleForText(aTextContent, aParentStyle);
9516 nextTextFrame->SetComputedStyle(newSC);
9517 }
9518
9519 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", 9519); MOZ_PretendNoReturn
(); } } while (0)
;
9520 // Put the new float before any of the floats in the block we're doing
9521 // first-letter for, that is, before any floats whose parent is
9522 // containingBlock.
9523 nsIFrame* prevSibling = nullptr;
9524 for (nsIFrame* f : aState.mFloatedList) {
9525 if (f->GetParent() == containingBlock) {
9526 break;
9527 }
9528 prevSibling = f;
9529 }
9530
9531 aState.AddChild(letterFrame, aResult, letterContent, aParentFrame, false,
9532 true, true, prevSibling);
9533
9534 if (nextTextFrame) {
9535 aResult.AppendFrame(nullptr, nextTextFrame);
9536 }
9537
9538 return letterFrame;
9539}
9540
9541/**
9542 * Create a new letter frame for aTextFrame. The letter frame will be
9543 * a child of aParentFrame.
9544 */
9545void nsCSSFrameConstructor::CreateLetterFrame(
9546 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9547 Text* aTextContent, nsContainerFrame* aParentFrame, nsFrameList& aResult) {
9548 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", 9548); MOZ_PretendNoReturn
(); } } while (0)
;
9549
9550 // Get a ComputedStyle for the first-letter-frame.
9551 //
9552 // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
9553 nsIFrame* parentFrame = nsIFrame::CorrectStyleParentFrame(
9554 aParentFrame, PseudoStyleType::FirstLetter);
9555
9556 ComputedStyle* parentComputedStyle = parentFrame->Style();
9557 ComputedStyle* parentComputedStyleIgnoringFirstLine = parentComputedStyle;
9558 if (parentFrame->IsLineFrame()) {
9559 parentComputedStyleIgnoringFirstLine =
9560 nsIFrame::CorrectStyleParentFrame(aBlockFrame,
9561 PseudoStyleType::FirstLetter)
9562 ->Style();
9563 }
9564
9565 // Use content from containing block so that we can actually
9566 // find a matching style rule.
9567 nsIContent* blockContent = aBlockFrame->GetContent();
9568
9569 // Create first-letter style rule, ignoring first line. If we already have a
9570 // first-line we'll reparent the style below.
9571 RefPtr<ComputedStyle> sc =
9572 GetFirstLetterStyle(blockContent, parentComputedStyleIgnoringFirstLine);
9573
9574 if (sc) {
9575 if (parentComputedStyleIgnoringFirstLine != parentComputedStyle) {
9576 sc = mPresShell->StyleSet()->ReparentComputedStyle(
9577 sc, parentComputedStyle, parentComputedStyle,
9578 blockContent->AsElement());
9579 }
9580
9581 RefPtr<ComputedStyle> textSC =
9582 mPresShell->StyleSet()->ResolveStyleForText(aTextContent, sc);
9583
9584 // Create a new text frame (the original one will be discarded)
9585 // pass a temporary stylecontext, the correct one will be set
9586 // later. Start off by unsetting the primary frame for
9587 // aTextContent, so it's no longer pointing to the to-be-destroyed
9588 // frame.
9589 // XXXbz it would be really nice to destroy the old frame _first_,
9590 // then create the new one, so we could avoid this hack.
9591 aTextContent->SetPrimaryFrame(nullptr);
9592 nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
9593
9594 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", 9595); MOZ_PretendNoReturn
(); } } while (0)
9595 "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", 9595); MOZ_PretendNoReturn
(); } } while (0)
;
9596 nsFrameConstructorState state(
9597 mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
9598 GetAbsoluteContainingBlock(aParentFrame, ABS_POS), aBlockContinuation);
9599
9600 // Create the right type of first-letter frame
9601 const nsStyleDisplay* display = sc->StyleDisplay();
9602 nsFirstLetterFrame* letterFrame;
9603 if (display->IsFloatingStyle() && !aParentFrame->IsInSVGTextSubtree()) {
9604 // Make a floating first-letter frame
9605 letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
9606 aParentFrame, parentComputedStyle,
9607 sc, aResult);
9608 } else {
9609 // Make an inflow first-letter frame
9610 letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
9611
9612 // Initialize the first-letter-frame. We don't want to use a text
9613 // content for a non-text frame (because we want its primary frame to
9614 // be a text frame).
9615 nsIContent* letterContent = aParentFrame->GetContent();
9616 letterFrame->Init(letterContent, aParentFrame, nullptr);
9617
9618 InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
9619
9620 SetInitialSingleChild(letterFrame, textFrame);
9621 aResult.Clear();
9622 aResult.AppendFrame(nullptr, letterFrame);
9623 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"
, 9624); MOZ_PretendNoReturn(); } } while (0)
9624 "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"
, 9624); MOZ_PretendNoReturn(); } } while (0)
;
9625 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9626 }
9627 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", 9629
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9629); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9628 !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", 9629
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9629); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9629 "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", 9629
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9629); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9630 auto parent =
9631 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9632 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9633 parent = static_cast<nsContainerFrame*>(
9634 parent->GetParent()->FirstContinuation());
9635 }
9636 parent->SetHasFirstLetterChild();
9637 aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
9638 letterFrame);
9639 aTextContent->SetPrimaryFrame(textFrame);
9640 }
9641}
9642
9643void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9644 nsContainerFrame* aBlockFrame, nsFrameList& aBlockFrames) {
9645 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9646
9647 nsContainerFrame* parentFrame = nullptr;
9648 nsIFrame* textFrame = nullptr;
9649 nsIFrame* prevFrame = nullptr;
9650 nsFrameList letterFrames;
9651 bool stopLooking = false;
9652 WrapFramesInFirstLetterFrame(
9653 aBlockFrame, aBlockFrame, aBlockFrame, aBlockFrames.FirstChild(),
9654 &parentFrame, &textFrame, &prevFrame, letterFrames, &stopLooking);
9655 if (!parentFrame) {
9656 return;
9657 }
9658 DestroyContext context(mPresShell);
9659 if (parentFrame == aBlockFrame) {
9660 // Take textFrame out of the block's frame list and substitute the
9661 // letter frame(s) instead.
9662 aBlockFrames.DestroyFrame(context, textFrame);
9663 aBlockFrames.InsertFrames(nullptr, prevFrame, std::move(letterFrames));
9664 } else {
9665 // Take the old textFrame out of the inline parent's child list
9666 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9667
9668 // Insert in the letter frame(s)
9669 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9670 std::move(letterFrames));
9671 }
9672}
9673
9674void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9675 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9676 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
9677 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
9678 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking) {
9679 nsIFrame* prevFrame = nullptr;
9680 nsIFrame* frame = aParentFrameList;
9681
9682 // This loop attempts to implement "Finding the First Letter":
9683 // https://drafts.csswg.org/css-pseudo-4/#application-in-css
9684 // FIXME: we don't handle nested blocks correctly yet though (bug 214004)
9685 while (frame) {
9686 nsIFrame* nextFrame = frame->GetNextSibling();
9687
9688 // Skip all ::markers and placeholders.
9689 if (frame->Style()->GetPseudoType() == PseudoStyleType::Marker ||
9690 frame->IsPlaceholderFrame()) {
9691 prevFrame = frame;
9692 frame = nextFrame;
9693 continue;
9694 }
9695 LayoutFrameType frameType = frame->Type();
9696 if (LayoutFrameType::Text == frameType) {
9697 // Wrap up first-letter content in a letter frame
9698 Text* textContent = frame->GetContent()->AsText();
9699 if (IsFirstLetterContent(textContent)) {
9700 // Create letter frame to wrap up the text
9701 CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
9702 aParentFrame, aLetterFrames);
9703
9704 // Provide adjustment information for parent
9705 *aModifiedParent = aParentFrame;
9706 *aTextFrame = frame;
9707 *aPrevFrame = prevFrame;
9708 *aStopLooking = true;
9709 return;
9710 }
9711 } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
9712 nsIFrame* kids = frame->PrincipalChildList().FirstChild();
9713 WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
9714 static_cast<nsContainerFrame*>(frame), kids,
9715 aModifiedParent, aTextFrame, aPrevFrame,
9716 aLetterFrames, aStopLooking);
9717 if (*aStopLooking) {
9718 return;
9719 }
9720 } else {
9721 // This will stop us looking to create more letter frames. For
9722 // example, maybe the frame-type is "letterFrame" or
9723 // "placeholderFrame". This keeps us from creating extra letter
9724 // frames, and also prevents us from creating letter frames when
9725 // the first real content child of a block is not text (e.g. an
9726 // image, hr, etc.)
9727 *aStopLooking = true;
9728 break;
9729 }
9730
9731 prevFrame = frame;
9732 frame = nextFrame;
9733 }
9734}
9735
9736static nsIFrame* FindFirstLetterFrame(nsIFrame* aFrame,
9737 FrameChildListID aListID) {
9738 for (nsIFrame* f : aFrame->GetChildList(aListID)) {
9739 if (f->IsLetterFrame()) {
9740 return f;
9741 }
9742 }
9743 return nullptr;
9744}
9745
9746static void ClearHasFirstLetterChildFrom(nsContainerFrame* aParentFrame) {
9747 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"
, 9747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 9747); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9748 auto* parent =
9749 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9750 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9751 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"
, 9751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9751); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9752 parent = static_cast<nsContainerFrame*>(
9753 parent->GetParent()->FirstContinuation());
9754 }
9755 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"
, 9755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9755); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9756 parent->ClearHasFirstLetterChild();
9757}
9758
9759void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
9760 PresShell* aPresShell, nsIFrame* aBlockFrame) {
9761 // Look for the first letter frame on the FrameChildListID::Float, then
9762 // FrameChildListID::PushedFloats.
9763 nsIFrame* floatFrame =
9764 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::Float);
9765 if (!floatFrame) {
9766 floatFrame =
9767 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::PushedFloats);
9768 if (!floatFrame) {
9769 return;
9770 }
9771 }
9772
9773 // Take the text frame away from the letter frame (so it isn't
9774 // destroyed when we destroy the letter frame).
9775 nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
9776 if (!textFrame) {
9777 return;
9778 }
9779
9780 // Discover the placeholder frame for the letter frame
9781 nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
9782 if (!placeholderFrame) {
9783 // Somethings really wrong
9784 return;
9785 }
9786 nsContainerFrame* parentFrame = placeholderFrame->GetParent();
9787 if (!parentFrame) {
9788 // Somethings really wrong
9789 return;
9790 }
9791
9792 ClearHasFirstLetterChildFrom(parentFrame);
9793
9794 // Create a new text frame with the right style that maps all of the content
9795 // that was previously part of the letter frame (and probably continued
9796 // elsewhere).
9797 ComputedStyle* parentSC = parentFrame->Style();
9798 nsIContent* textContent = textFrame->GetContent();
9799 if (!textContent) {
9800 return;
9801 }
9802 RefPtr<ComputedStyle> newSC =
9803 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9804 nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
9805 newTextFrame->Init(textContent, parentFrame, nullptr);
9806
9807 // Destroy the old text frame's continuations (the old text frame
9808 // will be destroyed when its letter frame is destroyed).
9809 nsIFrame* frameToDelete = textFrame->LastContinuation();
9810 DestroyContext context(mPresShell);
9811 while (frameToDelete != textFrame) {
9812 nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
9813 RemoveFrame(context, FrameChildListID::Principal, frameToDelete);
9814 frameToDelete = nextFrameToDelete;
9815 }
9816
9817 nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
9818
9819 // Now that everything is set...
9820#ifdef NOISY_FIRST_LETTER
9821 printf(
9822 "RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p "
9823 "newTextFrame=%p\n",
9824 textContent.get(), textFrame, newTextFrame);
9825#endif
9826
9827 // Remove placeholder frame and the float
9828 RemoveFrame(context, FrameChildListID::Principal, placeholderFrame);
9829
9830 // Now that the old frames are gone, we can start pointing to our
9831 // new primary frame.
9832 textContent->SetPrimaryFrame(newTextFrame);
9833
9834 // Wallpaper bug 822910.
9835 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9836 if (offsetsNeedFixing) {
9837 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9838 }
9839
9840 // Insert text frame in its place
9841 InsertFrames(parentFrame, FrameChildListID::Principal, prevSibling,
9842 nsFrameList(newTextFrame, newTextFrame));
9843
9844 if (offsetsNeedFixing) {
9845 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9846 }
9847}
9848
9849void nsCSSFrameConstructor::RemoveFirstLetterFrames(
9850 PresShell* aPresShell, nsContainerFrame* aFrame,
9851 nsContainerFrame* aBlockFrame, bool* aStopLooking) {
9852 nsIFrame* prevSibling = nullptr;
9853 nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
9854
9855 while (kid) {
9856 if (kid->IsLetterFrame()) {
9857 ClearHasFirstLetterChildFrom(aFrame);
9858 nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
9859 if (!textFrame) {
9860 break;
9861 }
9862
9863 // Create a new textframe
9864 ComputedStyle* parentSC = aFrame->Style();
9865 if (!parentSC) {
9866 break;
9867 }
9868 nsIContent* textContent = textFrame->GetContent();
9869 if (!textContent) {
9870 break;
9871 }
9872 RefPtr<ComputedStyle> newSC =
9873 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9874 textFrame = NS_NewTextFrame(aPresShell, newSC);
9875 textFrame->Init(textContent, aFrame, nullptr);
9876
9877 DestroyContext context(mPresShell);
9878
9879 // Next rip out the kid and replace it with the text frame
9880 RemoveFrame(context, FrameChildListID::Principal, kid);
9881
9882 // Now that the old frames are gone, we can start pointing to our
9883 // new primary frame.
9884 textContent->SetPrimaryFrame(textFrame);
9885
9886 // Wallpaper bug 822910.
9887 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9888 if (offsetsNeedFixing) {
9889 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9890 }
9891
9892 // Insert text frame in its place
9893 InsertFrames(aFrame, FrameChildListID::Principal, prevSibling,
9894 nsFrameList(textFrame, textFrame));
9895
9896 if (offsetsNeedFixing) {
9897 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9898 }
9899
9900 *aStopLooking = true;
9901 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"
, 9902); MOZ_PretendNoReturn(); } } while (0)
9902 "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"
, 9902); MOZ_PretendNoReturn(); } } while (0)
;
9903 aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9904 break;
9905 }
9906 if (IsInlineFrame(kid)) {
9907 nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
9908 if (kidAsContainerFrame) {
9909 // Look inside child inline frame for the letter frame.
9910 RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame, aBlockFrame,
9911 aStopLooking);
9912 if (*aStopLooking) {
9913 break;
9914 }
9915 }
9916 }
9917 prevSibling = kid;
9918 kid = kid->GetNextSibling();
9919 }
9920}
9921
9922void nsCSSFrameConstructor::RemoveLetterFrames(PresShell* aPresShell,
9923 nsContainerFrame* aBlockFrame) {
9924 aBlockFrame =
9925 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9926 aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
9927 nsContainerFrame* continuation = aBlockFrame;
9928
9929 bool stopLooking = false;
9930 do {
9931 RemoveFloatingFirstLetterFrames(aPresShell, continuation);
9932 RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
9933 &stopLooking);
9934 if (stopLooking) {
9935 break;
9936 }
9937 continuation =
9938 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9939 } while (continuation);
9940}
9941
9942// Fixup the letter frame situation for the given block
9943void nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) {
9944 aBlockFrame =
9945 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9946 nsContainerFrame* continuation = aBlockFrame;
9947
9948 nsContainerFrame* parentFrame = nullptr;
9949 nsIFrame* textFrame = nullptr;
9950 nsIFrame* prevFrame = nullptr;
9951 nsFrameList letterFrames;
9952 bool stopLooking = false;
9953 do {
9954 // XXX shouldn't this bit be set already (bug 408493), assert instead?
9955 continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9956 WrapFramesInFirstLetterFrame(
9957 aBlockFrame, continuation, continuation,
9958 continuation->PrincipalChildList().FirstChild(), &parentFrame,
9959 &textFrame, &prevFrame, letterFrames, &stopLooking);
9960 if (stopLooking) {
9961 break;
9962 }
9963 continuation =
9964 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9965 } while (continuation);
9966
9967 if (!parentFrame) {
9968 return;
9969 }
9970 // Take the old textFrame out of the parent's child list
9971 DestroyContext context(mPresShell);
9972 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9973
9974 // Insert in the letter frame(s)
9975 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9976 std::move(letterFrames));
9977}
9978
9979//----------------------------------------------------------------------
9980
9981void nsCSSFrameConstructor::ConstructBlock(
9982 nsFrameConstructorState& aState, nsIContent* aContent,
9983 nsContainerFrame* aParentFrame, nsContainerFrame* aContentParentFrame,
9984 ComputedStyle* aComputedStyle, nsContainerFrame** aNewFrame,
9985 nsFrameList& aFrameList, nsIFrame* aPositionedFrameForAbsPosContainer) {
9986 // clang-format off
9987 //
9988 // If a block frame is in a multi-column subtree, its children may need to
9989 // be chopped into runs of blocks containing column-spans and runs of
9990 // blocks containing no column-spans. Each run containing column-spans
9991 // will be wrapped by an anonymous block. See CreateColumnSpanSiblings() for
9992 // the implementation.
9993 //
9994 // If a block frame is a multi-column container, its children will need to
9995 // be processed as above. Moreover, it creates a ColumnSetWrapperFrame as
9996 // its outermost frame, and its children which have no
9997 // -moz-column-span-wrapper pseudo will be wrapped in ColumnSetFrames. See
9998 // FinishBuildingColumns() for the implementation.
9999 //
10000 // The multi-column subtree maintains the following invariants:
10001 //
10002 // 1) All the frames have the frame state bit
10003 // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR set, except for top-level
10004 // ColumnSetWrapperFrame and those children in the column-span subtrees.
10005 //
10006 // 2) The first and last frame under ColumnSetWrapperFrame are always
10007 // ColumnSetFrame.
10008 //
10009 // 3) ColumnSetFrames are linked together as continuations.
10010 //
10011 // 4) Those column-span wrappers are *not* linked together with themselves nor
10012 // with the original block frame. The continuation chain consists of the
10013 // original block frame and the original block's continuations wrapping
10014 // non-column-spans.
10015 //
10016 // For example, this HTML
10017 // <div id="x" style="column-count: 2;">
10018 // <div style="column-span: all">a</div>
10019 // <div id="y">
10020 // b
10021 // <div style="column-span: all">c</div>
10022 // <div style="column-span: all">d</div>
10023 // e
10024 // </div>
10025 // </div>
10026 // <div style="column-span: all">f</div>
10027 //
10028 // yields the following frame tree.
10029 //
10030 // A) ColumnSetWrapper (original style)
10031 // B) ColumnSet (-moz-column-set) <-- always created by BeginBuildingColumns
10032 // C) Block (-moz-column-content)
10033 // D) Block (-moz-column-span-wrapper, created by x)
10034 // E) Block (div)
10035 // F) Text ("a")
10036 // G) ColumnSet (-moz-column-set)
10037 // H) Block (-moz-column-content, created by x)
10038 // I) Block (div, y)
10039 // J) Text ("b")
10040 // K) Block (-moz-column-span-wrapper, created by x)
10041 // L) Block (-moz-column-span-wrapper, created by y)
10042 // M) Block (div, new BFC)
10043 // N) Text ("c")
10044 // O) Block (div, new BFC)
10045 // P) Text ("d")
10046 // Q) ColumnSet (-moz-column-set)
10047 // R) Block (-moz-column-content, created by x)
10048 // S) Block (div, y)
10049 // T) Text ("e")
10050 // U) Block (div, new BFC) <-- not in multi-column hierarchy
10051 // V) Text ("f")
10052 //
10053 // ColumnSet linkage described in 3): B -> G -> Q
10054 //
10055 // Block linkage described in 4): C -> H -> R and I -> S
10056 //
10057 // clang-format on
10058
10059 nsBlockFrame* blockFrame = do_QueryFrame(*aNewFrame);
10060 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"
, 10060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockFrame && blockFrame->IsBlockFrame()"
") (" "not a block frame?" ")"); do { MOZ_CrashSequence(__null
, 10060); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10061
10062 // Create column hierarchy if necessary.
10063 const bool needsColumn =
10064 aComputedStyle->StyleColumn()->IsColumnContainerStyle() &&
10065 !aParentFrame->IsTextInputFrame();
10066 if (needsColumn) {
10067 *aNewFrame = BeginBuildingColumns(aState, aContent, aParentFrame,
10068 blockFrame, aComputedStyle);
10069
10070 if (aPositionedFrameForAbsPosContainer == blockFrame) {
10071 aPositionedFrameForAbsPosContainer = *aNewFrame;
10072 }
10073 } else {
10074 // No need to create column hierarchy. Initialize block frame.
10075 blockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
10076 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
10077 }
10078
10079 aState.AddChild(*aNewFrame, aFrameList, aContent,
10080 aContentParentFrame ? aContentParentFrame : aParentFrame);
10081 if (!mRootElementFrame) {
10082 mRootElementFrame = *aNewFrame;
10083 }
10084
10085 // We should make the outer frame be the absolute containing block,
10086 // if one is required. We have to do this because absolute
10087 // positioning must be computed with respect to the CSS dimensions
10088 // of the element, which are the dimensions of the outer block. But
10089 // we can't really do that because only blocks can have absolute
10090 // children. So use the block and try to compensate with hacks
10091 // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10092 nsFrameConstructorSaveState absoluteSaveState;
10093 (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10094 if (aPositionedFrameForAbsPosContainer) {
10095 aState.PushAbsoluteContainingBlock(
10096 *aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
10097 }
10098
10099 nsFrameConstructorSaveState floatSaveState;
10100 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
10101
10102 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10103 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10104 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10105 }
10106
10107 // Process the child content
10108 nsFrameList childList;
10109 ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true, childList,
10110 true);
10111
10112 if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childList)) {
10113 // No need to create column-span siblings.
10114 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10115 std::move(childList));
10116 return;
10117 }
10118
10119 // Extract any initial non-column-span kids, and put them in block frame's
10120 // child list.
10121 nsFrameList initialNonColumnSpanKids =
10122 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10123 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10124 std::move(initialNonColumnSpanKids));
10125
10126 if (childList.IsEmpty()) {
10127 // No more kids to process (there weren't any column-span kids).
10128 return;
10129 }
10130
10131 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
10132 aState, blockFrame, childList,
10133 // If we're constructing a column container, pass nullptr as
10134 // aPositionedFrame to forbid reparenting absolute/fixed positioned frames
10135 // to column contents or column-span wrappers.
10136 needsColumn ? nullptr : aPositionedFrameForAbsPosContainer);
10137
10138 if (needsColumn) {
10139 // We're constructing a column container; need to finish building it.
10140 FinishBuildingColumns(aState, *aNewFrame, blockFrame, columnSpanSiblings);
10141 } else {
10142 // We're constructing a normal block which has column-span children in a
10143 // column hierarchy such as "x" in the following example.
10144 //
10145 // <div style="column-count: 2">
10146 // <div id="x">
10147 // <div>normal child</div>
10148 // <div style="column-span">spanner</div>
10149 // </div>
10150 // </div>
10151 aFrameList.AppendFrames(nullptr, std::move(columnSpanSiblings));
10152 }
10153
10154 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", 10155
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10155); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10155 "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", 10155
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10155); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10156}
10157
10158nsBlockFrame* nsCSSFrameConstructor::BeginBuildingColumns(
10159 nsFrameConstructorState& aState, nsIContent* aContent,
10160 nsContainerFrame* aParentFrame, nsContainerFrame* aColumnContent,
10161 ComputedStyle* aComputedStyle) {
10162 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", 10163
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10163); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10163 "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", 10163
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10163); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10164 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"
, 10165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10165); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10165 "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"
, 10165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10165); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10166
10167 // The initial column hierarchy looks like this:
10168 //
10169 // ColumnSetWrapper (original style)
10170 // ColumnSet (-moz-column-set)
10171 // Block (-moz-column-content)
10172 //
10173 nsBlockFrame* columnSetWrapper = NS_NewColumnSetWrapperFrame(
10174 mPresShell, aComputedStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10175 InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);
10176 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10177 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10178 columnSetWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10179 }
10180
10181 AutoFrameConstructionPageName pageNameTracker(aState, columnSetWrapper);
10182 RefPtr<ComputedStyle> columnSetStyle =
10183 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10184 PseudoStyleType::MozColumnSet, aComputedStyle);
10185 nsContainerFrame* columnSet = NS_NewColumnSetFrame(
10186 mPresShell, columnSetStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10187 InitAndRestoreFrame(aState, aContent, columnSetWrapper, columnSet);
10188 columnSet->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10189
10190 RefPtr<ComputedStyle> blockStyle =
10191 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10192 PseudoStyleType::MozColumnContent, columnSetStyle);
10193 aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
10194 InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
10195 aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10196
10197 // Set up the parent-child chain.
10198 SetInitialSingleChild(columnSetWrapper, columnSet);
10199 SetInitialSingleChild(columnSet, aColumnContent);
10200
10201 return columnSetWrapper;
10202}
10203
10204void nsCSSFrameConstructor::FinishBuildingColumns(
10205 nsFrameConstructorState& aState, nsContainerFrame* aColumnSetWrapper,
10206 nsContainerFrame* aColumnContent, nsFrameList& aColumnContentSiblings) {
10207 nsContainerFrame* prevColumnSet = aColumnContent->GetParent();
10208
10209 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"
, 10211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10211); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10210 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"
, 10211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10211); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10211 "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"
, 10211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10211); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
10212
10213 // Tag the first ColumnSet to have column-span siblings so that the bit can
10214 // propagate to all the continuations. We don't want the last ColumnSet to
10215 // have this bit, so we will unset the bit for it at the end of this function.
10216 prevColumnSet->SetHasColumnSpanSiblings(true);
10217
10218 nsFrameList finalList;
10219 while (aColumnContentSiblings.NotEmpty()) {
10220 nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
10221 if (f->IsColumnSpan()) {
10222 // Do nothing for column-span wrappers. Just move it to the final
10223 // items.
10224 finalList.AppendFrame(aColumnSetWrapper, f);
10225 } else {
10226 auto* continuingColumnSet = static_cast<nsContainerFrame*>(
10227 CreateContinuingFrame(prevColumnSet, aColumnSetWrapper, false));
10228 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", 10229);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10229); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10229 "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", 10229);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10229); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10230
10231 f->SetParent(continuingColumnSet);
10232 SetInitialSingleChild(continuingColumnSet, f);
10233 finalList.AppendFrame(aColumnSetWrapper, continuingColumnSet);
10234 prevColumnSet = continuingColumnSet;
10235 }
10236 }
10237
10238 // Unset the bit because the last ColumnSet has no column-span siblings.
10239 prevColumnSet->SetHasColumnSpanSiblings(false);
10240
10241 aColumnSetWrapper->AppendFrames(FrameChildListID::Principal,
10242 std::move(finalList));
10243}
10244
10245bool nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
10246 nsContainerFrame* aBlockFrame, const nsFrameList& aChildList) {
10247 if (!aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10248 // The block frame isn't in a multi-column block formatting context.
10249 return false;
10250 }
10251
10252 if (ShouldSuppressColumnSpanDescendants(aBlockFrame)) {
10253 // No need to create column-span siblings for a frame that suppresses them.
10254 return false;
10255 }
10256
10257 if (aChildList.IsEmpty()) {
10258 // No child needs to be processed.
10259 return false;
10260 }
10261
10262 // Need to actually look into the child list.
10263 return true;
10264}
10265
10266nsFrameList nsCSSFrameConstructor::CreateColumnSpanSiblings(
10267 nsFrameConstructorState& aState, nsContainerFrame* aInitialBlock,
10268 nsFrameList& aChildList, nsIFrame* aPositionedFrame) {
10269 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", 10269);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitialBlock->IsBlockFrameOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 10269); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10270 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", 10270);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10270); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10271
10272 nsIContent* const content = aInitialBlock->GetContent();
10273 nsContainerFrame* const parentFrame = aInitialBlock->GetParent();
10274 const bool isInitialBlockFloatCB = aInitialBlock->IsFloatContainingBlock();
10275
10276 nsFrameList siblings;
10277 nsContainerFrame* lastNonColumnSpanWrapper = aInitialBlock;
10278
10279 // Tag the first non-column-span wrapper to have column-span siblings so that
10280 // the bit can propagate to all the continuations. We don't want the last
10281 // wrapper to have this bit, so we will unset the bit for it at the end of
10282 // this function.
10283 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(true);
10284 do {
10285 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"
, 10285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Why call this if child list is empty?" ")"); do { MOZ_CrashSequence
(__null, 10285); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10286 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"
, 10287); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10287); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10287 "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"
, 10287); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10287); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10288
10289 // Grab the consecutive column-span kids, and reparent them into a
10290 // block frame.
10291 RefPtr<ComputedStyle> columnSpanWrapperStyle =
10292 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
10293 PseudoStyleType::MozColumnSpanWrapper);
10294 nsBlockFrame* columnSpanWrapper =
10295 NS_NewBlockFrame(mPresShell, columnSpanWrapperStyle);
10296 InitAndRestoreFrame(aState, content, parentFrame, columnSpanWrapper,
10297 AllowCounters::No);
10298 columnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10299 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10300
10301 nsFrameList columnSpanKids =
10302 aChildList.Split([](nsIFrame* f) { return !f->IsColumnSpan(); });
10303 columnSpanKids.ApplySetParent(columnSpanWrapper);
10304 columnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10305 std::move(columnSpanKids));
10306 if (aPositionedFrame) {
10307 aState.ReparentAbsoluteItems(columnSpanWrapper);
10308 }
10309
10310 siblings.AppendFrame(nullptr, columnSpanWrapper);
10311
10312 // Grab the consecutive non-column-span kids, and reparent them into a new
10313 // continuation of the last non-column-span wrapper frame.
10314 auto* nonColumnSpanWrapper = static_cast<nsContainerFrame*>(
10315 CreateContinuingFrame(lastNonColumnSpanWrapper, parentFrame, false));
10316 nonColumnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10317 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10318 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", 10319);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10319); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10319 "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", 10319);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10319); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10320
10321 if (aChildList.NotEmpty()) {
10322 nsFrameList nonColumnSpanKids =
10323 aChildList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10324
10325 nonColumnSpanKids.ApplySetParent(nonColumnSpanWrapper);
10326 nonColumnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10327 std::move(nonColumnSpanKids));
10328 if (aPositionedFrame) {
10329 aState.ReparentAbsoluteItems(nonColumnSpanWrapper);
10330 }
10331 if (isInitialBlockFloatCB) {
10332 aState.ReparentFloats(nonColumnSpanWrapper);
10333 }
10334 }
10335
10336 siblings.AppendFrame(nullptr, nonColumnSpanWrapper);
10337
10338 lastNonColumnSpanWrapper = nonColumnSpanWrapper;
10339 } while (aChildList.NotEmpty());
10340
10341 // Unset the bit because the last non-column-span wrapper has no column-span
10342 // siblings.
10343 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(false);
10344
10345 return siblings;
10346}
10347
10348bool nsCSSFrameConstructor::MaybeRecreateForColumnSpan(
10349 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
10350 nsFrameList& aFrameList, nsIFrame* aPrevSibling) {
10351 if (!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10352 return false;
10353 }
10354
10355 if (aFrameList.IsEmpty()) {
10356 return false;
10357 }
10358
10359 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"
, 10361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10361); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10360 "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"
, 10361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10361); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10361 "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"
, 10361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10361); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10362
10363 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
10364 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
10365 // We are appending a list of frames to the last continuation of a
10366 // ::-moz-column-content. This is the case where we can fix the frame tree
10367 // instead of reframing the containing block. Return false and let
10368 // AppendFramesToParent() deal with this.
10369 return false;
10370 }
10371
10372 auto HasColumnSpan = [](const nsFrameList& aList) {
10373 for (nsIFrame* f : aList) {
10374 if (f->IsColumnSpan()) {
10375 return true;
10376 }
10377 }
10378 return false;
10379 };
10380
10381 if (HasColumnSpan(aFrameList)) {
10382 // If any frame in the frame list has "column-span:all" style, i.e. a
10383 // -moz-column-span-wrapper frame, we need to reframe the multi-column
10384 // containing block.
10385 //
10386 // We can only be here if none of the new inserted nsIContent* nodes (via
10387 // ContentAppended or ContentRangeInserted) have column-span:all style, yet
10388 // some of them have column-span:all descendants. Sadly, there's no way to
10389 // detect this by checking FrameConstructionItems in WipeContainingBlock().
10390 // Otherwise, we would have already wiped the multi-column containing block.
10391 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)
10392 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)
;
10393
10394 // aFrameList can contain placeholder frames. In order to destroy their
10395 // associated out-of-flow frames properly, we need to manually flush all the
10396 // out-of-flow frames in aState to their container frames.
10397 aState.ProcessFrameInsertionsForAllLists();
10398 DestroyContext context(mPresShell);
10399 aFrameList.DestroyFrames(context);
10400 RecreateFramesForContent(
10401 GetMultiColumnContainingBlockFor(aParentFrame)->GetContent(),
10402 InsertionKind::Async);
10403 return true;
10404 }
10405
10406 return false;
10407}
10408
10409nsIFrame* nsCSSFrameConstructor::ConstructInline(
10410 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
10411 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
10412 nsFrameList& aFrameList) {
10413 // If an inline frame has non-inline kids, then we chop up the child list
10414 // into runs of blocks and runs of inlines, create anonymous block frames to
10415 // contain the runs of blocks, inline frames with our style for the runs of
10416 // inlines, and put all these frames, in order, into aFrameList.
10417 //
10418 // When there are column-span blocks in a run of blocks, instead of creating
10419 // an anonymous block to wrap them, we create multiple anonymous blocks,
10420 // wrapping runs of non-column-spans and runs of column-spans.
10421 //
10422 // We return the the first one. The whole setup is called an {ib}
10423 // split; in what follows "frames in the split" refers to the anonymous blocks
10424 // and inlines that contain our children.
10425 //
10426 // {ib} splits maintain the following invariants:
10427 // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
10428 // set.
10429 //
10430 // 2) Each frame in the split has the nsIFrame::IBSplitSibling
10431 // property pointing to the next frame in the split, except for the last
10432 // one, which does not have it set.
10433 //
10434 // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
10435 // property pointing to the previous frame in the split, except for the
10436 // first one, which does not have it set.
10437 //
10438 // 4) The first and last frame in the split are always inlines.
10439 //
10440 // 5) The frames wrapping runs of non-column-spans are linked together as
10441 // continuations. The frames wrapping runs of column-spans are *not*
10442 // linked with each other nor with other non-column-span wrappers.
10443 //
10444 // 6) The first and last frame in the chains of blocks are always wrapping
10445 // non-column-spans. Both of them are created even if they're empty.
10446 //
10447 // An invariant that is NOT maintained is that the wrappers are actually
10448 // linked via GetNextSibling linkage. A simple example is an inline
10449 // containing an inline that contains a block. The three parts of the inner
10450 // inline end up with three different parents.
10451 //
10452 // For example, this HTML:
10453 // <span>
10454 // <div>a</div>
10455 // <span>
10456 // b
10457 // <div>c</div>
10458 // </span>
10459 // d
10460 // <div>e</div>
10461 // f
10462 // </span>
10463 // Gives the following frame tree:
10464 //
10465 // Inline (outer span)
10466 // Block (anonymous, outer span)
10467 // Block (div)
10468 // Text("a")
10469 // Inline (outer span)
10470 // Inline (inner span)
10471 // Text("b")
10472 // Block (anonymous, outer span)
10473 // Block (anonymous, inner span)
10474 // Block (div)
10475 // Text("c")
10476 // Inline (outer span)
10477 // Inline (inner span)
10478 // Text("d")
10479 // Block (anonymous, outer span)
10480 // Block (div)
10481 // Text("e")
10482 // Inline (outer span)
10483 // Text("f")
10484
10485 nsIContent* const content = aItem.mContent;
10486 ComputedStyle* const computedStyle = aItem.mComputedStyle;
10487
10488 nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10489
10490 // Initialize the frame
10491 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
10492
10493 // definition cannot be inside next block because the object's destructor is
10494 // significant. this is part of the fix for bug 42372
10495 nsFrameConstructorSaveState absoluteSaveState;
10496
10497 bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
10498 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10499 if (isAbsPosCB) {
10500 // Relatively positioned frames becomes a container for child
10501 // frames that are positioned
10502 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
10503 }
10504
10505 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10506 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10507 newFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10508 }
10509
10510 // Process the child content
10511 nsFrameList childList;
10512 ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
10513 /* aParentIsWrapperAnonBox = */ false, childList);
10514
10515 nsIFrame* firstBlock = nullptr;
10516 if (!aItem.mIsAllInline) {
10517 for (nsIFrame* f : childList) {
10518 if (f->IsBlockOutside()) {
10519 firstBlock = f;
10520 break;
10521 }
10522 }
10523 }
10524
10525 if (aItem.mIsAllInline || !firstBlock) {
10526 // This part is easy. We either already know we have no non-inline kids,
10527 // or haven't found any when constructing actual frames (the latter can
10528 // happen only if out-of-flows that we thought had no containing block
10529 // acquired one when ancestor inline frames and {ib} splits got
10530 // constructed). Just put all the kids into the single inline frame and
10531 // bail.
10532 newFrame->SetInitialChildList(FrameChildListID::Principal,
10533 std::move(childList));
10534 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
10535 return newFrame;
10536 }
10537
10538 // This inline frame contains several types of children. Therefore this frame
10539 // has to be chopped into several pieces, as described above.
10540
10541 // Grab the first inline's kids
10542 nsFrameList firstInlineKids = childList.TakeFramesBefore(firstBlock);
10543 newFrame->SetInitialChildList(FrameChildListID::Principal,
10544 std::move(firstInlineKids));
10545
10546 aFrameList.AppendFrame(nullptr, newFrame);
10547
10548 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10549 CreateIBSiblings(aState, newFrame, isAbsPosCB, childList, aFrameList);
10550
10551 return newFrame;
10552}
10553
10554void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
10555 nsContainerFrame* aInitialInline,
10556 bool aIsAbsPosCB,
10557 nsFrameList& aChildList,
10558 nsFrameList& aSiblings) {
10559 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", 10559);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10559); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10560
10561 nsIContent* content = aInitialInline->GetContent();
10562 ComputedStyle* computedStyle = aInitialInline->Style();
10563 nsContainerFrame* parentFrame = aInitialInline->GetParent();
10564
10565 // Resolve the right style for our anonymous blocks.
10566 //
10567 // The distinction in styles is needed because of CSS 2.1, section
10568 // 9.2.1.1, which says:
10569 //
10570 // When such an inline box is affected by relative positioning, any
10571 // resulting translation also affects the block-level box contained
10572 // in the inline box.
10573 RefPtr<ComputedStyle> blockSC =
10574 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10575 PseudoStyleType::MozBlockInsideInlineWrapper, computedStyle);
10576
10577 nsContainerFrame* lastNewInline =
10578 static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
10579 do {
10580 // On entry to this loop aChildList is not empty and the first frame in it
10581 // is block-level.
10582 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"
, 10582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Should have child items" ")"); do { MOZ_CrashSequence
(__null, 10582); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10583 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"
, 10584); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10584); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10584 "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"
, 10584); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10584); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10585
10586 // The initial run of blocks belongs to an anonymous block that we create
10587 // right now. The anonymous block will be the parent of these block
10588 // children of the inline.
10589 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10590 InitAndRestoreFrame(aState, content, parentFrame, blockFrame,
10591 AllowCounters::No);
10592 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10593 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10594 }
10595
10596 // Find the first non-block child which defines the end of our block kids
10597 // and the start of our next inline's kids
10598 nsFrameList blockKids =
10599 aChildList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
10600
10601 if (!aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10602 MoveChildrenTo(aInitialInline, blockFrame, blockKids);
10603
10604 SetFrameIsIBSplit(lastNewInline, blockFrame);
10605 aSiblings.AppendFrame(nullptr, blockFrame);
10606 } else {
10607 // Extract any initial non-column-span frames, and put them in
10608 // blockFrame's child list.
10609 nsFrameList initialNonColumnSpanKids =
10610 blockKids.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10611 MoveChildrenTo(aInitialInline, blockFrame, initialNonColumnSpanKids);
10612
10613 SetFrameIsIBSplit(lastNewInline, blockFrame);
10614 aSiblings.AppendFrame(nullptr, blockFrame);
10615
10616 if (blockKids.NotEmpty()) {
10617 // Although SetFrameIsIBSplit() will add NS_FRAME_PART_OF_IBSPLIT for
10618 // blockFrame later, we manually add the bit earlier here to make all
10619 // the continuations of blockFrame created in
10620 // CreateColumnSpanSiblings(), i.e. non-column-span wrappers, have the
10621 // bit via nsIFrame::Init().
10622 blockFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
10623
10624 nsFrameList columnSpanSiblings =
10625 CreateColumnSpanSiblings(aState, blockFrame, blockKids,
10626 aIsAbsPosCB ? aInitialInline : nullptr);
10627 aSiblings.AppendFrames(nullptr, std::move(columnSpanSiblings));
10628 }
10629 }
10630
10631 // Now grab the initial inlines in aChildList and put them into an inline
10632 // frame.
10633 nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10634 InitAndRestoreFrame(aState, content, parentFrame, inlineFrame,
10635 AllowCounters::No);
10636 inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10637 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10638 inlineFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10639 }
10640
10641 if (aIsAbsPosCB) {
10642 inlineFrame->MarkAsAbsoluteContainingBlock();
10643 }
10644
10645 if (aChildList.NotEmpty()) {
10646 nsFrameList inlineKids =
10647 aChildList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
10648 MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
10649 }
10650
10651 SetFrameIsIBSplit(blockFrame, inlineFrame);
10652 aSiblings.AppendFrame(nullptr, inlineFrame);
10653 lastNewInline = inlineFrame;
10654 } while (aChildList.NotEmpty());
10655
10656 SetFrameIsIBSplit(lastNewInline, nullptr);
10657}
10658
10659void nsCSSFrameConstructor::BuildInlineChildItems(
10660 nsFrameConstructorState& aState, FrameConstructionItem& aParentItem,
10661 bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) {
10662 ComputedStyle* const parentStyle = aParentItem.mComputedStyle;
10663 nsIContent* const parentContent = aParentItem.mContent;
10664
10665 if (!aItemIsWithinSVGText) {
10666 if (parentStyle->StyleDisplay()->IsListItem()) {
10667 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10668 *parentStyle, PseudoStyleType::Marker,
10669 aParentItem.mChildItems);
10670 }
10671 // Probe for generated content before
10672 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10673 *parentStyle, PseudoStyleType::Before,
10674 aParentItem.mChildItems);
10675 }
10676
10677 ItemFlags flags;
10678 if (aItemIsWithinSVGText) {
10679 flags += ItemFlag::IsWithinSVGText;
10680 }
10681 if (aItemAllowsTextPathChild &&
10682 aParentItem.mContent->IsSVGElement(nsGkAtoms::a)) {
10683 flags += ItemFlag::AllowTextPathChild;
10684 }
10685
10686 FlattenedChildIterator iter(parentContent);
10687 for (nsIContent* content = iter.GetNextChild(); content;
10688 content = iter.GetNextChild()) {
10689 AddFrameConstructionItems(aState, content, iter.ShadowDOMInvolved(),
10690 *parentStyle, InsertionPoint(),
10691 aParentItem.mChildItems, flags);
10692 }
10693
10694 if (!aItemIsWithinSVGText) {
10695 // Probe for generated content after
10696 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10697 *parentStyle, PseudoStyleType::After,
10698 aParentItem.mChildItems);
10699 }
10700
10701 aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
10702}
10703
10704// return whether it's ok to append (in the AppendFrames sense) to
10705// aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10706// be an ib-split inline.
10707static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
10708 nsIFrame* aNextSibling) {
10709 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"
, 10709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInlineFrame(aParentFrame)"
") (" "Must have an inline parent here" ")"); do { MOZ_CrashSequence
(__null, 10709); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10710
10711 do {
10712 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", 10713);
MOZ_PretendNoReturn(); } } while (0)
10713 "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", 10713);
MOZ_PretendNoReturn(); } } while (0)
;
10714 if (aNextSibling || aParentFrame->GetNextContinuation() ||
10715 GetIBSplitSibling(aParentFrame)) {
10716 return false;
10717 }
10718
10719 aNextSibling = aParentFrame->GetNextSibling();
10720 aParentFrame = aParentFrame->GetParent();
10721 } while (IsInlineFrame(aParentFrame));
10722
10723 return true;
10724}
10725
10726bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame) {
10727#define TRACE(reason) \
10728 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)
10729 "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)
;
10730
10731 const LayoutFrameType frameType = aFrame->Type();
10732
10733 // FIXME(emilio): This looks terribly inefficient if you insert elements deep
10734 // in a MathML subtree.
10735 if (aFrame->IsMathMLFrame()) {
10736 TRACE("MathML");
10737 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10738 return true;
10739 }
10740
10741 // A ruby-related frame that's getting new children.
10742 // The situation for ruby is complex, especially when interacting with
10743 // spaces. It contains these two special cases apart from tables:
10744 // 1) There are effectively three types of white spaces in ruby frames
10745 // we handle differently: leading/tailing/inter-level space,
10746 // inter-base/inter-annotation space, and inter-segment space.
10747 // These three types of spaces can be converted to each other when
10748 // their sibling changes.
10749 // 2) The first effective child of a ruby frame must always be a ruby
10750 // base container. It should be created or destroyed accordingly.
10751 if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
10752 RubyUtils::IsRubyContainerBox(frameType)) {
10753 // We want to optimize it better, and avoid reframing as much as
10754 // possible. But given the cases above, and the fact that a ruby
10755 // usually won't be very large, it should be fine to reframe it.
10756 TRACE("Ruby");
10757 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10758 return true;
10759 }
10760
10761 // Reframe the multi-column container whenever elements insert/append
10762 // into it because we need to reconstruct column-span split.
10763 if (aFrame->IsColumnSetWrapperFrame()) {
10764 TRACE("Multi-column");
10765 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10766 return true;
10767 }
10768
10769 return false;
10770
10771#undef TRACE
10772}
10773
10774bool nsCSSFrameConstructor::WipeContainingBlock(
10775 nsFrameConstructorState& aState, nsIFrame* aContainingBlock,
10776 nsIFrame* aFrame, FrameConstructionItemList& aItems, bool aIsAppend,
10777 nsIFrame* aPrevSibling) {
10778#define TRACE(reason) \
10779 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)
10780 "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)
;
10781
10782 if (aItems.IsEmpty()) {
10783 return false;
10784 }
10785
10786 // Before we go and append the frames, we must check for several
10787 // special situations.
10788
10789 if (aFrame->GetContent() == mDocument->GetRootElement()) {
10790 // Situation #1 is when we insert content that becomes the canonical body
10791 // element, and its used WritingMode is different from the root element's
10792 // used WritingMode.
10793 // We need to reframe the root element so that the root element's frames has
10794 // the correct writing-mode propagated from body element. (See
10795 // nsCSSFrameConstructor::ConstructDocElementFrame.)
10796 //
10797 // Bug 1594297: When inserting a new <body>, we may need to reframe the old
10798 // <body> which has a "overflow" value other than simple "visible". But it's
10799 // tricky, see bug 1593752.
10800 nsIContent* bodyElement = mDocument->GetBodyElement();
10801 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10802 const WritingMode bodyWM(iter.item().mComputedStyle);
10803 if (iter.item().mContent == bodyElement &&
10804 bodyWM != aFrame->GetWritingMode()) {
10805 TRACE("Root");
10806 RecreateFramesForContent(mDocument->GetRootElement(),
10807 InsertionKind::Async);
10808 return true;
10809 }
10810 }
10811 }
10812
10813 nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
10814
10815 // Situation #2 is a flex / grid container frame into which we're inserting
10816 // new inline non-replaced children, adjacent to an existing anonymous flex or
10817 // grid item.
10818 if (aFrame->IsFlexOrGridContainer()) {
10819 FCItemIterator iter(aItems);
10820
10821 // Check if we're adding to-be-wrapped content right *after* an existing
10822 // anonymous flex or grid item (which would need to absorb this content).
10823 const bool isLegacyWebKitBox = IsFlexContainerForLegacyWebKitBox(aFrame);
10824 if (aPrevSibling && IsAnonymousItem(aPrevSibling) &&
10825 iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10826 TRACE("Inserting inline after anon flex or grid item");
10827 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10828 return true;
10829 }
10830
10831 // Check if we're adding to-be-wrapped content right *before* an existing
10832 // anonymous flex or grid item (which would need to absorb this content).
10833 if (nextSibling && IsAnonymousItem(nextSibling)) {
10834 // Jump to the last entry in the list
10835 iter.SetToEnd();
10836 iter.Prev();
10837 if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10838 TRACE("Inserting inline before anon flex or grid item");
10839 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10840 return true;
10841 }
10842 }
10843 }
10844
10845 // Situation #3 is an anonymous flex or grid item that's getting new children
10846 // who don't want to be wrapped.
10847 if (IsAnonymousItem(aFrame)) {
10848 AssertAnonymousFlexOrGridItemParent(aFrame);
10849
10850 // We need to push a null float containing block to be sure that
10851 // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
10852 // inserted content. (In particular, this is necessary in order for
10853 // its "GetGeometricParent" call to return the correct result.)
10854 // We're not honoring floats on this content because it has the
10855 // _flex/grid container_ as its parent in the content tree.
10856 nsFrameConstructorSaveState floatSaveState;
10857 aState.PushFloatContainingBlock(nullptr, floatSaveState);
10858
10859 FCItemIterator iter(aItems);
10860 // Skip over things that _do_ need an anonymous flex item, because
10861 // they're perfectly happy to go here -- they won't cause a reframe.
10862 nsIFrame* containerFrame = aFrame->GetParent();
10863 const bool isLegacyWebKitBox =
10864 IsFlexContainerForLegacyWebKitBox(containerFrame);
10865 if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10866 // We hit something that _doesn't_ need an anonymous flex item!
10867 // Rebuild the flex container to bust it out.
10868 TRACE("Inserting non-inlines inside anon flex or grid item");
10869 RecreateFramesForContent(containerFrame->GetContent(),
10870 InsertionKind::Async);
10871 return true;
10872 }
10873
10874 // If we get here, then everything in |aItems| needs to be wrapped in
10875 // an anonymous flex or grid item. That's where it's already going - good!
10876 }
10877
10878 // Situation #4 is a case when table pseudo-frames don't work out right
10879 ParentType parentType = GetParentType(aFrame);
10880 // If all the kids want a parent of the type that aFrame is, then we're all
10881 // set to go. Indeed, there won't be any table pseudo-frames created between
10882 // aFrame and the kids, so those won't need to be merged with any table
10883 // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10884 // table pseudo-frame, then all the kids in this list would have wanted a
10885 // frame of that type wrapping them anyway, so putting them inside it is ok.
10886 if (!aItems.AllWantParentType(parentType)) {
10887 // Don't give up yet. If parentType is not eTypeBlock and the parent is
10888 // not a generated content frame, then try filtering whitespace out of the
10889 // list.
10890 if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
10891 // For leading whitespace followed by a kid that wants our parent type,
10892 // there are four cases:
10893 // 1) We have a previous sibling which is not a table pseudo. That means
10894 // that previous sibling wanted a (non-block) parent of the type we're
10895 // looking at. Then the whitespace comes between two table-internal
10896 // elements, so should be collapsed out.
10897 // 2) We have a previous sibling which is a table pseudo. It might have
10898 // kids who want this whitespace, so we need to reframe.
10899 // 3) We have no previous sibling and our parent frame is not a table
10900 // pseudo. That means that we'll be at the beginning of our actual
10901 // non-block-type parent, and the whitespace is OK to collapse out.
10902 // If something is ever inserted before us, it'll find our own parent
10903 // as its parent and if it's something that would care about the
10904 // whitespace it'll want a block parent, so it'll trigger a reframe at
10905 // that point.
10906 // 4) We have no previous sibling and our parent frame is a table pseudo.
10907 // Need to reframe.
10908 // All that is predicated on finding the correct previous sibling. We
10909 // might have to walk backwards along continuations from aFrame to do so.
10910 //
10911 // It's always OK to drop whitespace between any two items that want a
10912 // parent of type parentType.
10913 //
10914 // For trailing whitespace preceded by a kid that wants our parent type,
10915 // there are four cases:
10916 // 1) We have a next sibling which is not a table pseudo. That means
10917 // that next sibling wanted a (non-block) parent of the type we're
10918 // looking at. Then the whitespace comes between two table-internal
10919 // elements, so should be collapsed out.
10920 // 2) We have a next sibling which is a table pseudo. It might have
10921 // kids who want this whitespace, so we need to reframe.
10922 // 3) We have no next sibling and our parent frame is not a table
10923 // pseudo. That means that we'll be at the end of our actual
10924 // non-block-type parent, and the whitespace is OK to collapse out.
10925 // If something is ever inserted after us, it'll find our own parent
10926 // as its parent and if it's something that would care about the
10927 // whitespace it'll want a block parent, so it'll trigger a reframe at
10928 // that point.
10929 // 4) We have no next sibling and our parent frame is a table pseudo.
10930 // Need to reframe.
10931 // All that is predicated on finding the correct next sibling. We might
10932 // have to walk forward along continuations from aFrame to do so. That
10933 // said, in the case when nextSibling is null at this point and aIsAppend
10934 // is true, we know we're in case 3. Furthermore, in that case we don't
10935 // even have to worry about the table pseudo situation; we know our
10936 // parent is not a table pseudo there.
10937 FCItemIterator iter(aItems);
10938 FCItemIterator start(iter);
10939 do {
10940 if (iter.SkipItemsWantingParentType(parentType)) {
10941 break;
10942 }
10943
10944 // iter points to an item that wants a different parent. If it's not
10945 // whitespace, we're done; no more point scanning the list.
10946 if (!iter.item().IsWhitespace(aState)) {
10947 break;
10948 }
10949
10950 if (iter == start) {
10951 // Leading whitespace. How to handle this depends on our
10952 // previous sibling and aFrame. See the long comment above.
10953 nsIFrame* prevSibling = aPrevSibling;
10954 if (!prevSibling) {
10955 // Try to find one after all
10956 nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
10957 while (parentPrevCont) {
10958 prevSibling = parentPrevCont->PrincipalChildList().LastChild();
10959 if (prevSibling) {
10960 break;
10961 }
10962 parentPrevCont = parentPrevCont->GetPrevContinuation();
10963 }
10964 };
10965 if (prevSibling) {
10966 if (IsTablePseudo(prevSibling)) {
10967 // need to reframe
10968 break;
10969 }
10970 } else if (IsTablePseudo(aFrame)) {
10971 // need to reframe
10972 break;
10973 }
10974 }
10975
10976 FCItemIterator spaceEndIter(iter);
10977 // Advance spaceEndIter past any whitespace
10978 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
10979
10980 bool okToDrop;
10981 if (trailingSpaces) {
10982 // Trailing whitespace. How to handle this depeds on aIsAppend, our
10983 // next sibling and aFrame. See the long comment above.
10984 okToDrop = aIsAppend && !nextSibling;
10985 if (!okToDrop) {
10986 if (!nextSibling) {
10987 // Try to find one after all
10988 nsIFrame* parentNextCont = aFrame->GetNextContinuation();
10989 while (parentNextCont) {
10990 nextSibling = parentNextCont->PrincipalChildList().FirstChild();
10991 if (nextSibling) {
10992 break;
10993 }
10994 parentNextCont = parentNextCont->GetNextContinuation();
10995 }
10996 }
10997
10998 okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
10999 (!nextSibling && !IsTablePseudo(aFrame));
11000 } else {
11001 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"
, 11001); MOZ_PretendNoReturn(); } } while (0)
;
11002 }
11003 } else {
11004 okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
11005 }
11006
11007 if (okToDrop) {
11008 iter.DeleteItemsTo(this, spaceEndIter);
11009 } else {
11010 // We're done: we don't want to drop the whitespace, and it has the
11011 // wrong parent type.
11012 break;
11013 }
11014
11015 // Now loop, since |iter| points to item right after the whitespace we
11016 // removed.
11017 } while (!iter.IsDone());
11018 }
11019
11020 // We might be able to figure out some sort of optimizations here, but they
11021 // would have to depend on having a correct aPrevSibling and a correct next
11022 // sibling. For example, we can probably avoid reframing if none of
11023 // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11024 // doesn't seem worth it to worry about that for now, especially since we
11025 // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11026 // this method.
11027
11028 // aItems might have changed, so recheck the parent type thing. In fact,
11029 // it might be empty, so recheck that too.
11030 if (aItems.IsEmpty()) {
11031 return false;
11032 }
11033
11034 // If aFrame is empty, the insertion process will be able to take care of
11035 // creating any needed pseudo-parents.
11036 if (!aItems.AllWantParentType(parentType) &&
11037 !SafeToInsertPseudoNeedingChildren(aFrame)) {
11038 // Reframing aFrame->GetContent() is good enough, since the content of
11039 // table pseudo-frames is the ancestor content.
11040 TRACE("Pseudo-frames going wrong");
11041 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11042 return true;
11043 }
11044 }
11045
11046 // Situation #5 is a frame in multicol subtree that's getting new children.
11047 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
11048 bool anyColumnSpanItems = false;
11049 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11050 if (iter.item().mComputedStyle->StyleColumn()->IsColumnSpanStyle()) {
11051 anyColumnSpanItems = true;
11052 break;
11053 }
11054 }
11055
11056 bool needsReframe =
11057 // 1. Insert / append any column-span children.
11058 anyColumnSpanItems ||
11059 // 2. GetInsertionPrevSibling() modifies insertion parent. If the prev
11060 // sibling is a column-span, aFrame ends up being the
11061 // column-span-wrapper.
11062 aFrame->Style()->GetPseudoType() ==
11063 PseudoStyleType::MozColumnSpanWrapper ||
11064 // 3. Append into {ib} split container. There might be room for
11065 // optimization, but let's reframe for correctness...
11066 IsFramePartOfIBSplit(aFrame);
11067
11068 if (needsReframe) {
11069 TRACE("Multi-column");
11070 RecreateFramesForContent(
11071 GetMultiColumnContainingBlockFor(aFrame)->GetContent(),
11072 InsertionKind::Async);
11073 return true;
11074 }
11075
11076 // If we get here, then we need further check for {ib} split to decide
11077 // whether to reframe. For example, appending a block into an empty inline
11078 // that is not part of an {ib} split, but should become an {ib} split.
11079 }
11080
11081 // A <fieldset> may need to pick up a new rendered legend from aItems.
11082 // We currently can't handle this case without recreating frames for
11083 // the fieldset.
11084 // XXXmats we should be able to optimize this when the fieldset doesn't
11085 // currently have a rendered legend. ContentRangeInserted needs to be fixed
11086 // to use the inner frame as the content insertion frame in that case.
11087 if (const auto* fieldset = GetFieldSetFrameFor(aFrame)) {
11088 // Check if any item is eligible to be a rendered legend.
11089 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11090 const auto& item = iter.item();
11091 if (!item.mContent->IsHTMLElement(nsGkAtoms::legend)) {
11092 continue;
11093 }
11094 const auto* display = item.mComputedStyle->StyleDisplay();
11095 if (display->IsFloatingStyle() ||
11096 display->IsAbsolutelyPositionedStyle()) {
11097 continue;
11098 }
11099 TRACE("Fieldset with rendered legend");
11100 RecreateFramesForContent(fieldset->GetContent(), InsertionKind::Async);
11101 return true;
11102 }
11103 }
11104
11105 // Now we have several cases involving {ib} splits. Put them all in a
11106 // do/while with breaks to take us to the "go and reconstruct" code.
11107 do {
11108 if (IsInlineFrame(aFrame)) {
11109 if (aItems.AreAllItemsInline()) {
11110 // We can just put the kids in.
11111 return false;
11112 }
11113
11114 if (!IsFramePartOfIBSplit(aFrame)) {
11115 // Need to go ahead and reconstruct.
11116 break;
11117 }
11118
11119 // Now we're adding kids including some blocks to an inline part of an
11120 // {ib} split. If we plan to call AppendFrames, and don't have a next
11121 // sibling for the new frames, and our parent is the last continuation of
11122 // the last part of the {ib} split, and the same is true of all our
11123 // ancestor inlines (they have no following continuations and they're the
11124 // last part of their {ib} splits and we'd be adding to the end for all
11125 // of them), then AppendFrames will handle things for us. Bail out in
11126 // that case.
11127 if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
11128 return false;
11129 }
11130
11131 // Need to reconstruct.
11132 break;
11133 }
11134
11135 // Now we know we have a block parent. If it's not part of an
11136 // ib-split, we're all set.
11137 if (!IsFramePartOfIBSplit(aFrame)) {
11138 return false;
11139 }
11140
11141 // We're adding some kids to a block part of an {ib} split. If all the
11142 // kids are blocks, we don't need to reconstruct.
11143 if (aItems.AreAllItemsBlock()) {
11144 return false;
11145 }
11146
11147 // We might have some inline kids for this block. Just fall out of the
11148 // loop and reconstruct.
11149 } while (false);
11150
11151 // If we don't have a containing block, start with aFrame and look for one.
11152 if (!aContainingBlock) {
11153 aContainingBlock = aFrame;
11154 }
11155
11156 // To find the right block to reframe, just walk up the tree until we find a
11157 // frame that is:
11158 // 1) Not part of an IB split
11159 // 2) Not a pseudo-frame
11160 // 3) Not an inline frame
11161 // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
11162 // enforces that the root is display:none, display:table, or display:block.
11163 // Note that walking up "too far" is OK in terms of correctness, even if it
11164 // might be a little inefficient. This is why we walk out of all
11165 // pseudo-frames -- telling which ones are or are not OK to walk out of is
11166 // too hard (and I suspect that we do in fact need to walk out of all of
11167 // them).
11168 while (IsFramePartOfIBSplit(aContainingBlock) ||
11169 aContainingBlock->IsInlineOutside() ||
11170 aContainingBlock->Style()->IsPseudoOrAnonBox()) {
11171 aContainingBlock = aContainingBlock->GetParent();
11172 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"
, 11174); MOZ_PretendNoReturn(); } } while (0)
11173 "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"
, 11174); MOZ_PretendNoReturn(); } } while (0)
11174 "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"
, 11174); MOZ_PretendNoReturn(); } } while (0)
;
11175 }
11176
11177 // Tell parent of the containing block to reformulate the
11178 // entire block. This is painful and definitely not optimal
11179 // but it will *always* get the right answer.
11180
11181 nsIContent* blockContent = aContainingBlock->GetContent();
11182 TRACE("IB splits");
11183 RecreateFramesForContent(blockContent, InsertionKind::Async);
11184 return true;
11185#undef TRACE
11186}
11187
11188void nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) {
11189 // XXXbz how exactly would we get here while isReflowing anyway? Should this
11190 // whole test be ifdef DEBUG?
11191 if (mPresShell->IsReflowLocked()) {
11192 // don't ReframeContainingBlock, this will result in a crash
11193 // if we remove a tree that's in reflow - see bug 121368 for testcase
11194 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11196); MOZ_PretendNoReturn(); } while (0)
11195 "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11196); MOZ_PretendNoReturn(); } while (0)
11196 "Reflow!!!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11196); MOZ_PretendNoReturn(); } while (0)
;
11197 return;
11198 }
11199
11200 // Get the first "normal" ancestor of the target frame.
11201 nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11202 if (containingBlock) {
11203 // From here we look for the containing block in case the target
11204 // frame is already a block (which can happen when an inline frame
11205 // wraps some of its content in an anonymous block; see
11206 // ConstructInline)
11207
11208 // NOTE: We used to get the FloatContainingBlock here, but it was often
11209 // wrong. GetIBContainingBlock works much better and provides the correct
11210 // container in all cases so GetFloatContainingBlock(aFrame) has been
11211 // removed
11212
11213 // And get the containingBlock's content
11214 if (nsIContent* blockContent = containingBlock->GetContent()) {
11215#ifdef DEBUG1
11216 if (gNoisyContentUpdates) {
11217 printf(" ==> blockContent=%p\n", blockContent);
11218 }
11219#endif
11220 RecreateFramesForContent(blockContent, InsertionKind::Async);
11221 return;
11222 }
11223 }
11224
11225 // If we get here, we're screwed!
11226 RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11227 InsertionKind::Async);
11228}
11229
11230//////////////////////////////////////////////////////////
11231// nsCSSFrameConstructor::FrameConstructionItem methods //
11232//////////////////////////////////////////////////////////
11233bool nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace(
11234 nsFrameConstructorState& aState) const {
11235 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"
, 11236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11236); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
11236 "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"
, 11236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11236); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11237 if (!mIsText) {
11238 return false;
11239 }
11240 // Set content whitespace flags, but not for generated content, where we
11241 // never expect to see these.
11242 if (!(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT)) {
11243 mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11244 NS_REFRAME_IF_WHITESPACE);
11245 }
11246 return mContent->TextIsOnlyWhitespace();
11247}
11248
11249//////////////////////////////////////////////////////////////
11250// nsCSSFrameConstructor::FrameConstructionItemList methods //
11251//////////////////////////////////////////////////////////////
11252void nsCSSFrameConstructor::FrameConstructionItemList::AdjustCountsForItem(
11253 FrameConstructionItem* aItem, int32_t aDelta) {
11254 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"
, 11254); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDelta == 1 || aDelta == -1"
") (" "Unexpected delta" ")"); do { MOZ_CrashSequence(__null
, 11254); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11255 mItemCount += aDelta;
11256 if (aItem->mIsAllInline) {
11257 mInlineCount += aDelta;
11258 }
11259 if (aItem->mIsBlock) {
11260 mBlockCount += aDelta;
11261 }
11262 mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
11263}
11264
11265////////////////////////////////////////////////////////////////////////
11266// nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11267////////////////////////////////////////////////////////////////////////
11268inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11269 SkipItemsWantingParentType(ParentType aParentType) {
11270 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", 11270
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11270); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11271 while (item().DesiredParentType() == aParentType) {
11272 Next();
11273 if (IsDone()) {
11274 return true;
11275 }
11276 }
11277 return false;
11278}
11279
11280inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11281 SkipItemsNotWantingParentType(ParentType aParentType) {
11282 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", 11282
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11282); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11283 while (item().DesiredParentType() != aParentType) {
11284 Next();
11285 if (IsDone()) {
11286 return true;
11287 }
11288 }
11289 return false;
11290}
11291
11292// Note: we implement -webkit-{inline-}box using nsFlexContainerFrame, but we
11293// use different rules for what gets wrapped in an anonymous flex item.
11294bool nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem(
11295 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11296 if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) {
11297 // This will be an inline non-replaced box.
11298 return true;
11299 }
11300
11301 if (aIsLegacyWebKitBox) {
11302 if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
11303 // In an emulated legacy box, all inline-level content gets wrapped in an
11304 // anonymous flex item.
11305 return true;
11306 }
11307 if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
11308 aState.GetGeometricParent(*mComputedStyle->StyleDisplay(), nullptr)) {
11309 // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
11310 // placeholder which (because our container is an emulated legacy box)
11311 // we'll need to wrap in an anonymous flex item. So, we just treat
11312 // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
11313 // and then when we spawn the placeholder, it'll end up in the right
11314 // spot.
11315 return true;
11316 }
11317 }
11318
11319 return false;
11320}
11321
11322inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11323 SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState& aState,
11324 bool aIsLegacyWebKitBox) {
11325 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", 11325
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11325); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11326 while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox)) {
11327 Next();
11328 if (IsDone()) {
11329 return true;
11330 }
11331 }
11332 return false;
11333}
11334
11335inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11336 SkipItemsThatDontNeedAnonFlexOrGridItem(
11337 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11338 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", 11338
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11338); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11339 while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox))) {
11340 Next();
11341 if (IsDone()) {
11342 return true;
11343 }
11344 }
11345 return false;
11346}
11347
11348inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11349 SkipItemsNotWantingRubyParent() {
11350 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", 11350
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11350); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11351 while (!IsRubyParentType(item().DesiredParentType())) {
11352 Next();
11353 if (IsDone()) {
11354 return true;
11355 }
11356 }
11357 return false;
11358}
11359
11360inline bool
11361nsCSSFrameConstructor::FrameConstructionItemList::Iterator::SkipWhitespace(
11362 nsFrameConstructorState& aState) {
11363 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", 11363
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11363); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11364 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"
, 11364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item().IsWhitespace(aState)"
") (" "Not pointing to whitespace?" ")"); do { MOZ_CrashSequence
(__null, 11364); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11365 do {
11366 Next();
11367 if (IsDone()) {
11368 return true;
11369 }
11370 } while (item().IsWhitespace(aState));
11371
11372 return false;
11373}
11374
11375void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11376 AppendItemToList(FrameConstructionItemList& aTargetList) {
11377 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11377); MOZ_PretendNoReturn(); } } while (0)
;
11378 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", 11378
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "should not be done"
")"); do { MOZ_CrashSequence(__null, 11378); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11379
11380 FrameConstructionItem* item = mCurrent;
11381 Next();
11382 item->remove();
11383 aTargetList.mItems.insertBack(item);
11384
11385 mList.AdjustCountsForItem(item, -1);
11386 aTargetList.AdjustCountsForItem(item, 1);
11387}
11388
11389void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11390 AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
11391 FrameConstructionItemList& aTargetList) {
11392 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11392); MOZ_PretendNoReturn(); } } while (0)
;
11393 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", 11393
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11393); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11394
11395 // We can't just move our guts to the other list if it already has
11396 // some information or if we're not moving our entire list.
11397 if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
11398 do {
11399 AppendItemToList(aTargetList);
11400 } while (*this != aEnd);
11401 return;
11402 }
11403
11404 // Move our entire list of items into the empty target list.
11405 aTargetList.mItems = std::move(mList.mItems);
11406
11407 // Copy over the various counters
11408 aTargetList.mInlineCount = mList.mInlineCount;
11409 aTargetList.mBlockCount = mList.mBlockCount;
11410 aTargetList.mItemCount = mList.mItemCount;
11411 memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
11412 sizeof(aTargetList.mDesiredParentCounts));
11413
11414 // reset mList
11415 mList.Reset(aFCtor);
11416
11417 // Point ourselves to aEnd, as advertised
11418 SetToEnd();
11419 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"
, 11419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this == aEnd"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11419); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11420}
11421
11422void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::InsertItem(
11423 FrameConstructionItem* aItem) {
11424 if (IsDone()) {
11425 mList.mItems.insertBack(aItem);
11426 } else {
11427 // Just insert the item before us. There's no magic here.
11428 mCurrent->setPrevious(aItem);
11429 }
11430 mList.AdjustCountsForItem(aItem, 1);
11431
11432 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", 11432
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem->getNext() == mCurrent"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11432); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11433}
11434
11435void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::DeleteItemsTo(
11436 nsCSSFrameConstructor* aFCtor, const Iterator& aEnd) {
11437 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", 11437
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11437); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11438 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"
, 11438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this != aEnd"
") (" "Shouldn't be at aEnd yet" ")"); do { MOZ_CrashSequence
(__null, 11438); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11439
11440 do {
11441 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"
, 11441); MOZ_PretendNoReturn(); } } while (0)
;
11442 FrameConstructionItem* item = mCurrent;
11443 Next();
11444 item->remove();
11445 mList.AdjustCountsForItem(item, -1);
11446 item->Delete(aFCtor);
11447 } while (*this != aEnd);
11448}
11449
11450void nsCSSFrameConstructor::QuotesDirty() {
11451 mQuotesDirty = true;
11452 mPresShell->SetNeedLayoutFlush();
11453}
11454
11455void nsCSSFrameConstructor::CountersDirty() {
11456 mCountersDirty = true;
11457 mPresShell->SetNeedLayoutFlush();
11458}
11459
11460void* nsCSSFrameConstructor::AllocateFCItem() {
11461 void* item;
11462 if (mFirstFreeFCItem) {
11463 item = mFirstFreeFCItem;
11464 mFirstFreeFCItem = mFirstFreeFCItem->mNext;
11465 } else {
11466 item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
11467 }
11468 ++mFCItemsInUse;
11469 return item;
11470}
11471
11472void nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem) {
11473 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", 11473);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFCItemsInUse != 0"
")"); do { MOZ_CrashSequence(__null, 11473); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11474 if (--mFCItemsInUse == 0) {
11475 // The arena is now unused - clear it but retain one chunk.
11476 mFirstFreeFCItem = nullptr;
11477 mFCItemPool.Clear();
11478 } else {
11479 // Prepend it to the list of free items.
11480 FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
11481 item->mNext = mFirstFreeFCItem;
11482 mFirstFreeFCItem = item;
11483 }
11484}
11485
11486void nsCSSFrameConstructor::AddSizeOfIncludingThis(
11487 nsWindowSizes& aSizes) const {
11488 if (nsIFrame* rootFrame = GetRootFrame()) {
11489 rootFrame->AddSizeOfExcludingThisForTree(aSizes);
11490 if (RetainedDisplayListBuilder* builder =
11491 rootFrame->GetProperty(RetainedDisplayListBuilder::Cached())) {
11492 builder->AddSizeOfIncludingThis(aSizes);
11493 }
11494 }
11495
11496 // This must be done after measuring from the frame tree, since frame
11497 // manager will measure sizes of staled computed values and style
11498 // structs, which only make sense after we know what are being used.
11499 nsFrameManager::AddSizeOfIncludingThis(aSizes);
11500
11501 // Measurement of the following members may be added later if DMD finds it
11502 // is worthwhile:
11503 // - mFCItemPool
11504 // - mContainStyleScopeManager
11505}