Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/layout/base/./../../../layout/base/nsCSSFrameConstructor.cpp
Warning:line 6919, 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/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -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-09-01-224014-2642839-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/HTMLSelectElement.h"
51#include "mozilla/dom/HTMLSharedListElement.h"
52#include "mozilla/dom/HTMLSummaryElement.h"
53#include "mozilla/intl/LocaleService.h"
54#include "nsAtom.h"
55#include "nsAutoLayoutPhase.h"
56#include "nsBlockFrame.h"
57#include "nsCRT.h"
58#include "nsCanvasFrame.h"
59#include "nsCheckboxRadioFrame.h"
60#include "nsComboboxControlFrame.h"
61#include "nsContainerFrame.h"
62#include "nsContentUtils.h"
63#include "nsError.h"
64#include "nsFieldSetFrame.h"
65#include "nsFirstLetterFrame.h"
66#include "nsFlexContainerFrame.h"
67#include "nsGkAtoms.h"
68#include "nsGridContainerFrame.h"
69#include "nsHTMLParts.h"
70#include "nsIAnonymousContentCreator.h"
71#include "nsIFormControl.h"
72#include "nsIFrameInlines.h"
73#include "nsIObjectLoadingContent.h"
74#include "nsIPopupContainer.h"
75#include "nsIScriptError.h"
76#include "nsImageFrame.h"
77#include "nsInlineFrame.h"
78#include "nsLayoutUtils.h"
79#include "nsListControlFrame.h"
80#include "nsMathMLParts.h"
81#include "nsNameSpaceManager.h"
82#include "nsPageContentFrame.h"
83#include "nsPageFrame.h"
84#include "nsPageSequenceFrame.h"
85#include "nsPlaceholderFrame.h"
86#include "nsPresContext.h"
87#include "nsRefreshDriver.h"
88#include "nsRubyBaseContainerFrame.h"
89#include "nsRubyBaseFrame.h"
90#include "nsRubyFrame.h"
91#include "nsRubyTextContainerFrame.h"
92#include "nsRubyTextFrame.h"
93#include "nsStyleConsts.h"
94#include "nsStyleStructInlines.h"
95#include "nsTArray.h"
96#include "nsTableCellFrame.h"
97#include "nsTableColFrame.h"
98#include "nsTableFrame.h"
99#include "nsTableRowFrame.h"
100#include "nsTableRowGroupFrame.h"
101#include "nsTableWrapperFrame.h"
102#include "nsTextControlFrame.h"
103#include "nsTextNode.h"
104#include "nsTransitionManager.h"
105#include "nsUnicharUtils.h"
106#include "nsXULElement.h"
107
108#ifdef XP_MACOSX
109# include "nsIDocShell.h"
110#endif
111
112#ifdef ACCESSIBILITY1
113# include "nsAccessibilityService.h"
114#endif
115
116#undef NOISY_FIRST_LETTER
117
118using namespace mozilla;
119using namespace mozilla::dom;
120
121nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell, ComputedStyle* aStyle);
122
123nsIFrame* NS_NewHTMLVideoFrame(PresShell* aPresShell, ComputedStyle* aStyle);
124nsIFrame* NS_NewHTMLAudioFrame(PresShell* aPresShell, ComputedStyle* aStyle);
125
126nsContainerFrame* NS_NewSVGOuterSVGFrame(PresShell* aPresShell,
127 ComputedStyle* aStyle);
128nsContainerFrame* NS_NewSVGOuterSVGAnonChildFrame(PresShell* aPresShell,
129 ComputedStyle* aStyle);
130nsIFrame* NS_NewSVGInnerSVGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
131nsIFrame* NS_NewSVGGeometryFrame(PresShell* aPresShell, ComputedStyle* aStyle);
132nsIFrame* NS_NewSVGGFrame(PresShell* aPresShell, ComputedStyle* aStyle);
133nsContainerFrame* NS_NewSVGForeignObjectFrame(PresShell* aPresShell,
134 ComputedStyle* aStyle);
135nsIFrame* NS_NewSVGAFrame(PresShell* aPresShell, ComputedStyle* aStyle);
136nsIFrame* NS_NewSVGSwitchFrame(PresShell* aPresShell, ComputedStyle* aStyle);
137nsIFrame* NS_NewSVGSymbolFrame(PresShell* aPresShell, ComputedStyle* aStyle);
138nsIFrame* NS_NewSVGTextFrame(PresShell* aPresShell, ComputedStyle* aStyle);
139nsIFrame* NS_NewSVGContainerFrame(PresShell* aPresShell, ComputedStyle* aStyle);
140nsIFrame* NS_NewSVGUseFrame(PresShell* aPresShell, ComputedStyle* aStyle);
141nsIFrame* NS_NewSVGViewFrame(PresShell* aPresShell, ComputedStyle* aStyle);
142extern nsIFrame* NS_NewSVGLinearGradientFrame(PresShell* aPresShell,
143 ComputedStyle* aStyle);
144extern nsIFrame* NS_NewSVGRadialGradientFrame(PresShell* aPresShell,
145 ComputedStyle* aStyle);
146extern nsIFrame* NS_NewSVGStopFrame(PresShell* aPresShell,
147 ComputedStyle* aStyle);
148nsContainerFrame* NS_NewSVGMarkerFrame(PresShell* aPresShell,
149 ComputedStyle* aStyle);
150nsContainerFrame* NS_NewSVGMarkerAnonChildFrame(PresShell* aPresShell,
151 ComputedStyle* aStyle);
152extern nsIFrame* NS_NewSVGImageFrame(PresShell* aPresShell,
153 ComputedStyle* aStyle);
154nsIFrame* NS_NewSVGClipPathFrame(PresShell* aPresShell, ComputedStyle* aStyle);
155nsIFrame* NS_NewSVGFilterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
156nsIFrame* NS_NewSVGPatternFrame(PresShell* aPresShell, ComputedStyle* aStyle);
157nsIFrame* NS_NewSVGMaskFrame(PresShell* aPresShell, ComputedStyle* aStyle);
158nsIFrame* NS_NewSVGFEContainerFrame(PresShell* aPresShell,
159 ComputedStyle* aStyle);
160nsIFrame* NS_NewSVGFELeafFrame(PresShell* aPresShell, ComputedStyle* aStyle);
161nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
162nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
163 ComputedStyle* aStyle);
164nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
165nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
166nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);
167nsIFrame* NS_NewInputButtonControlFrame(PresShell*, ComputedStyle*);
168
169#include "mozilla/dom/NodeInfo.h"
170#include "nsContentCreatorFunctions.h"
171#include "nsNodeInfoManager.h"
172#include "prenv.h"
173
174#ifdef DEBUG1
175// Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
176// more of the following flags (comma separated) for handy debug
177// output.
178static bool gNoisyContentUpdates = false;
179static bool gReallyNoisyContentUpdates = false;
180static bool gNoisyInlineConstruction = false;
181
182struct FrameCtorDebugFlags {
183 const char* name;
184 bool* on;
185};
186
187static FrameCtorDebugFlags gFrameCtorDebugFlags[] = {
188 {"content-updates", &gNoisyContentUpdates},
189 {"really-noisy-content-updates", &gReallyNoisyContentUpdates},
190 {"noisy-inline", &gNoisyInlineConstruction}};
191
192# define NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags)) (std::size(gFrameCtorDebugFlags))
193#endif
194
195//------------------------------------------------------------------
196
197nsIFrame* NS_NewLeafBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
198
199nsIFrame* NS_NewRangeFrame(PresShell* aPresShell, ComputedStyle* aStyle);
200
201nsIFrame* NS_NewTextBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
202
203nsIFrame* NS_NewSplitterFrame(PresShell* aPresShell, ComputedStyle* aStyle);
204
205nsIFrame* NS_NewMenuPopupFrame(PresShell* aPresShell, ComputedStyle* aStyle);
206
207nsIFrame* NS_NewTreeBodyFrame(PresShell* aPresShell, ComputedStyle* aStyle);
208
209nsIFrame* NS_NewSliderFrame(PresShell* aPresShell, ComputedStyle* aStyle);
210
211nsIFrame* NS_NewScrollbarFrame(PresShell* aPresShell, ComputedStyle* aStyle);
212
213nsIFrame* NS_NewScrollbarButtonFrame(PresShell*, ComputedStyle*);
214nsIFrame* NS_NewSimpleXULLeafFrame(PresShell*, ComputedStyle*);
215
216nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
217nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
218nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
219nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
220nsIFrame* NS_NewImageFrameForViewTransition(PresShell*, ComputedStyle*);
221
222// Returns true if aFrame is an anonymous flex/grid item.
223static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
224 return aFrame->Style()->GetPseudoType() == PseudoStyleType::MozAnonymousItem;
225}
226
227// Returns true IFF the given nsIFrame is a nsFlexContainerFrame and represents
228// a -webkit-{inline-}box container.
229static inline bool IsFlexContainerForLegacyWebKitBox(const nsIFrame* aFrame) {
230 return aFrame->IsFlexContainerFrame() && aFrame->IsLegacyWebkitBox();
231}
232
233static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
234 const nsIFrame* aChild, const nsIFrame* aParent) {
235 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"
, 235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsAnonymousItem(aChild)"
") (" "expected an anonymous item child frame" ")"); do { MOZ_CrashSequence
(__null, 235); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
236 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", 236
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ") (" "expected a parent frame"
")"); do { MOZ_CrashSequence(__null, 236); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
237 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"
, 239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 239)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
238 "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"
, 239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 239)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
239 "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"
, 239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsFlexOrGridContainer()"
") (" "anonymous items should only exist as children of flex/grid "
"container frames" ")"); do { MOZ_CrashSequence(__null, 239)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
240}
241
242static MOZ_ALWAYS_INLINEinline void AssertAnonymousFlexOrGridItemParent(
243 const nsIFrame* aChild) {
244 AssertAnonymousFlexOrGridItemParent(aChild, aChild->GetParent());
245}
246
247#define ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
\
248 [](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { \
249 return _func(aPs, aStyle); \
250 }
251
252/**
253 * True if aFrame is an actual inline frame in the sense of non-replaced
254 * display:inline CSS boxes. In other words, it can be affected by {ib}
255 * splitting and can contain first-letter frames. Basically, this is either an
256 * inline frame (positioned or otherwise) or an line frame (this last because
257 * it can contain first-letter and because inserting blocks in the middle of it
258 * needs to terminate it).
259 */
260static bool IsInlineFrame(const nsIFrame* aFrame) {
261 return aFrame->IsLineParticipant();
262}
263
264/**
265 * True for display: contents elements.
266 */
267static inline bool IsDisplayContents(const Element* aElement) {
268 return aElement->IsDisplayContents();
269}
270
271static inline bool IsDisplayContents(const nsIContent* aContent) {
272 return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
273}
274
275/**
276 * True if aFrame is an instance of an SVG frame class or is an inline/block
277 * frame being used for SVG text.
278 */
279static bool IsFrameForSVG(const nsIFrame* aFrame) {
280 return aFrame->IsSVGFrame() || aFrame->IsInSVGTextSubtree();
281}
282
283static bool IsLastContinuationForColumnContent(const nsIFrame* aFrame) {
284 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"
, 284); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ")")
; do { MOZ_CrashSequence(__null, 284); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
285 return aFrame->Style()->GetPseudoType() ==
286 PseudoStyleType::MozColumnContent &&
287 !aFrame->GetNextContinuation();
288}
289
290/**
291 * Returns true iff aFrame explicitly prevents its descendants from floating
292 * (at least, down to the level of descendants which themselves are
293 * float-containing blocks -- those will manage the floating status of any
294 * lower-level descendents inside them, of course).
295 */
296static bool ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) {
297 return aFrame->IsFlexOrGridContainer() || aFrame->IsMathMLFrame();
298}
299
300// Return true if column-span descendants should be suppressed under aFrame's
301// subtree (until a multi-column container re-establishing a block formatting
302// context). Basically, this is testing whether aFrame establishes a new block
303// formatting context or not.
304static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
305 if (aFrame->Style()->GetPseudoType() == PseudoStyleType::MozColumnContent) {
306 // Never suppress column-span under ::-moz-column-content frames.
307 return false;
308 }
309
310 if (aFrame->IsInlineFrame()) {
311 // Allow inline frames to have column-span block children.
312 return false;
313 }
314
315 if (!aFrame->IsBlockFrameOrSubclass() ||
316 aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) ||
317 aFrame->IsFixedPosContainingBlock()) {
318 // Need to suppress column-span if we:
319 // - Are a different block formatting context,
320 // - Are an out-of-flow frame, OR
321 // - Establish a containing block for fixed-position descendants
322 //
323 // For example, the children of a column-span never need to be further
324 // processed even if there is a nested column-span child. Because a
325 // column-span always creates its own block formatting context, a nested
326 // column-span child won't be in the same block formatting context with the
327 // nearest multi-column ancestor. This is the same case as if the
328 // column-span is outside of a multi-column hierarchy.
329 return true;
330 }
331
332 return false;
333}
334
335// Reparent a frame into a wrapper frame that is a child of its old parent.
336static void ReparentFrame(RestyleManager* aRestyleManager,
337 nsContainerFrame* aNewParentFrame, nsIFrame* aFrame,
338 bool aForceStyleReparent) {
339 aFrame->SetParent(aNewParentFrame);
340 // We reparent frames for two reasons: to put them inside ::first-line, and to
341 // put them inside some wrapper anonymous boxes.
342 if (aForceStyleReparent) {
343 aRestyleManager->ReparentComputedStyleForFirstLine(aFrame);
344 }
345}
346
347static void ReparentFrames(nsCSSFrameConstructor* aFrameConstructor,
348 nsContainerFrame* aNewParentFrame,
349 const nsFrameList& aFrameList,
350 bool aForceStyleReparent) {
351 RestyleManager* restyleManager = aFrameConstructor->RestyleManager();
352 for (nsIFrame* f : aFrameList) {
353 ReparentFrame(restyleManager, aNewParentFrame, f, aForceStyleReparent);
354 }
355}
356
357//----------------------------------------------------------------------
358//
359// When inline frames get weird and have block frames in them, we
360// annotate them to help us respond to incremental content changes
361// more easily.
362
363static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) {
364 bool result = aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT);
365 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", 367
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 367); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
366 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", 367
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 367); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
367 "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", 367
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!result || aFrame->IsBlockFrameOrSubclass() || aFrame->IsInlineFrameOrSubclass()"
") (" "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"
")"); do { MOZ_CrashSequence(__null, 367); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
368 return result;
369}
370
371static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) {
372 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", 372); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 372); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
373
374 // We only store the "ib-split sibling" annotation with the first
375 // frame in the continuation chain. Walk back to find that frame now.
376 return aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
377}
378
379static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) {
380 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", 380); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)" ") (" "Shouldn't call this"
")"); do { MOZ_CrashSequence(__null, 380); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
381
382 // We only store the ib-split sibling annotation with the first
383 // frame in the continuation chain. Walk back to find that frame now.
384 return aFrame->FirstContinuation()->GetProperty(
385 nsIFrame::IBSplitPrevSibling());
386}
387
388static nsContainerFrame* GetLastIBSplitSibling(nsIFrame* aFrame) {
389 for (nsIFrame *frame = aFrame, *next;; frame = next) {
390 next = GetIBSplitSibling(frame);
391 if (!next) {
392 return static_cast<nsContainerFrame*>(frame);
393 }
394 }
395 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"
, 395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unreachable code" ")"); do { MOZ_CrashSequence
(__null, 395); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
396 return nullptr;
397}
398
399static void SetFrameIsIBSplit(nsContainerFrame* aFrame,
400 nsContainerFrame* aIBSplitSibling) {
401 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", 401
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "bad args!"
")"); do { MOZ_CrashSequence(__null, 401); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
402
403 // We should be the only continuation
404 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"
, 405); MOZ_PretendNoReturn(); } } while (0)
405 "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"
, 405); MOZ_PretendNoReturn(); } } while (0)
;
406 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", 408); MOZ_PretendNoReturn
(); } } while (0)
407 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", 408); MOZ_PretendNoReturn
(); } } while (0)
408 "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", 408); MOZ_PretendNoReturn
(); } } while (0)
;
409
410 // Mark the frame as ib-split.
411 aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
412
413 if (aIBSplitSibling) {
414 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", 416); MOZ_PretendNoReturn
(); } } while (0)
415 "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", 416); MOZ_PretendNoReturn
(); } } while (0)
416 "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", 416); MOZ_PretendNoReturn
(); } } while (0)
;
417
418 // Store the ib-split sibling (if we were given one) with the
419 // first frame in the flow.
420 aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling);
421 aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame);
422 }
423}
424
425static nsIFrame* GetIBContainingBlockFor(nsIFrame* aFrame) {
426 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", 428
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 428); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
427 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", 428
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 428); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
428 "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", 428
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFramePartOfIBSplit(aFrame)"
") (" "GetIBContainingBlockFor() should only be called on known IB frames"
")"); do { MOZ_CrashSequence(__null, 428); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
429
430 // Get the first "normal" ancestor of the target frame.
431 nsIFrame* parentFrame;
432 do {
433 parentFrame = aFrame->GetParent();
434
435 if (!parentFrame) {
436 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"
, 436); MOZ_PretendNoReturn(); } while (0)
;
437 return aFrame;
438 }
439
440 // Note that we ignore non-ib-split frames which have a pseudo on their
441 // ComputedStyle -- they're not the frames we're looking for! In
442 // particular, they may be hiding a real parent that _is_ in an ib-split.
443 if (!IsFramePartOfIBSplit(parentFrame) &&
444 !parentFrame->Style()->IsPseudoOrAnonBox()) {
445 break;
446 }
447
448 aFrame = parentFrame;
449 } while (true);
450
451 // post-conditions
452 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"
, 454); MOZ_PretendNoReturn(); } } while (0)
453 "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"
, 454); MOZ_PretendNoReturn(); } } while (0)
454 "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"
, 454); MOZ_PretendNoReturn(); } } while (0)
;
455 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", 456); MOZ_PretendNoReturn
(); } } while (0)
456 "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", 456); MOZ_PretendNoReturn
(); } } while (0)
;
457
458 return parentFrame;
459}
460
461// Find the multicol containing block suitable for reframing.
462//
463// Note: this function may not return a ColumnSetWrapperFrame. For example, if
464// the multicol containing block has "overflow:scroll" style,
465// ScrollContainerFrame is returned because ColumnSetWrapperFrame is the
466// scrolled frame which has the -moz-scrolled-content pseudo style. We may walk
467// up "too far", but in terms of correctness of reframing, it's OK.
468static nsContainerFrame* GetMultiColumnContainingBlockFor(nsIFrame* aFrame) {
469 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", 470
); 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, 470); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
470 "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", 470
); 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, 470); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
471
472 nsContainerFrame* current = aFrame->GetParent();
473 while (current &&
474 (current->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
475 current->Style()->IsPseudoOrAnonBox())) {
476 current = current->GetParent();
477 }
478
479 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", 480
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 480); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
480 "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", 480
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current" ") (" "No multicol containing block in a valid column hierarchy?"
")"); do { MOZ_CrashSequence(__null, 480); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
481
482 return current;
483}
484
485static bool InsertSeparatorBeforeAccessKey() {
486 static bool sInitialized = false;
487 static bool sValue = false;
488 if (!sInitialized) {
489 sInitialized = true;
490 sValue =
491 intl::LocaleService::GetInstance()->InsertSeparatorBeforeAccesskeys();
492 }
493 return sValue;
494}
495
496static bool AlwaysAppendAccessKey() {
497 static bool sInitialized = false;
498 static bool sValue = false;
499 if (!sInitialized) {
500 sInitialized = true;
501 sValue = intl::LocaleService::GetInstance()->AlwaysAppendAccesskeys();
502 }
503 return sValue;
504}
505
506//----------------------------------------------------------------------
507
508// Block/inline frame construction logic. We maintain a few invariants here:
509//
510// 1. Block frames contain block and inline frames.
511//
512// 2. Inline frames only contain inline frames. If an inline parent has a block
513// child then the block child is migrated upward until it lands in a block
514// parent (the inline frames containing block is where it will end up).
515
516inline void SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame) {
517 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", 517
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->GetNextSibling()"
") (" "Should be using a frame list" ")"); do { MOZ_CrashSequence
(__null, 517); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
518 aParent->SetInitialChildList(FrameChildListID::Principal,
519 nsFrameList(aFrame, aFrame));
520}
521
522// -----------------------------------------------------------
523
524// Structure used when constructing formatting object trees. Contains
525// state information needed for absolutely positioned elements
526namespace mozilla {
527struct AbsoluteFrameList final : public nsFrameList {
528 // Containing block for absolutely positioned elements.
529 nsContainerFrame* mContainingBlock;
530
531 explicit AbsoluteFrameList(nsContainerFrame* aContainingBlock = nullptr)
532 : mContainingBlock(aContainingBlock) {}
533
534 // Transfer frames in aOther to this list. aOther becomes empty after this
535 // operation.
536 AbsoluteFrameList(AbsoluteFrameList&& aOther) = default;
537 AbsoluteFrameList& operator=(AbsoluteFrameList&& aOther) = default;
538
539#ifdef DEBUG1
540 // XXXbz Does this need a debug-only assignment operator that nulls out the
541 // childList in the AbsoluteFrameList we're copying? Introducing a difference
542 // between debug and non-debug behavior seems bad, so I guess not...
543 ~AbsoluteFrameList() {
544 NS_ASSERTION(!FirstChild(),do { if (!(!FirstChild())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Dangling child list. Someone forgot to insert it?", "!FirstChild()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 545); MOZ_PretendNoReturn
(); } } while (0)
545 "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", 545); MOZ_PretendNoReturn
(); } } while (0)
;
546 }
547#endif
548};
549} // namespace mozilla
550
551// -----------------------------------------------------------
552
553// Structure for saving the existing state when pushing/poping containing
554// blocks. The destructor restores the state to its previous state
555class MOZ_STACK_CLASS nsFrameConstructorSaveState {
556 public:
557 ~nsFrameConstructorSaveState();
558
559 private:
560 // Pointer to struct whose data we save/restore.
561 AbsoluteFrameList* mList = nullptr;
562
563 // The saved pointer to the fixed list.
564 AbsoluteFrameList* mSavedFixedList = nullptr;
565
566 // Copy of original frame list. This can be the original absolute list or a
567 // float list.
568 AbsoluteFrameList mSavedList;
569
570 // The name of the child list in which our frames would belong.
571 mozilla::FrameChildListID mChildListID = FrameChildListID::Principal;
572 nsFrameConstructorState* mState = nullptr;
573
574 friend class nsFrameConstructorState;
575};
576
577// Structure used for maintaining state information during the
578// frame construction process
579class MOZ_STACK_CLASS nsFrameConstructorState {
580 public:
581 nsPresContext* mPresContext;
582 PresShell* mPresShell;
583 nsCSSFrameConstructor* mFrameConstructor;
584
585 // Containing block information for out-of-flow frames.
586 //
587 // Floats are easy. Whatever is our float CB.
588 //
589 // Regular abspos elements are easy too. Its containing block can be the
590 // nearest abspos element, or the ICB (the canvas frame).
591 //
592 // Top layer abspos elements are always children of the ICB, but we can get
593 // away with having two different lists (mAbsoluteList and
594 // mTopLayerAbsoluteList), because because top layer frames cause
595 // non-top-layer frames to be contained inside (so any descendants of a top
596 // layer abspos can never share containing block with it, unless they're also
597 // in the top layer).
598 //
599 // Regular fixed elements however are trickier. Fixed elements can be
600 // contained in one of three lists:
601 //
602 // * mAbsoluteList, if our abspos cb is also a fixpos cb (e.g., is
603 // transformed or has a filter).
604 //
605 // * mAncestorFixedList, if the fixpos cb is an ancestor element other than
606 // the viewport frame, (so, a transformed / filtered
607 // ancestor).
608 //
609 // * mRealFixedList, which is also the fixed list used for the top layer
610 // fixed items, which is the fixed list of the viewport
611 // frame.
612 //
613 // It is important that mRealFixedList is shared between regular and top layer
614 // fixpos elements, since no-top-layer descendants of top layer fixed elements
615 // could share ICB and vice versa, so without that there would be no guarantee
616 // of layout ordering between them.
617 AbsoluteFrameList mFloatedList;
618 AbsoluteFrameList mAbsoluteList;
619 AbsoluteFrameList mTopLayerAbsoluteList;
620 AbsoluteFrameList mAncestorFixedList;
621 AbsoluteFrameList mRealFixedList;
622
623 // Never null, always pointing to one of the lists documented above.
624 AbsoluteFrameList* mFixedList;
625
626 // What `page: auto` resolves to. This is the used page-name of the parent
627 // frame. Updated by AutoFrameConstructionPageName.
628 const nsAtom* mAutoPageNameValue = nullptr;
629
630 nsCOMPtr<nsILayoutHistoryState> mFrameState;
631 // These bits will be added to the state bits of any frame we construct
632 // using this state.
633 nsFrameState mAdditionalStateBits = NS_FRAME_STATE_NONE;
634
635 // If false (which is the default) then call SetPrimaryFrame() as needed
636 // during frame construction. If true, don't make any SetPrimaryFrame()
637 // calls, except for generated content which doesn't have a primary frame
638 // yet. The mCreatingExtraFrames == true mode is meant to be used for
639 // construction of random "extra" frames for elements via normal frame
640 // construction APIs (e.g. replication of things across pages in paginated
641 // mode).
642 bool mCreatingExtraFrames;
643
644 // This keeps track of whether we have found a "rendered legend" for
645 // the current FieldSetFrame.
646 bool mHasRenderedLegend;
647
648 nsTArray<RefPtr<nsIContent>> mGeneratedContentWithInitializer;
649
650#ifdef DEBUG1
651 // Record the float containing block candidate passed into
652 // MaybePushFloatContainingBlock() to keep track that we've call the method to
653 // handle the float CB scope before processing the CB's children. It is reset
654 // in ConstructFramesFromItemList().
655 nsContainerFrame* mFloatCBCandidate = nullptr;
656#endif
657
658 // Constructor
659 // Use the passed-in history state.
660 nsFrameConstructorState(
661 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
662 nsContainerFrame* aAbsoluteContainingBlock,
663 nsContainerFrame* aFloatContainingBlock,
664 already_AddRefed<nsILayoutHistoryState> aHistoryState);
665 // Get the history state from the pres context's pres shell.
666 nsFrameConstructorState(PresShell* aPresShell,
667 nsContainerFrame* aFixedContainingBlock,
668 nsContainerFrame* aAbsoluteContainingBlock,
669 nsContainerFrame* aFloatContainingBlock);
670
671 ~nsFrameConstructorState();
672
673 // Process the frame insertions for all the out-of-flow nsAbsoluteItems.
674 void ProcessFrameInsertionsForAllLists();
675
676 // Function to push the existing absolute containing block state and
677 // create a new scope. Code that uses this function should get matching
678 // logic in GetAbsoluteContainingBlock.
679 // Also makes aNewAbsoluteContainingBlock the containing block for
680 // fixed-pos elements if necessary.
681 // aPositionedFrame is the frame whose style actually makes
682 // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable
683 // element aPositionedFrame is the element's primary frame and
684 // aNewAbsoluteContainingBlock is the scrolled frame.
685 void PushAbsoluteContainingBlock(
686 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
687 nsFrameConstructorSaveState& aSaveState);
688
689 // Function to forbid floats descendants under aFloatCBCandidate, or open a
690 // new float containing block scope for aFloatCBCandidate. The current
691 // state is saved in aSaveState if a new scope is pushed.
692 void MaybePushFloatContainingBlock(nsContainerFrame* aFloatCBCandidate,
693 nsFrameConstructorSaveState& aSaveState);
694
695 // Helper function for MaybePushFloatContainingBlock().
696 void PushFloatContainingBlock(nsContainerFrame* aNewFloatContainingBlock,
697 nsFrameConstructorSaveState& aSaveState);
698
699 // Function to return the proper geometric parent for a frame with display
700 // struct given by aStyleDisplay and parent's frame given by
701 // aContentParentFrame.
702 nsContainerFrame* GetGeometricParent(
703 const nsStyleDisplay& aStyleDisplay,
704 nsContainerFrame* aContentParentFrame) const;
705
706 // Collect absolute frames in mAbsoluteList which are proper descendants
707 // of aNewParent, and reparent them to aNewParent.
708 //
709 // Note: This function does something unusual that moves absolute items
710 // after their frames are constructed under a column hierarchy which has
711 // column-span elements. Do not use this if you're not dealing with
712 // columns.
713 void ReparentAbsoluteItems(nsContainerFrame* aNewParent);
714
715 // Collect floats in mFloatedList which are proper descendants of aNewParent,
716 // and reparent them to aNewParent.
717 //
718 // Note: This function does something unusual that moves floats after their
719 // frames are constructed under a column hierarchy which has column-span
720 // elements. Do not use this if you're not dealing with columns.
721 void ReparentFloats(nsContainerFrame* aNewParent);
722
723 /**
724 * Function to add a new frame to the right frame list. This MUST be called
725 * on frames before their children have been processed if the frames might
726 * conceivably be out-of-flow; otherwise cleanup in error cases won't work
727 * right. Also, this MUST be called on frames after they have been
728 * initialized.
729 * @param aNewFrame the frame to add
730 * @param aFrameList the list to add in-flow frames to
731 * @param aContent the content pointer for aNewFrame
732 * @param aParentFrame the parent frame for the content if it were in-flow
733 * @param aCanBePositioned pass false if the frame isn't allowed to be
734 * positioned
735 * @param aCanBeFloated pass false if the frame isn't allowed to be
736 * floated
737 */
738 void AddChild(nsIFrame* aNewFrame, nsFrameList& aFrameList,
739 nsIContent* aContent, nsContainerFrame* aParentFrame,
740 bool aCanBePositioned = true, bool aCanBeFloated = true,
741 bool aInsertAfter = false,
742 nsIFrame* aInsertAfterFrame = nullptr);
743
744 /**
745 * Function to return the fixed-pos element list. Normally this will just
746 * hand back the fixed-pos element list, but in case we're dealing with a
747 * transformed element that's acting as an abs-pos and fixed-pos container,
748 * we'll hand back the abs-pos list. Callers should use this function if they
749 * want to get the list acting as the fixed-pos item parent.
750 */
751 AbsoluteFrameList& GetFixedList() { return *mFixedList; }
752 const AbsoluteFrameList& GetFixedList() const { return *mFixedList; }
753
754 protected:
755 friend class nsFrameConstructorSaveState;
756
757 /**
758 * ProcessFrameInsertions takes the frames in aFrameList and adds them as
759 * kids to the aChildListID child list of |aFrameList.containingBlock|.
760 */
761 void ProcessFrameInsertions(AbsoluteFrameList& aFrameList,
762 mozilla::FrameChildListID aChildListID);
763
764 /**
765 * GetOutOfFlowFrameList selects the out-of-flow frame list the new
766 * frame should be added to. If the frame shouldn't be added to any
767 * out-of-flow list, it returns nullptr. The corresponding type of
768 * placeholder is also returned via the aPlaceholderType parameter
769 * if this method doesn't return nullptr. The caller should check
770 * whether the returned list really has a containing block.
771 */
772 AbsoluteFrameList* GetOutOfFlowFrameList(nsIFrame* aNewFrame,
773 bool aCanBePositioned,
774 bool aCanBeFloated,
775 nsFrameState* aPlaceholderType);
776};
777
778nsFrameConstructorState::nsFrameConstructorState(
779 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
780 nsContainerFrame* aAbsoluteContainingBlock,
781 nsContainerFrame* aFloatContainingBlock,
782 already_AddRefed<nsILayoutHistoryState> aHistoryState)
783 : mPresContext(aPresShell->GetPresContext()),
784 mPresShell(aPresShell),
785 mFrameConstructor(aPresShell->FrameConstructor()),
786 mFloatedList(aFloatContainingBlock),
787 mAbsoluteList(aAbsoluteContainingBlock),
788 mTopLayerAbsoluteList(mFrameConstructor->GetCanvasFrame()),
789 mAncestorFixedList(aFixedContainingBlock),
790 mRealFixedList(
791 static_cast<nsContainerFrame*>(mFrameConstructor->GetRootFrame())),
792 // See PushAbsoluteContaningBlock below
793 mFrameState(aHistoryState),
794 mCreatingExtraFrames(false),
795 mHasRenderedLegend(false) {
796 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)
;
797 mFixedList = [&] {
798 if (aFixedContainingBlock == aAbsoluteContainingBlock) {
799 return &mAbsoluteList;
800 }
801 if (aAbsoluteContainingBlock == mRealFixedList.mContainingBlock) {
802 return &mRealFixedList;
803 }
804 return &mAncestorFixedList;
805 }();
806}
807
808nsFrameConstructorState::nsFrameConstructorState(
809 PresShell* aPresShell, nsContainerFrame* aFixedContainingBlock,
810 nsContainerFrame* aAbsoluteContainingBlock,
811 nsContainerFrame* aFloatContainingBlock)
812 : nsFrameConstructorState(
813 aPresShell, aFixedContainingBlock, aAbsoluteContainingBlock,
814 aFloatContainingBlock,
815 aPresShell->GetDocument()->GetLayoutHistoryState()) {}
816
817nsFrameConstructorState::~nsFrameConstructorState() {
818 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)
;
819 ProcessFrameInsertionsForAllLists();
820 for (auto& content : Reversed(mGeneratedContentWithInitializer)) {
821 content->RemoveProperty(nsGkAtoms::genConInitializerProperty);
822 }
823}
824
825void nsFrameConstructorState::ProcessFrameInsertionsForAllLists() {
826 ProcessFrameInsertions(mFloatedList, FrameChildListID::Float);
827 ProcessFrameInsertions(mAbsoluteList, FrameChildListID::Absolute);
828 ProcessFrameInsertions(mTopLayerAbsoluteList, FrameChildListID::Absolute);
829 ProcessFrameInsertions(*mFixedList, FrameChildListID::Absolute);
830 ProcessFrameInsertions(mRealFixedList, FrameChildListID::Absolute);
831}
832
833void nsFrameConstructorState::PushAbsoluteContainingBlock(
834 nsContainerFrame* aNewAbsoluteContainingBlock, nsIFrame* aPositionedFrame,
835 nsFrameConstructorSaveState& aSaveState) {
836 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"
, 837); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 837); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
837 "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"
, 837); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!!aNewAbsoluteContainingBlock == !!aPositionedFrame"
") (" "We should have both or none" ")"); do { MOZ_CrashSequence
(__null, 837); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
838 aSaveState.mList = &mAbsoluteList;
839 aSaveState.mChildListID = FrameChildListID::Absolute;
840 aSaveState.mState = this;
841 aSaveState.mSavedList = std::move(mAbsoluteList);
842 aSaveState.mSavedFixedList = mFixedList;
843 mAbsoluteList = AbsoluteFrameList(aNewAbsoluteContainingBlock);
844 mFixedList = [&] {
845 if (!aPositionedFrame || aPositionedFrame->IsFixedPosContainingBlock()) {
846 // See if we need to treat abspos and fixedpos the same. This happens if
847 // we're a transformed/filtered/etc element, or if we force a null abspos
848 // containing block (for mathml for example).
849 return &mAbsoluteList;
850 }
851 if (aPositionedFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Auto) {
852 // If our new CB is in the top layer, and isn't a fixed CB itself, we also
853 // escape the usual containment.
854 return &mRealFixedList;
855 }
856 if (mFixedList == &mAbsoluteList) {
857 // If we were pointing to our old absolute list, keep pointing to it.
858 return &aSaveState.mSavedList;
859 }
860 // Otherwise keep pointing to the current thing (another ancestor's
861 // absolute list, or the real fixed list, doesn't matter).
862 return mFixedList;
863 }();
864
865 if (aNewAbsoluteContainingBlock &&
866 !aNewAbsoluteContainingBlock->IsAbsoluteContainer()) {
867 aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
868 }
869}
870
871void nsFrameConstructorState::MaybePushFloatContainingBlock(
872 nsContainerFrame* aFloatCBCandidate,
873 nsFrameConstructorSaveState& aSaveState) {
874 // The logic here needs to match the logic in GetFloatContainingBlock().
875 if (ShouldSuppressFloatingOfDescendants(aFloatCBCandidate)) {
876 // Pushing a null float containing block forbids any frames from being
877 // floated until a new float containing block is pushed. See implementation
878 // of nsFrameConstructorState::AddChild().
879 //
880 // XXX we should get rid of null float containing blocks and teach the
881 // various frame classes to deal with floats instead.
882 PushFloatContainingBlock(nullptr, aSaveState);
883 } else if (aFloatCBCandidate->IsFloatContainingBlock()) {
884 PushFloatContainingBlock(aFloatCBCandidate, aSaveState);
885 }
886
887#ifdef DEBUG1
888 mFloatCBCandidate = aFloatCBCandidate;
889#endif
890}
891
892void nsFrameConstructorState::PushFloatContainingBlock(
893 nsContainerFrame* aNewFloatContainingBlock,
894 nsFrameConstructorSaveState& aSaveState) {
895 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"
, 897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 897); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
896 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"
, 897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 897); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
897 "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"
, 897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aNewFloatContainingBlock || aNewFloatContainingBlock->IsFloatContainingBlock()"
") (" "Please push a real float containing block!" ")"); do {
MOZ_CrashSequence(__null, 897); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
898 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", 902); MOZ_PretendNoReturn
(); } } while (0)
899 !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", 902); MOZ_PretendNoReturn
(); } } while (0)
900 !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", 902); MOZ_PretendNoReturn
(); } } while (0)
901 "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", 902); MOZ_PretendNoReturn
(); } } while (0)
902 "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", 902); MOZ_PretendNoReturn
(); } } while (0)
;
903 aSaveState.mList = &mFloatedList;
904 aSaveState.mSavedList = std::move(mFloatedList);
905 aSaveState.mChildListID = FrameChildListID::Float;
906 aSaveState.mState = this;
907 mFloatedList = AbsoluteFrameList(aNewFloatContainingBlock);
908}
909
910nsContainerFrame* nsFrameConstructorState::GetGeometricParent(
911 const nsStyleDisplay& aStyleDisplay,
912 nsContainerFrame* aContentParentFrame) const {
913 // If there is no container for a fixed, absolute, or floating root
914 // frame, we will ignore the positioning. This hack is originally
915 // brought to you by the letter T: tables, since other roots don't
916 // even call into this code. See bug 178855.
917 //
918 // XXX Disabling positioning in this case is a hack. If one was so inclined,
919 // one could support this either by (1) inserting a dummy block between the
920 // table and the canvas or (2) teaching the canvas how to reflow positioned
921 // elements. (1) has the usual problems when multiple frames share the same
922 // content (notice all the special cases in this file dealing with inner
923 // tables and table wrappers which share the same content). (2) requires some
924 // work and possible factoring.
925 //
926 // XXXbz couldn't we just force position to "static" on roots and
927 // float to "none"? That's OK per CSS 2.1, as far as I can tell.
928
929 if (aContentParentFrame && aContentParentFrame->IsInSVGTextSubtree()) {
930 return aContentParentFrame;
931 }
932
933 if (aStyleDisplay.IsFloatingStyle() && mFloatedList.mContainingBlock) {
934 NS_ASSERTION(!aStyleDisplay.IsAbsolutelyPositionedStyle(),do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 935); MOZ_PretendNoReturn(); } } while (0)
935 "Absolutely positioned _and_ floating?")do { if (!(!aStyleDisplay.IsAbsolutelyPositionedStyle())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Absolutely positioned _and_ floating?",
"!aStyleDisplay.IsAbsolutelyPositionedStyle()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 935); MOZ_PretendNoReturn(); } } while (0)
;
936 return mFloatedList.mContainingBlock;
937 }
938
939 if (aStyleDisplay.mTopLayer != StyleTopLayer::None) {
940 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"
, 941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 941); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
941 "-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"
, 941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.mTopLayer == StyleTopLayer::Auto"
") (" "-moz-top-layer should be either none or auto" ")"); do
{ MOZ_CrashSequence(__null, 941); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
942 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", 943
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 943); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
943 "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", 943
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay.IsAbsolutelyPositionedStyle()"
") (" "Top layer items should always be absolutely positioned"
")"); do { MOZ_CrashSequence(__null, 943); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
944 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed) {
945 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"
, 945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealFixedList.mContainingBlock"
") (" "No root frame?" ")"); do { MOZ_CrashSequence(__null, 945
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
946 return mRealFixedList.mContainingBlock;
947 }
948 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", 948); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStyleDisplay.mPosition == StylePositionProperty::Absolute"
")"); do { MOZ_CrashSequence(__null, 948); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
949 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", 949); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mTopLayerAbsoluteList.mContainingBlock" ")"
); do { MOZ_CrashSequence(__null, 949); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
950 return mTopLayerAbsoluteList.mContainingBlock;
951 }
952
953 if (aStyleDisplay.mPosition == StylePositionProperty::Absolute &&
954 mAbsoluteList.mContainingBlock) {
955 return mAbsoluteList.mContainingBlock;
956 }
957
958 if (aStyleDisplay.mPosition == StylePositionProperty::Fixed &&
959 mFixedList->mContainingBlock) {
960 return mFixedList->mContainingBlock;
961 }
962
963 return aContentParentFrame;
964}
965
966void nsFrameConstructorState::ReparentAbsoluteItems(
967 nsContainerFrame* aNewParent) {
968 // Bug 1491727: This function might not conform to the spec. See
969 // https://github.com/w3c/csswg-drafts/issues/1894.
970
971 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"
, 972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 972); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
972 "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"
, 972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 972); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
973
974 AbsoluteFrameList newAbsoluteItems(aNewParent);
975
976 nsIFrame* current = mAbsoluteList.FirstChild();
977 while (current) {
978 nsIFrame* placeholder = current->GetPlaceholderFrame();
979
980 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
981 nsIFrame* next = current->GetNextSibling();
982 mAbsoluteList.RemoveFrame(current);
983 newAbsoluteItems.AppendFrame(aNewParent, current);
984 current = next;
985 } else {
986 current = current->GetNextSibling();
987 }
988 }
989
990 if (newAbsoluteItems.NotEmpty()) {
991 // ~nsFrameConstructorSaveState() will move newAbsoluteItems to
992 // aNewParent's absolute child list.
993 nsFrameConstructorSaveState absoluteSaveState;
994
995 // It doesn't matter whether aNewParent has position style or not. Caller
996 // won't call us if we can't have absolute children.
997 PushAbsoluteContainingBlock(aNewParent, aNewParent, absoluteSaveState);
998 mAbsoluteList = std::move(newAbsoluteItems);
999 }
1000}
1001
1002void nsFrameConstructorState::ReparentFloats(nsContainerFrame* aNewParent) {
1003 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"
, 1004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1004); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1004 "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"
, 1004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)"
") (" "Restrict the usage under column hierarchy." ")"); do {
MOZ_CrashSequence(__null, 1004); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1005 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", 1007
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1007); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1006 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", 1007
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1007); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1007 "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", 1007
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent->IsFloatContainingBlock()"
") (" "Why calling this method if aNewParent is not a float containing block?"
")"); do { MOZ_CrashSequence(__null, 1007); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1008
1009 // Gather floats that should reparent under aNewParent.
1010 AbsoluteFrameList floats(aNewParent);
1011 nsIFrame* current = mFloatedList.FirstChild();
1012 while (current) {
1013 nsIFrame* placeholder = current->GetPlaceholderFrame();
1014 nsIFrame* next = current->GetNextSibling();
1015 if (nsLayoutUtils::IsProperAncestorFrame(aNewParent, placeholder)) {
1016 mFloatedList.RemoveFrame(current);
1017 floats.AppendFrame(aNewParent, current);
1018 }
1019 current = next;
1020 }
1021
1022 if (floats.NotEmpty()) {
1023 // Make floats move into aNewParent's float child list in
1024 // ~nsFrameConstructorSaveState() when destructing floatSaveState.
1025 nsFrameConstructorSaveState floatSaveState;
1026 PushFloatContainingBlock(aNewParent, floatSaveState);
1027 mFloatedList = std::move(floats);
1028 }
1029}
1030
1031AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList(
1032 nsIFrame* aNewFrame, bool aCanBePositioned, bool aCanBeFloated,
1033 nsFrameState* aPlaceholderType) {
1034 const nsStyleDisplay* disp = aNewFrame->StyleDisplay();
1035 if (aCanBeFloated && disp->IsFloatingStyle()) {
1036 *aPlaceholderType = PLACEHOLDER_FOR_FLOAT;
1037 return &mFloatedList;
1038 }
1039
1040 if (aCanBePositioned) {
1041 if (disp->mTopLayer != StyleTopLayer::None) {
1042 *aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
1043 if (disp->mPosition == StylePositionProperty::Fixed) {
1044 *aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
1045 return &mRealFixedList;
1046 }
1047 *aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
1048 return &mTopLayerAbsoluteList;
1049 }
1050 if (disp->mPosition == StylePositionProperty::Absolute) {
1051 *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS;
1052 return &mAbsoluteList;
1053 }
1054 if (disp->mPosition == StylePositionProperty::Fixed) {
1055 *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS;
1056 return mFixedList;
1057 }
1058 }
1059 return nullptr;
1060}
1061
1062void nsFrameConstructorState::AddChild(
1063 nsIFrame* aNewFrame, nsFrameList& aFrameList, nsIContent* aContent,
1064 nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated,
1065 bool aInsertAfter, nsIFrame* aInsertAfterFrame) {
1066 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", 1066); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aNewFrame->GetNextSibling()" ") (" "Shouldn't happen"
")"); do { MOZ_CrashSequence(__null, 1066); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1067
1068 nsFrameState placeholderType = NS_FRAME_STATE_NONE;
1069 AbsoluteFrameList* outOfFlowFrameList = GetOutOfFlowFrameList(
1070 aNewFrame, aCanBePositioned, aCanBeFloated, &placeholderType);
1071
1072 // The comments in GetGeometricParent regarding root table frames
1073 // all apply here, unfortunately. Thus, we need to check whether
1074 // the returned frame items really has containing block.
1075 nsFrameList* frameList;
1076 if (outOfFlowFrameList && outOfFlowFrameList->mContainingBlock) {
1077 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", 1078); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1078); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1078 "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", 1078); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->GetParent() == outOfFlowFrameList->mContainingBlock"
") (" "Parent of the frame is not the containing block?" ")"
); do { MOZ_CrashSequence(__null, 1078); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1079 frameList = outOfFlowFrameList;
1080 } else {
1081 frameList = &aFrameList;
1082 placeholderType = NS_FRAME_STATE_NONE;
1083 }
1084
1085 if (placeholderType != NS_FRAME_STATE_NONE) {
1086 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", 1087); MOZ_PretendNoReturn
(); } } while (0)
1087 "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", 1087); MOZ_PretendNoReturn
(); } } while (0)
;
1088 nsIFrame* placeholderFrame =
1089 nsCSSFrameConstructor::CreatePlaceholderFrameFor(
1090 mPresShell, aContent, aNewFrame, aParentFrame, nullptr,
1091 placeholderType);
1092
1093 placeholderFrame->AddStateBits(mAdditionalStateBits);
1094 // Add the placeholder frame to the flow
1095 aFrameList.AppendFrame(nullptr, placeholderFrame);
1096 }
1097#ifdef DEBUG1
1098 else {
1099 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", 1100); MOZ_PretendNoReturn
(); } } while (0)
1100 "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", 1100); MOZ_PretendNoReturn
(); } } while (0)
;
1101 }
1102#endif
1103
1104 if (aInsertAfter) {
1105 frameList->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame);
1106 } else {
1107 frameList->AppendFrame(nullptr, aNewFrame);
1108 }
1109}
1110
1111// Some of this function's callers recurse 1000 levels deep in crashtests. On
1112// platforms where stack limits are low, we can't afford to incorporate this
1113// function's `AutoTArray`s into its callers' stack frames, so disable inlining.
1114MOZ_NEVER_INLINE__attribute__((noinline)) void nsFrameConstructorState::ProcessFrameInsertions(
1115 AbsoluteFrameList& aFrameList, FrameChildListID aChildListID) {
1116 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", 1119); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1119); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1117 &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", 1119); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1119); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1118 &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", 1119); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1119); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1119 &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", 1119); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "&aFrameList == &mFloatedList || &aFrameList == &mAbsoluteList || &aFrameList == &mTopLayerAbsoluteList || &aFrameList == &mAncestorFixedList || &aFrameList == mFixedList || &aFrameList == &mRealFixedList"
")"); do { MOZ_CrashSequence(__null, 1119); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1120 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"
, 1121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1121); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1121 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"
, 1121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float"
")"); do { MOZ_CrashSequence(__null, 1121); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1122 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", 1123); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1123); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1123 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", 1123); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1123); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1124 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"
, 1125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1125); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1125 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"
, 1125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1125); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1126 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"
, 1127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1127); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1127 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"
, 1127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1127); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1128 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"
, 1129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1129); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1129 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"
, 1129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1129); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1130 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"
, 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1131); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1131 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"
, 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Absolute"
")"); do { MOZ_CrashSequence(__null, 1131); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1132
1133 if (aFrameList.IsEmpty()) {
1134 return;
1135 }
1136
1137 nsContainerFrame* containingBlock = aFrameList.mContainingBlock;
1138
1139 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"
, 1139); MOZ_PretendNoReturn(); } } while (0)
;
1140
1141 // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1142 // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1143 // is set) and doesn't have any frames in the aChildListID child list yet.
1144 const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1145 if (childList.IsEmpty() &&
1146 containingBlock->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1147 // If we're injecting absolutely positioned frames, inject them on the
1148 // absolute containing block
1149 if (aChildListID == FrameChildListID::Absolute) {
1150 containingBlock->GetAbsoluteContainingBlock()->SetInitialChildList(
1151 containingBlock, aChildListID, std::move(aFrameList));
1152 } else {
1153 containingBlock->SetInitialChildList(aChildListID, std::move(aFrameList));
1154 }
1155 } else if (childList.IsEmpty() ||
1156 aChildListID == FrameChildListID::Absolute) {
1157 // The order is not important for abs-pos/fixed-pos frame list, just
1158 // append the frame items to the list directly.
1159 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1160 std::move(aFrameList));
1161 } else {
1162 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", 1162); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aChildListID == FrameChildListID::Float" ")"
); do { MOZ_CrashSequence(__null, 1162); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1163 // Note that whether the frame construction context is doing an append or
1164 // not is not helpful here, since it could be appending to some frame in
1165 // the middle of the document, which means we're not necessarily
1166 // appending to the children of the containing block.
1167 //
1168 // We need to make sure the 'append to the end of document' case is fast.
1169 // So first test the last child of the containing block
1170 nsIFrame* lastChild = childList.LastChild();
1171 lastChild = lastChild->FirstContinuation()->GetPlaceholderFrame();
1172
1173 // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1174 // so this will make out-of-flows respect the ordering of placeholders,
1175 // which is great because it takes care of anonymous content.
1176 nsIFrame* firstNewFrame = aFrameList.FirstChild();
1177 firstNewFrame = firstNewFrame->GetPlaceholderFrame();
1178
1179 // Cache the ancestor chain so that we can reuse it if needed.
1180 AutoTArray<const nsIFrame*, 20> firstNewFrameAncestors;
1181 const nsIFrame* notCommonAncestor = nsLayoutUtils::FillAncestors(
1182 firstNewFrame, containingBlock, &firstNewFrameAncestors);
1183
1184 if (nsLayoutUtils::CompareTreePosition(
1185 lastChild, firstNewFrame, firstNewFrameAncestors,
1186 notCommonAncestor ? containingBlock : nullptr) < 0) {
1187 // lastChild comes before the new children, so just append
1188 mFrameConstructor->AppendFrames(containingBlock, aChildListID,
1189 std::move(aFrameList));
1190 } else {
1191 // Try the other children. First collect them to an array so that a
1192 // reasonable fast binary search can be used to find the insertion point.
1193 AutoTArray<std::pair<nsIFrame*, nsPlaceholderFrame*>, 128> children;
1194 for (nsIFrame* f : childList) {
1195 children.AppendElement(
1196 std::make_pair(f, f->FirstContinuation()->GetPlaceholderFrame()));
1197 }
1198
1199 nsIFrame* insertionPoint = nullptr;
1200 int32_t imin = 0;
1201 int32_t max = children.Length();
1202 while (max > imin) {
1203 int32_t imid = imin + ((max - imin) / 2);
1204 const auto& pair = children[imid];
1205 int32_t compare = nsLayoutUtils::CompareTreePosition(
1206 pair.second, firstNewFrame, firstNewFrameAncestors,
1207 notCommonAncestor ? containingBlock : nullptr);
1208 if (compare > 0) {
1209 // f is after the new frame.
1210 max = imid;
1211 insertionPoint = imid > 0 ? children[imid - 1].first : nullptr;
1212 } else if (compare < 0) {
1213 // f is before the new frame.
1214 imin = imid + 1;
1215 insertionPoint = pair.first;
1216 } else {
1217 // This is for the old behavior. Should be removed once it is
1218 // guaranteed that CompareTreePosition can't return 0!
1219 // See bug 928645.
1220 NS_WARNING("Something odd happening???")NS_DebugBreak(NS_DEBUG_WARNING, "Something odd happening???",
nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp",
1220)
;
1221 insertionPoint = nullptr;
1222 for (auto [frame, placeholder] : children) {
1223 if (nsLayoutUtils::CompareTreePosition(
1224 placeholder, firstNewFrame, firstNewFrameAncestors,
1225 notCommonAncestor ? containingBlock : nullptr) > 0) {
1226 break;
1227 }
1228 insertionPoint = frame;
1229 }
1230 break;
1231 }
1232 }
1233 mFrameConstructor->InsertFrames(containingBlock, aChildListID,
1234 insertionPoint, std::move(aFrameList));
1235 }
1236 }
1237
1238 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"
, 1238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrameList.IsEmpty()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 1238); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1239}
1240
1241nsFrameConstructorSaveState::~nsFrameConstructorSaveState() {
1242 // Restore the state
1243 if (mList) {
1244 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", 1244
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mState" ") (" "Can't have mList set without having a state!"
")"); do { MOZ_CrashSequence(__null, 1244); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1245 mState->ProcessFrameInsertions(*mList, mChildListID);
1246
1247 if (mList == &mState->mAbsoluteList) {
1248 mState->mAbsoluteList = std::move(mSavedList);
1249 mState->mFixedList = mSavedFixedList;
1250 } else {
1251 mState->mFloatedList = std::move(mSavedList);
1252 }
1253
1254 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", 1255
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1255); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1255 "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", 1255
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSavedList.IsEmpty()"
") (" "Frames in mSavedList should've moved back into mState!"
")"); do { MOZ_CrashSequence(__null, 1255); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1256 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"
, 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1257); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1257 "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"
, 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mList->LastChild() || !mList->LastChild()->GetNextSibling()"
") (" "Something corrupted our list!" ")"); do { MOZ_CrashSequence
(__null, 1257); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1258 }
1259}
1260
1261/**
1262 * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1263 * pointer of the frames in the list, and reparents their views as needed.
1264 * nsIFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1265 * ancestors as needed. Then it sets the list as the initial child list
1266 * on aNewParent, unless aNewParent either already has kids or has been
1267 * reflowed; in that case it appends the new frames. Note that this
1268 * method differs from ReparentFrames in that it doesn't change the kids'
1269 * style.
1270 */
1271// XXXbz Since this is only used for {ib} splits, could we just copy the view
1272// bits from aOldParent to aNewParent and then use the
1273// nsFrameList::ApplySetParent? That would still leave us doing two passes
1274// over the list, of course; if we really wanted to we could factor out the
1275// relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1276// views, which would make most of this function go away.
1277static void MoveChildrenTo(nsIFrame* aOldParent, nsContainerFrame* aNewParent,
1278 nsFrameList& aFrameList) {
1279 aFrameList.ApplySetParent(aNewParent);
1280
1281 if (aNewParent->PrincipalChildList().IsEmpty() &&
1282 aNewParent->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
1283 aNewParent->SetInitialChildList(FrameChildListID::Principal,
1284 std::move(aFrameList));
1285 } else {
1286 aNewParent->AppendFrames(FrameChildListID::Principal,
1287 std::move(aFrameList));
1288 }
1289}
1290
1291static void EnsureAutoPageName(nsFrameConstructorState& aState,
1292 const nsContainerFrame* const aFrame) {
1293 // Check if we need to figure out our used page name.
1294 // When building the entire document, this should only happen for the
1295 // root, which will mean the loop will immediately end. Either way, this will
1296 // only happen once for each time the frame constructor is run.
1297 if (aState.mAutoPageNameValue) {
1298 return;
1299 }
1300
1301 for (const nsContainerFrame* frame = aFrame; frame;
1302 frame = frame->GetParent()) {
1303 if (const nsAtom* maybePageName = frame->GetStylePageName()) {
1304 aState.mAutoPageNameValue = maybePageName;
1305 return;
1306 }
1307 }
1308 // Ensure that a root with `page: auto` gets an empty page name
1309 // https://drafts.csswg.org/css-page-3/#using-named-pages
1310 aState.mAutoPageNameValue = nsGkAtoms::_empty;
1311}
1312
1313nsCSSFrameConstructor::AutoFrameConstructionPageName::
1314 AutoFrameConstructionPageName(nsFrameConstructorState& aState,
1315 nsIFrame* const aFrame)
1316 : mState(aState), mNameToRestore(nullptr) {
1317 if (!aState.mPresContext->IsPaginated()) {
1318 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"
, 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1319); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1319 "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"
, 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aState.mAutoPageNameValue"
") (" "Page name should not have been set" ")"); do { MOZ_CrashSequence
(__null, 1319); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1320 return;
1321 }
1322#ifdef DEBUG1
1323 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"
, 1324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1324); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1324 "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"
, 1324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should only have been visited once" ")"); do { MOZ_CrashSequence
(__null, 1324); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1325 aFrame->mWasVisitedByAutoFrameConstructionPageName = true;
1326#endif
1327
1328 EnsureAutoPageName(aState, aFrame->GetParent());
1329 mNameToRestore = aState.mAutoPageNameValue;
1330
1331 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", 1332
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1332); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1332 "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", 1332
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNameToRestore" ") ("
"Page name should have been found by EnsureAutoPageName" ")"
); do { MOZ_CrashSequence(__null, 1332); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1333 if (const nsAtom* maybePageName = aFrame->GetStylePageName()) {
1334 aState.mAutoPageNameValue = maybePageName;
1335 }
1336 aFrame->SetAutoPageValue(aState.mAutoPageNameValue);
1337}
1338
1339nsCSSFrameConstructor::AutoFrameConstructionPageName::
1340 ~AutoFrameConstructionPageName() {
1341 // This isn't actually useful when not in paginated layout, but it's very
1342 // likely cheaper to unconditionally write this pointer than to test for
1343 // paginated layout and then branch on the result.
1344 mState.mAutoPageNameValue = mNameToRestore;
1345}
1346
1347//----------------------------------------------------------------------
1348
1349nsCSSFrameConstructor::nsCSSFrameConstructor(Document* aDocument,
1350 PresShell* aPresShell)
1351 : nsFrameManager(aPresShell),
1352 mDocument(aDocument),
1353 mFirstFreeFCItem(nullptr),
1354 mFCItemsInUse(0),
1355 mCurrentDepth(0),
1356 mQuotesDirty(false),
1357 mCountersDirty(false),
1358 mAlwaysCreateFramesForIgnorableWhitespace(false),
1359 mRemovingContent(false) {
1360#ifdef DEBUG1
1361 static bool gFirstTime = true;
1362 if (gFirstTime) {
1363 gFirstTime = false;
1364 char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1365 if (flags) {
1366 bool error = false;
1367 for (;;) {
1368 char* comma = strchr(flags, ',');
1369 if (comma) *comma = '\0';
1370
1371 bool found = false;
1372 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1373 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1374 while (flag < limit) {
1375 if (nsCRT::strcasecmp(flag->name, flags) == 0) {
1376 *(flag->on) = true;
1377 printf("nsCSSFrameConstructor: setting %s debug flag on\n",
1378 flag->name);
1379 found = true;
1380 break;
1381 }
1382 ++flag;
1383 }
1384
1385 if (!found) error = true;
1386
1387 if (!comma) break;
1388
1389 *comma = ',';
1390 flags = comma + 1;
1391 }
1392
1393 if (error) {
1394 printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1395 FrameCtorDebugFlags* flag = gFrameCtorDebugFlags;
1396 FrameCtorDebugFlags* limit = gFrameCtorDebugFlags + NUM_DEBUG_FLAGS(std::size(gFrameCtorDebugFlags));
1397 while (flag < limit) {
1398 printf(" %s\n", flag->name);
1399 ++flag;
1400 }
1401 printf(
1402 "Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of "
1403 "flag\n");
1404 printf("names (no whitespace)\n");
1405 }
1406 }
1407 }
1408#endif
1409}
1410
1411void nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) {
1412 if (aFrame->StyleDisplay()->IsContainStyle()) {
1413 mContainStyleScopeManager.DestroyScopesFor(aFrame);
1414 }
1415
1416 if (aFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
1417 mContainStyleScopeManager.DestroyQuoteNodesFor(aFrame)) {
1418 QuotesDirty();
1419 }
1420
1421 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
1422 mContainStyleScopeManager.DestroyCounterNodesFor(aFrame)) {
1423 // Technically we don't need to update anything if we destroyed only
1424 // USE nodes. However, this is unlikely to happen in the real world
1425 // since USE nodes generally go along with INCREMENT nodes.
1426 CountersDirty();
1427 }
1428
1429 RestyleManager()->NotifyDestroyingFrame(aFrame);
1430}
1431
1432struct nsGenConInitializer {
1433 UniquePtr<nsGenConNode> mNode;
1434 nsGenConList* mList;
1435 void (nsCSSFrameConstructor::*mDirtyAll)();
1436
1437 nsGenConInitializer(UniquePtr<nsGenConNode> aNode, nsGenConList* aList,
1438 void (nsCSSFrameConstructor::*aDirtyAll)())
1439 : mNode(std::move(aNode)), mList(aList), mDirtyAll(aDirtyAll) {}
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
1500 auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
1501 aOriginatingElement, name);
1502 auto node = MakeUnique<nsCounterUseNode>(
1503 *style, std::move(separator), aContentIndex,
1504 /* aAllCounters = */ type == Type::Counters);
1505
1506 auto initializer = MakeUnique<nsGenConInitializer>(
1507 std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
1508 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1509 aAddChild(c);
1510 return;
1511 }
1512 case Type::OpenQuote:
1513 case Type::CloseQuote:
1514 case Type::NoOpenQuote:
1515 case Type::NoCloseQuote: {
1516 auto node = MakeUnique<nsQuoteNode>(type, aContentIndex);
1517 auto* quoteList =
1518 mContainStyleScopeManager.QuoteListFor(aOriginatingElement);
1519 auto initializer = MakeUnique<nsGenConInitializer>(
1520 std::move(node), quoteList, &nsCSSFrameConstructor::QuotesDirty);
1521 RefPtr c = CreateGenConTextNode(aState, u""_ns, std::move(initializer));
1522 aAddChild(c);
1523 return;
1524 }
1525
1526 case Type::MozLabelContent: {
1527 nsAutoString accesskey;
1528 if (!aOriginatingElement.GetAttr(nsGkAtoms::accesskey, accesskey) ||
1529 accesskey.IsEmpty() || !LookAndFeel::GetMenuAccessKey()) {
1530 // Easy path: just return a regular value attribute content.
1531 nsCOMPtr<nsIContent> content;
1532 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::value,
1533 getter_AddRefs(content));
1534 aAddChild(content);
1535 return;
1536 }
1537
1538 nsAutoString value;
1539 aOriginatingElement.GetAttr(nsGkAtoms::value, value);
1540
1541 auto AppendAccessKeyLabel = [&] {
1542 // Always append accesskey text in uppercase, see bug 1806167.
1543 ToUpperCase(accesskey);
1544 nsAutoString accessKeyLabel = u"("_ns + accesskey + u")"_ns;
1545 if (!StringEndsWith(value, accessKeyLabel)) {
1546 if (InsertSeparatorBeforeAccessKey() && !value.IsEmpty() &&
1547 !NS_IS_SPACE(value.Last())) {
1548 value.Append(' ');
1549 }
1550 value.Append(accessKeyLabel);
1551 }
1552 };
1553 if (AlwaysAppendAccessKey()) {
1554 AppendAccessKeyLabel();
1555 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1556 aAddChild(c);
1557 return;
1558 }
1559
1560 const auto accessKeyStart = [&]() -> Maybe<size_t> {
1561 nsAString::const_iterator start, end;
1562 value.BeginReading(start);
1563 value.EndReading(end);
1564
1565 const auto originalStart = start;
1566 // not appending access key - do case-sensitive search
1567 // first
1568 bool found = true;
1569 if (!FindInReadable(accesskey, start, end)) {
1570 start = originalStart;
1571 // didn't find it - perform a case-insensitive search
1572 found = CaseInsensitiveFindInReadable(accesskey, start, end);
1573 }
1574 if (!found) {
1575 return Nothing();
1576 }
1577 return Some(Distance(originalStart, start));
1578 }();
1579
1580 if (accessKeyStart.isNothing()) {
1581 AppendAccessKeyLabel();
1582 RefPtr c = CreateGenConTextNode(aState, value, nullptr);
1583 aAddChild(c);
1584 return;
1585 }
1586
1587 if (*accessKeyStart != 0) {
1588 RefPtr beginning = CreateGenConTextNode(
1589 aState, Substring(value, 0, *accessKeyStart), nullptr);
1590 aAddChild(beginning);
1591 }
1592
1593 {
1594 RefPtr accessKeyText = CreateGenConTextNode(
1595 aState, Substring(value, *accessKeyStart, accesskey.Length()),
1596 nullptr);
1597 RefPtr<nsIContent> underline =
1598 mDocument->CreateHTMLElement(nsGkAtoms::u);
1599 underline->AppendChildTo(accessKeyText, /* aNotify = */ false,
1600 IgnoreErrors());
1601 aAddChild(underline);
1602 }
1603
1604 size_t accessKeyEnd = *accessKeyStart + accesskey.Length();
1605 if (accessKeyEnd != value.Length()) {
1606 RefPtr valueEnd = CreateGenConTextNode(
1607 aState, Substring(value, *accessKeyStart + accesskey.Length()),
1608 nullptr);
1609 aAddChild(valueEnd);
1610 }
1611 break;
1612 }
1613 case Type::MozAltContent: {
1614 // Use the "alt" attribute; if that fails and the node is an HTML
1615 // <input>, try the value attribute and then fall back to some default
1616 // localized text we have.
1617 // XXX what if the 'alt' attribute is added later, how will we
1618 // detect that and do the right thing here?
1619 if (aOriginatingElement.HasAttr(nsGkAtoms::alt)) {
1620 nsCOMPtr<nsIContent> content;
1621 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::alt,
1622 getter_AddRefs(content));
1623 aAddChild(content);
1624 return;
1625 }
1626
1627 if (aOriginatingElement.IsHTMLElement(nsGkAtoms::input)) {
1628 if (aOriginatingElement.HasAttr(nsGkAtoms::value)) {
1629 nsCOMPtr<nsIContent> content;
1630 NS_NewAttributeContent(mDocument->NodeInfoManager(), nsGkAtoms::value,
1631 getter_AddRefs(content));
1632 aAddChild(content);
1633 return;
1634 }
1635
1636 nsAutoString temp;
1637 nsContentUtils::GetMaybeLocalizedString(
1638 PropertiesFile::FORMS_PROPERTIES, "Submit", mDocument, temp);
1639 RefPtr c = CreateGenConTextNode(aState, temp, nullptr);
1640 aAddChild(c);
1641 return;
1642 }
1643 break;
1644 }
1645 }
1646}
1647
1648void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
1649 nsFrameConstructorState& aState, Element& aOriginatingElement,
1650 const ComputedStyle& aPseudoStyle,
1651 const FunctionRef<void(nsIContent*)> aAddChild) {
1652 const nsStyleList* styleList = aPseudoStyle.StyleList();
1653 if (!styleList->mListStyleImage.IsNone()) {
1654 RefPtr<nsIContent> child =
1655 GeneratedImageContent::CreateForListStyleImage(*mDocument);
1656 aAddChild(child);
1657 child = CreateGenConTextNode(aState, u" "_ns, nullptr);
1658 aAddChild(child);
1659 return;
1660 }
1661 CreateGeneratedContentFromListStyleType(aState, aOriginatingElement,
1662 aPseudoStyle, aAddChild);
1663}
1664
1665void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
1666 nsFrameConstructorState& aState, Element& aOriginatingElement,
1667 const ComputedStyle& aPseudoStyle,
1668 const FunctionRef<void(nsIContent*)> aAddChild) {
1669 using Tag = StyleCounterStyle::Tag;
1670 const auto& styleType = aPseudoStyle.StyleList()->mListStyleType;
1671 switch (styleType.tag) {
1672 case Tag::None:
1673 return;
1674 case Tag::String: {
1675 nsDependentAtomString string(styleType.AsString().AsAtom());
1676 RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr);
1677 aAddChild(child);
1678 return;
1679 }
1680 case Tag::Name:
1681 case Tag::Symbols:
1682 break;
1683 }
1684
1685 auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet,
1686 styleType);
1687 if (styleType.IsName()) {
1688 nsAtom* name = styleType.AsName().AsAtom();
1689 if (name == nsGkAtoms::disc || name == nsGkAtoms::circle ||
1690 name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed ||
1691 name == nsGkAtoms::disclosure_open) {
1692 // We don't need a use node inserted for these.
1693 CounterStyle* counterStyle = mPresShell->GetPresContext()
1694 ->CounterStyleManager()
1695 ->ResolveCounterStyle(name);
1696 nsAutoString text;
1697 node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
1698 // Note that we're done with 'node' in this case. It's not inserted into
1699 // any list so it's deleted when we return.
1700 RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
1701 aAddChild(child);
1702 return;
1703 }
1704 }
1705
1706 auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
1707 aOriginatingElement, nsGkAtoms::list_item);
1708 auto initializer = MakeUnique<nsGenConInitializer>(
1709 std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
1710 RefPtr<nsIContent> child =
1711 CreateGenConTextNode(aState, EmptyString(), std::move(initializer));
1712 aAddChild(child);
1713}
1714
1715// Frames for these may not be leaves in the proper sense, but we still don't
1716// want to expose generated content on them. For the purposes of the page they
1717// should be leaves.
1718static bool HasUAWidget(const Element& aOriginatingElement) {
1719 const ShadowRoot* sr = aOriginatingElement.GetShadowRoot();
1720 return sr && sr->IsUAWidget();
1721}
1722
1723/*
1724 * aParentFrame - the frame that should be the parent of the generated
1725 * content. This is the frame for the corresponding content node,
1726 * which must not be a leaf frame.
1727 *
1728 * Any items created are added to aItems.
1729 *
1730 * We create an XML element (tag _moz_generated_content_before/after/marker)
1731 * representing the pseudoelement. We create a DOM node for each 'content'
1732 * item and make those nodes the children of the XML element. Then we create
1733 * a frame subtree for the XML element as if it were a regular child of
1734 * aParentFrame/aParentContent, giving the XML element the ::before, ::after
1735 * or ::marker style.
1736 */
1737void nsCSSFrameConstructor::CreateGeneratedContentItem(
1738 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
1739 Element& aOriginatingElement, ComputedStyle& aStyle,
1740 PseudoStyleType aPseudoElement, FrameConstructionItemList& aItems,
1741 ItemFlags aExtraFlags) {
1742 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1743 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1744 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1745 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1746 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1747 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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1748 "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"
, 1748); 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, 1748); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1749
1750 if (aPseudoElement != PseudoStyleType::Backdrop &&
1751 aPseudoElement != PseudoStyleType::PickerIcon &&
1752 HasUAWidget(aOriginatingElement) &&
1753 !aOriginatingElement.IsHTMLElement(nsGkAtoms::details)) {
1754 // ::before / ::after / ::marker shouldn't work on <video> / <input>.
1755 return;
1756 }
1757
1758 ServoStyleSet* styleSet = mPresShell->StyleSet();
1759
1760 // Probe for the existence of the pseudo-element.
1761 // |ProbePseudoElementStyle| checks the relevant properties for the pseudo.
1762 // It only returns a non-null value if the pseudo should exist.
1763 RefPtr<ComputedStyle> pseudoStyle = styleSet->ProbePseudoElementStyle(
1764 aOriginatingElement, aPseudoElement, nullptr, &aStyle);
1765 if (!pseudoStyle) {
1766 return;
1767 }
1768
1769 nsAtom* elemName = nullptr;
1770 nsAtom* property = nullptr;
1771 switch (aPseudoElement) {
1772 case PseudoStyleType::Before:
1773 elemName = nsGkAtoms::mozgeneratedcontentbefore;
1774 property = nsGkAtoms::beforePseudoProperty;
1775 break;
1776 case PseudoStyleType::After:
1777 elemName = nsGkAtoms::mozgeneratedcontentafter;
1778 property = nsGkAtoms::afterPseudoProperty;
1779 break;
1780 case PseudoStyleType::Marker:
1781 // We want to get a marker style even if we match no rules, but we still
1782 // want to check the result of GeneratedContentPseudoExists.
1783 elemName = nsGkAtoms::mozgeneratedcontentmarker;
1784 property = nsGkAtoms::markerPseudoProperty;
1785 break;
1786 case PseudoStyleType::Backdrop:
1787 elemName = nsGkAtoms::mozgeneratedcontentbackdrop;
1788 property = nsGkAtoms::backdropPseudoProperty;
1789 break;
1790 case PseudoStyleType::Checkmark:
1791 elemName = nsGkAtoms::mozgeneratedcontentcheckmark;
1792 property = nsGkAtoms::checkmarkPseudoProperty;
1793 break;
1794 case PseudoStyleType::PickerIcon:
1795 elemName = nsGkAtoms::mozgeneratedcontentpickericon;
1796 property = nsGkAtoms::pickerIconPseudoProperty;
1797 break;
1798 default:
1799 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"
, 1799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected aPseudoElement" ")");
do { MOZ_CrashSequence(__null, 1799); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1800 }
1801
1802 RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
1803 elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
1804 RefPtr<Element> container;
1805 nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1806 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1807 return;
1808 }
1809
1810 // Cleared when the pseudo is unbound from the tree, so no need to store a
1811 // strong reference, nor a destructor.
1812 aOriginatingElement.SetProperty(property, container.get());
1813
1814 container->SetIsNativeAnonymousRoot();
1815 container->SetPseudoElementType(aPseudoElement);
1816
1817 BindContext context(aOriginatingElement, BindContext::ForNativeAnonymous);
1818 rv = container->BindToTree(context, aOriginatingElement);
1819 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1820 container->UnbindFromTree();
1821 return;
1822 }
1823
1824 if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
1825 container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
1826 }
1827
1828 // Servo has already eagerly computed the style for the container, so we can
1829 // just stick the style on the element and avoid an additional traversal.
1830 //
1831 // We don't do this for pseudos that may trigger animations or transitions,
1832 // since those need to be kicked off by the traversal machinery.
1833 //
1834 // Note that when a pseudo-element animates, we flag the originating element,
1835 // so we check that flag, but we could also a more expensive (but exhaustive)
1836 // check using EffectSet::GetEffectSet, for example.
1837 if (!Servo_ComputedValues_SpecifiesAnimationsOrTransitions(pseudoStyle) &&
1838 !aOriginatingElement.MayHaveAnimations()) {
1839 Servo_SetExplicitStyle(container, pseudoStyle);
1840 } else {
1841 // If animations are involved, we avoid the SetExplicitStyle optimization
1842 // above. We need to grab style with animations from the pseudo element and
1843 // replace old one.
1844 mPresShell->StyleSet()->StyleNewSubtree(container);
1845 pseudoStyle = ServoStyleSet::ResolveServoStyle(*container);
1846 }
1847 if (aPseudoElement != PseudoStyleType::Backdrop) {
1848 auto AppendChild = [&container, this](nsIContent* aChild) {
1849 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
1850 // here; it would get set under AppendChildTo. But AppendChildTo might
1851 // think that we're going from not being anonymous to being anonymous and
1852 // do some extra work; setting the flag here avoids that.
1853 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1854 container->AppendChildTo(aChild, false, IgnoreErrors());
1855 if (auto* childElement = Element::FromNode(aChild)) {
1856 // If we created any children elements, Servo needs to traverse them,
1857 // but the root is already set up.
1858 mPresShell->StyleSet()->StyleNewSubtree(childElement);
1859 }
1860 };
1861 auto items = pseudoStyle->StyleContent()->NonAltContentItems();
1862 size_t index = 0;
1863 for (const auto& item : items) {
1864 CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
1865 index++, AppendChild);
1866 }
1867 // If a ::marker has no 'content' then generate it from its 'list-style-*'.
1868 if (index == 0 && aPseudoElement == PseudoStyleType::Marker) {
1869 CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
1870 *pseudoStyle, AppendChild);
1871 }
1872 }
1873 auto flags = ItemFlags{ItemFlag::IsGeneratedContent} + aExtraFlags;
1874 AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
1875 pseudoStyle, flags, aItems);
1876}
1877
1878/****************************************************
1879 ** BEGIN TABLE SECTION
1880 ****************************************************/
1881
1882// The term pseudo frame is being used instead of anonymous frame, since
1883// anonymous frame has been used elsewhere to refer to frames that have
1884// generated content
1885
1886// Return whether the given frame is a table pseudo-frame. Note that
1887// cell-content and table-outer frames have pseudo-types, but are always
1888// created, even for non-anonymous cells and tables respectively. So for those
1889// we have to examine the cell or table frame to see whether it's a pseudo
1890// frame. In particular, a lone table caption will have a table wrapper as its
1891// parent, but will also trigger construction of an empty inner table, which
1892// will be the one we can examine to see whether the wrapper was a pseudo-frame.
1893static bool IsTablePseudo(nsIFrame* aFrame) {
1894 auto pseudoType = aFrame->Style()->GetPseudoType();
1895 if (pseudoType == PseudoStyleType::NotPseudo) {
1896 return false;
1897 }
1898 return pseudoType == PseudoStyleType::MozTable ||
1899 pseudoType == PseudoStyleType::MozInlineTable ||
1900 pseudoType == PseudoStyleType::MozTableColumnGroup ||
1901 pseudoType == PseudoStyleType::MozTableRowGroup ||
1902 pseudoType == PseudoStyleType::MozTableRow ||
1903 pseudoType == PseudoStyleType::MozTableCell ||
1904 (pseudoType == PseudoStyleType::MozCellContent &&
1905 aFrame->GetParent()->Style()->GetPseudoType() ==
1906 PseudoStyleType::MozTableCell) ||
1907 (pseudoType == PseudoStyleType::MozTableWrapper &&
1908 static_cast<nsTableWrapperFrame*>(aFrame)
1909 ->InnerTableFrame()
1910 ->Style()
1911 ->IsPseudoOrAnonBox());
1912}
1913
1914static bool IsRubyPseudo(nsIFrame* aFrame) {
1915 return RubyUtils::IsRubyPseudo(aFrame->Style()->GetPseudoType());
1916}
1917
1918// Note that this is (subtly) different to ParentIsWrapperAnonBox, since
1919// ParentIsWrapperAnonBox is really just about restyles, but there are wrapper
1920// anon boxes that don't need to return true for that...
1921// FIXME(emilio): This should be less complicated, ParentIsWrapperAnonBox should
1922// probably be renamed to something else, and this should just use
1923// IsWrapperAnonBox or similar...
1924static bool IsWrapperPseudo(nsIFrame* aFrame) {
1925 auto pseudoType = aFrame->Style()->GetPseudoType();
1926 if (!PseudoStyle::IsAnonBox(pseudoType)) {
1927 return false;
1928 }
1929 return PseudoStyle::IsWrapperAnonBox(pseudoType) || IsTablePseudo(aFrame);
1930}
1931
1932static bool IsInAnonymousTable(nsIFrame* aFrame) {
1933 for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
1934 if (!IsWrapperPseudo(f)) {
1935 return false;
1936 }
1937 if (f->IsTableWrapperFrame()) {
1938 return true;
1939 }
1940 }
1941 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"
, 1941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Expected to be called inside tables"
")"); do { MOZ_CrashSequence(__null, 1941); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1942 return false;
1943}
1944
1945/* static */
1946nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType(
1947 LayoutFrameType aFrameType) {
1948 if (aFrameType == LayoutFrameType::Table) {
1949 return eTypeTable;
1950 }
1951 if (aFrameType == LayoutFrameType::TableRowGroup) {
1952 return eTypeRowGroup;
1953 }
1954 if (aFrameType == LayoutFrameType::TableRow) {
1955 return eTypeRow;
1956 }
1957 if (aFrameType == LayoutFrameType::TableColGroup) {
1958 return eTypeColGroup;
1959 }
1960 if (aFrameType == LayoutFrameType::RubyBaseContainer) {
1961 return eTypeRubyBaseContainer;
1962 }
1963 if (aFrameType == LayoutFrameType::RubyTextContainer) {
1964 return eTypeRubyTextContainer;
1965 }
1966 if (aFrameType == LayoutFrameType::Ruby) {
1967 return eTypeRuby;
1968 }
1969
1970 return eTypeBlock;
1971}
1972
1973// Pull all the captions present in aItems out into aCaptions.
1974static void PullOutCaptionFrames(nsFrameList& aList, nsFrameList& aCaptions) {
1975 nsIFrame* child = aList.FirstChild();
1976 while (child) {
1977 nsIFrame* nextSibling = child->GetNextSibling();
1978 if (child->StyleDisplay()->mDisplay == StyleDisplay::TableCaption) {
1979 aList.RemoveFrame(child);
1980 aCaptions.AppendFrame(nullptr, child);
1981 }
1982 child = nextSibling;
1983 }
1984}
1985
1986// Construct the outer, inner table frames and the children frames for the
1987// table.
1988// XXX Page break frames for pseudo table frames are not constructed to avoid
1989// the risk associated with revising the pseudo frame mechanism. The long term
1990// solution of having frames handle page-break-before/after will solve the
1991// problem.
1992nsIFrame* nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
1993 FrameConstructionItem& aItem,
1994 nsContainerFrame* aParentFrame,
1995 const nsStyleDisplay* aDisplay,
1996 nsFrameList& aFrameList) {
1997 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"
, 1999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
1999); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
1998 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"
, 1999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
1999); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
1999 "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"
, 1999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::Table || aDisplay->mDisplay == StyleDisplay::InlineTable"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
1999); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2000
2001 nsIContent* const content = aItem.mContent;
2002 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2003 const bool isMathMLContent = content->IsMathMLElement();
2004
2005 // create the pseudo SC for the table wrapper as a child of the inner SC
2006 RefPtr<ComputedStyle> outerComputedStyle =
2007 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2008 PseudoStyleType::MozTableWrapper, computedStyle);
2009
2010 // Create the table wrapper frame which holds the caption and inner table
2011 // frame
2012 nsContainerFrame* newFrame;
2013 if (isMathMLContent) {
2014 newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerComputedStyle);
2015 } else {
2016 newFrame = NS_NewTableWrapperFrame(mPresShell, outerComputedStyle);
2017 }
2018
2019 nsContainerFrame* geometricParent = aState.GetGeometricParent(
2020 *outerComputedStyle->StyleDisplay(), aParentFrame);
2021
2022 // Init the table wrapper frame
2023 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
2024
2025 // Create the inner table frame
2026 nsContainerFrame* innerFrame;
2027 if (isMathMLContent) {
2028 innerFrame = NS_NewMathMLmtableFrame(mPresShell, computedStyle);
2029 } else {
2030 innerFrame = NS_NewTableFrame(mPresShell, computedStyle);
2031 }
2032
2033 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
2034 innerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2035
2036 // Put the newly created frames into the right child list
2037 SetInitialSingleChild(newFrame, innerFrame);
2038
2039 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
2040
2041 if (!mRootElementFrame) {
2042 mRootElementFrame = newFrame;
2043 }
2044
2045 nsFrameList childList;
2046
2047 // Process children
2048 nsFrameConstructorSaveState absoluteSaveState;
2049
2050 // Mark the table frame as an absolute container if needed
2051 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2052 if (newFrame->IsAbsPosContainingBlock()) {
2053 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
2054 }
2055
2056 nsFrameConstructorSaveState floatSaveState;
2057 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
2058
2059 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2060 ConstructFramesFromItemList(
2061 aState, aItem.mChildItems, innerFrame,
2062 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2063 } else {
2064 ProcessChildren(aState, content, computedStyle, innerFrame, true, childList,
2065 false);
2066 }
2067
2068 nsFrameList captionList;
2069 PullOutCaptionFrames(childList, captionList);
2070
2071 // Set the inner table frame's principal child list.
2072 innerFrame->SetInitialChildList(FrameChildListID::Principal,
2073 std::move(childList));
2074
2075 // Append caption frames to the table wrapper frame's principal child list.
2076 if (captionList.NotEmpty()) {
2077 captionList.ApplySetParent(newFrame);
2078 newFrame->AppendFrames(FrameChildListID::Principal, std::move(captionList));
2079 }
2080
2081 return newFrame;
2082}
2083
2084static void MakeTablePartAbsoluteContainingBlock(
2085 nsFrameConstructorState& aState, nsFrameConstructorSaveState& aAbsSaveState,
2086 nsContainerFrame* aFrame) {
2087 // If we're positioned, then we need to become an absolute containing block
2088 // for any absolutely positioned children.
2089 aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2090 if (aFrame->IsAbsPosContainingBlock()) {
2091 aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState);
2092 }
2093}
2094
2095nsIFrame* nsCSSFrameConstructor::ConstructTableRowOrRowGroup(
2096 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2097 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2098 nsFrameList& aFrameList) {
2099 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"
, 2103); 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, 2103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2100 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"
, 2103); 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, 2103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2101 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"
, 2103); 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, 2103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2102 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"
, 2103); 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, 2103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2103 "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"
, 2103); 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, 2103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2104 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"
, 2105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2105); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2105 "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"
, 2105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem.mComputedStyle->StyleDisplay() == aDisplay"
") (" "Display style doesn't match style" ")"); do { MOZ_CrashSequence
(__null, 2105); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2106 nsIContent* const content = aItem.mContent;
2107 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2108
2109 nsContainerFrame* newFrame;
2110 if (aDisplay->mDisplay == StyleDisplay::TableRow) {
2111 if (content->IsMathMLElement()) {
2112 newFrame = NS_NewMathMLmtrFrame(mPresShell, computedStyle);
2113 } else {
2114 newFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
2115 }
2116 } else {
2117 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
2118 }
2119
2120 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
2121
2122 nsFrameConstructorSaveState absoluteSaveState;
2123 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, newFrame);
2124
2125 nsFrameConstructorSaveState floatSaveState;
2126 aState.MaybePushFloatContainingBlock(newFrame, floatSaveState);
2127
2128 nsFrameList childList;
2129 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2130 ConstructFramesFromItemList(
2131 aState, aItem.mChildItems, newFrame,
2132 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2133 } else {
2134 ProcessChildren(aState, content, computedStyle, newFrame, true, childList,
2135 false);
2136 }
2137
2138 newFrame->SetInitialChildList(FrameChildListID::Principal,
2139 std::move(childList));
2140 aFrameList.AppendFrame(nullptr, newFrame);
2141 return newFrame;
2142}
2143
2144nsIFrame* nsCSSFrameConstructor::ConstructTableCol(
2145 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2146 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2147 nsFrameList& aFrameList) {
2148 nsIContent* const content = aItem.mContent;
2149 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2150
2151 nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, computedStyle);
2152 InitAndRestoreFrame(aState, content, aParentFrame, colFrame);
2153
2154 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", 2154); MOZ_PretendNoReturn
(); } } while (0)
;
2155
2156 aFrameList.AppendFrame(nullptr, colFrame);
2157
2158 // construct additional col frames if the col frame has a span > 1
2159 int32_t span = colFrame->GetSpan();
2160 for (int32_t spanX = 1; spanX < span; spanX++) {
2161 nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, computedStyle);
2162 InitAndRestoreFrame(aState, content, aParentFrame, newCol,
2163 AllowCounters::No);
2164 aFrameList.LastChild()->SetNextContinuation(newCol);
2165 newCol->SetPrevContinuation(aFrameList.LastChild());
2166 aFrameList.AppendFrame(nullptr, newCol);
2167 newCol->SetColType(eColAnonymousCol);
2168 }
2169
2170 return colFrame;
2171}
2172
2173nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
2174 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2175 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
2176 nsFrameList& aFrameList) {
2177 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"
, 2177); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay->mDisplay == StyleDisplay::TableCell"
") (" "Unexpected call" ")"); do { MOZ_CrashSequence(__null,
2177); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2178
2179 nsIContent* const content = aItem.mContent;
2180 ComputedStyle* const computedStyle = aItem.mComputedStyle;
2181 const bool isMathMLContent = content->IsMathMLElement();
2182
2183 nsTableFrame* tableFrame =
2184 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
2185 nsContainerFrame* cellFrame;
2186 // <mtable> is border separate in mathml.css and the MathML code doesn't
2187 // implement border collapse. For those users who style <mtable> with border
2188 // collapse, give them the default non-MathML table frames that understand
2189 // border collapse. This won't break us because MathML table frames are all
2190 // subclasses of the default table code, and so we can freely mix <mtable>
2191 // with <mtr> or <tr>, <mtd> or <td>. What will happen is just that non-MathML
2192 // frames won't understand MathML attributes and will therefore miss the
2193 // special handling that the MathML code does.
2194 if (isMathMLContent && !tableFrame->IsBorderCollapse()) {
2195 cellFrame = NS_NewMathMLmtdFrame(mPresShell, computedStyle, tableFrame);
2196 } else {
2197 // Warning: If you change this and add a wrapper frame around table cell
2198 // frames, make sure Bug 368554 doesn't regress!
2199 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2200 cellFrame = NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
2201 }
2202
2203 // Initialize the table cell frame
2204 InitAndRestoreFrame(aState, content, aParentFrame, cellFrame);
2205 cellFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2206
2207 // Resolve pseudo style and initialize the body cell frame
2208 RefPtr<ComputedStyle> innerPseudoStyle =
2209 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
2210 PseudoStyleType::MozCellContent, computedStyle);
2211
2212 nsContainerFrame* cellInnerFrame;
2213 nsContainerFrame* scrollFrame = nullptr;
2214 bool isScrollable = false;
2215 // Create a block frame that will format the cell's content
2216 if (isMathMLContent) {
2217 cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2218 } else {
2219 isScrollable = innerPseudoStyle->StyleDisplay()->IsScrollableOverflow() &&
2220 !aState.mPresContext->IsPaginated() &&
2221 StaticPrefs::layout_tables_scrollable_cells();
2222 if (isScrollable) {
2223 innerPseudoStyle = BeginBuildingScrollContainerFrame(
2224 aState, content, innerPseudoStyle, cellFrame, false, scrollFrame);
2225 }
2226 cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle);
2227 }
2228 auto* parent = scrollFrame ? scrollFrame : cellFrame;
2229 InitAndRestoreFrame(aState, content, parent, cellInnerFrame);
2230
2231 nsFrameConstructorSaveState absoluteSaveState;
2232 MakeTablePartAbsoluteContainingBlock(aState, absoluteSaveState, cellFrame);
2233
2234 nsFrameConstructorSaveState floatSaveState;
2235 aState.MaybePushFloatContainingBlock(cellInnerFrame, floatSaveState);
2236
2237 nsFrameList childList;
2238 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
2239 AutoFrameConstructionPageName pageNameTracker(aState, cellInnerFrame);
2240 ConstructFramesFromItemList(
2241 aState, aItem.mChildItems, cellInnerFrame,
2242 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
2243 } else {
2244 // Process the child content
2245 ProcessChildren(aState, content, computedStyle, cellInnerFrame, true,
2246 childList, !isMathMLContent);
2247 }
2248
2249 cellInnerFrame->SetInitialChildList(FrameChildListID::Principal,
2250 std::move(childList));
2251
2252 if (isScrollable) {
2253 FinishBuildingScrollContainerFrame(scrollFrame, cellInnerFrame);
2254 }
2255 SetInitialSingleChild(cellFrame, scrollFrame ? scrollFrame : cellInnerFrame);
2256 aFrameList.AppendFrame(nullptr, cellFrame);
2257 return cellFrame;
2258}
2259
2260static inline bool NeedFrameFor(const nsFrameConstructorState& aState,
2261 nsContainerFrame* aParentFrame,
2262 nsIContent* aChildContent) {
2263 // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2264 // Remove it once that's fixed.
2265 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"
, 2268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2268); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2266 !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"
, 2268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2268); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2267 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"
, 2268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2268); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
2268 "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"
, 2268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChildContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent"
") (" "Why did we get called?" ")"); do { MOZ_CrashSequence(
__null, 2268); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2269
2270 // don't create a whitespace frame if aParentFrame doesn't want it.
2271 // always create frames for children in generated content. counter(),
2272 // quotes, and attr() content can easily change dynamically and we don't
2273 // want to be reconstructing frames. It's not even clear that these
2274 // should be considered ignorable just because they evaluate to
2275 // whitespace.
2276
2277 // We could handle all this in CreateNeededPseudoContainers or some other
2278 // place after we build our frame construction items, but that would involve
2279 // creating frame construction items for whitespace kids that ignores
2280 // white-space, where we know we'll be dropping them all anyway, and involve
2281 // an extra walk down the frame construction item list.
2282 auto excludesIgnorableWhitespace = [](nsIFrame* aParentFrame) {
2283 return aParentFrame->IsMathMLFrame();
2284 };
2285 if (!aParentFrame || !excludesIgnorableWhitespace(aParentFrame) ||
2286 aParentFrame->IsGeneratedContentFrame() || !aChildContent->IsText()) {
2287 return true;
2288 }
2289
2290 aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2291 NS_REFRAME_IF_WHITESPACE);
2292 return !aChildContent->TextIsOnlyWhitespace();
2293}
2294
2295/***********************************************
2296 * END TABLE SECTION
2297 ***********************************************/
2298
2299nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
2300 Element* aDocElement) {
2301 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", 2302
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2302); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2302 "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", 2302
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetRootFrame()" ") ("
"No viewport? Someone forgot to call ConstructRootFrame!" ")"
); do { MOZ_CrashSequence(__null, 2302); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2303 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", 2304); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2304); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2304 "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", 2304); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDocElementContainingBlock" ") (" "Shouldn't have a doc element containing block here"
")"); do { MOZ_CrashSequence(__null, 2304); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2305
2306 // Ensure the document element is styled at this point.
2307 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2308 // construction from PresShell::Initialize.
2309 if (!aDocElement->HasServoData()) {
2310 mPresShell->StyleSet()->StyleNewSubtree(aDocElement);
2311 }
2312 aDocElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2313
2314 // Make sure to call UpdateViewportScrollStylesOverride before
2315 // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2316 // properly.
2317 DebugOnly<nsIContent*> propagatedScrollFrom;
2318 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
2319 propagatedScrollFrom = presContext->UpdateViewportScrollStylesOverride();
2320 }
2321
2322 SetUpDocElementContainingBlock(aDocElement);
2323
2324 // This has the side-effect of getting `mFrameTreeState` from our docshell.
2325 //
2326 // FIXME(emilio): There may be a more sensible time to do this.
2327 if (!mFrameTreeState) {
2328 mPresShell->CaptureHistoryState(getter_AddRefs(mFrameTreeState));
2329 }
2330
2331 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"
, 2331); MOZ_PretendNoReturn(); } } while (0)
;
2332 nsFrameConstructorState state(
2333 mPresShell,
2334 GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
2335 nullptr, nullptr, do_AddRef(mFrameTreeState));
2336
2337 RefPtr<ComputedStyle> computedStyle =
2338 ServoStyleSet::ResolveServoStyle(*aDocElement);
2339
2340 const nsStyleDisplay* display = computedStyle->StyleDisplay();
2341
2342 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2343
2344 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", 2347); MOZ_PretendNoReturn
(); } } while (0)
2345 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", 2347); MOZ_PretendNoReturn
(); } } while (0)
2346 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", 2347); MOZ_PretendNoReturn
(); } } while (0)
2347 "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", 2347); MOZ_PretendNoReturn
(); } } while (0)
;
2348
2349 if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)(__builtin_expect(!!(display->mDisplay == StyleDisplay::None
), 0))
) {
2350 return nullptr;
2351 }
2352
2353 // This implements "The Principal Writing Mode".
2354 // https://drafts.csswg.org/css-writing-modes-3/#principal-flow
2355 //
2356 // If there's a <body> element in an HTML document, its writing-mode,
2357 // direction, and text-orientation override the root element's used value.
2358 //
2359 // We need to copy <body>'s WritingMode to mDocElementContainingBlock before
2360 // construct mRootElementFrame so that anonymous internal frames such as
2361 // <html> with table style can copy their parent frame's mWritingMode in
2362 // nsIFrame::Init().
2363 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"
, 2365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2365); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2364 "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"
, 2365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2365); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2365 "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"
, 2365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "We need to copy <body>'s principal writing-mode before "
"constructing mRootElementFrame." ")"); do { MOZ_CrashSequence
(__null, 2365); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2366
2367 const WritingMode propagatedWM = [&] {
2368 const WritingMode rootWM(computedStyle);
2369 if (computedStyle->StyleDisplay()->IsContainAny()) {
2370 return rootWM;
2371 }
2372 Element* body = mDocument->GetBodyElement();
2373 if (!body) {
2374 return rootWM;
2375 }
2376 RefPtr<ComputedStyle> bodyStyle = ResolveComputedStyle(body);
2377 if (bodyStyle->StyleDisplay()->IsContainAny()) {
2378 return rootWM;
2379 }
2380 const WritingMode bodyWM(bodyStyle);
2381 if (bodyWM != rootWM) {
2382 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Layout"_ns,
2383 mDocument,
2384 PropertiesFile::LAYOUT_PROPERTIES,
2385 "PrincipalWritingModePropagationWarning");
2386 }
2387 return bodyWM;
2388 }();
2389
2390 mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
2391 propagatedWM);
2392
2393 // Push the absolute containing block now so we can absolutely position the
2394 // root element
2395 nsFrameConstructorSaveState canvasCbSaveState;
2396 mCanvasFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2397
2398 state.PushAbsoluteContainingBlock(mCanvasFrame, mCanvasFrame,
2399 canvasCbSaveState);
2400
2401 nsFrameConstructorSaveState docElementCbSaveState;
2402 if (mCanvasFrame != mDocElementContainingBlock) {
2403 mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2404 state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2405 mDocElementContainingBlock,
2406 docElementCbSaveState);
2407 }
2408
2409 // The rules from CSS 2.1, section 9.2.4, have already been applied
2410 // by the style system, so we can assume that display->mDisplay is
2411 // either NONE, BLOCK, or TABLE.
2412
2413 // contentFrame is the primary frame for the root element. frameList contains
2414 // the children of the initial containing block.
2415 //
2416 // The first of those frames is usually `contentFrame`, but it can be
2417 // different, in particular if the root frame is positioned, in which case
2418 // contentFrame is the out-of-flow frame and frameList.FirstChild() is the
2419 // placeholder.
2420 //
2421 // The rest of the frames in frameList are the anonymous content of the canvas
2422 // frame.
2423 nsContainerFrame* contentFrame;
2424 nsFrameList frameList;
2425 bool processChildren = false;
2426
2427 nsFrameConstructorSaveState absoluteSaveState;
2428
2429 if (aDocElement->IsSVGElement()) {
2430 if (!aDocElement->IsSVGElement(nsGkAtoms::svg)) {
2431 return nullptr;
2432 }
2433 // We're going to call the right function ourselves, so no need to give a
2434 // function to this FrameConstructionData.
2435
2436 // XXXbz on the other hand, if we converted this whole function to
2437 // FrameConstructionData/Item, then we'd need the right function
2438 // here... but would probably be able to get away with less code in this
2439 // function in general.
2440 static constexpr FrameConstructionData rootSVGData;
2441 AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
2442 do_AddRef(computedStyle), true);
2443
2444 contentFrame = static_cast<nsContainerFrame*>(ConstructOuterSVG(
2445 state, item, mDocElementContainingBlock, display, frameList));
2446 } else if (display->mDisplay == StyleDisplay::Flex ||
2447 display->mDisplay == StyleDisplay::WebkitBox ||
2448 display->mDisplay == StyleDisplay::Grid) {
2449 auto func = [&] {
2450 if (display->mDisplay == StyleDisplay::Grid) {
2451 return NS_NewGridContainerFrame;
2452 }
2453 return NS_NewFlexContainerFrame;
2454 }();
2455 contentFrame = func(mPresShell, computedStyle);
2456 InitAndRestoreFrame(
2457 state, aDocElement,
2458 state.GetGeometricParent(*display, mDocElementContainingBlock),
2459 contentFrame);
2460 state.AddChild(contentFrame, frameList, aDocElement,
2461 mDocElementContainingBlock);
2462 processChildren = true;
2463
2464 contentFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2465 if (contentFrame->IsAbsPosContainingBlock()) {
2466 state.PushAbsoluteContainingBlock(contentFrame, contentFrame,
2467 absoluteSaveState);
2468 }
2469 } else if (display->mDisplay == StyleDisplay::Table) {
2470 // We're going to call the right function ourselves, so no need to give a
2471 // function to this FrameConstructionData.
2472
2473 // XXXbz on the other hand, if we converted this whole function to
2474 // FrameConstructionData/Item, then we'd need the right function
2475 // here... but would probably be able to get away with less code in this
2476 // function in general.
2477 static constexpr FrameConstructionData rootTableData;
2478 AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
2479 do_AddRef(computedStyle), true);
2480
2481 // if the document is a table then just populate it.
2482 contentFrame = static_cast<nsContainerFrame*>(ConstructTable(
2483 state, item, mDocElementContainingBlock, display, frameList));
2484 } else if (display->DisplayInside() == StyleDisplayInside::Ruby) {
2485 static constexpr FrameConstructionData data(
2486 &nsCSSFrameConstructor::ConstructBlockRubyFrame);
2487 AutoFrameConstructionItem item(this, &data, aDocElement,
2488 do_AddRef(computedStyle), true);
2489 contentFrame = static_cast<nsContainerFrame*>(ConstructBlockRubyFrame(
2490 state, item,
2491 state.GetGeometricParent(*display, mDocElementContainingBlock), display,
2492 frameList));
2493 } else {
2494 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"
, 2496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2496); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2495 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"
, 2496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2496); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2496 "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"
, 2496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot"
") (" "Unhandled display type for root element" ")"); do { MOZ_CrashSequence
(__null, 2496); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2497 contentFrame = NS_NewBlockFrame(mPresShell, computedStyle);
2498 ConstructBlock(
2499 state, aDocElement,
2500 state.GetGeometricParent(*display, mDocElementContainingBlock),
2501 mDocElementContainingBlock, computedStyle, &contentFrame, frameList,
2502 contentFrame->IsAbsPosContainingBlock() ? contentFrame : nullptr);
2503 }
2504
2505 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", 2505); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "frameList.FirstChild()" ")"); do { MOZ_CrashSequence
(__null, 2505); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2506 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"
, 2506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameList.FirstChild()->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2506); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2507 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"
, 2507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentFrame"
")"); do { MOZ_CrashSequence(__null, 2507); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2508
2509 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"
, 2511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2511); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2510 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"
, 2511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2511); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2511 "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"
, 2511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "processChildren ? !mRootElementFrame : mRootElementFrame == contentFrame"
") (" "unexpected mRootElementFrame" ")"); do { MOZ_CrashSequence
(__null, 2511); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2512 if (processChildren) {
2513 mRootElementFrame = contentFrame;
2514 }
2515
2516 // Figure out which frame has the main style for the document element,
2517 // assigning it to mRootElementStyleFrame.
2518 // Backgrounds should be propagated from that frame to the viewport.
2519 contentFrame->GetParentComputedStyle(&mRootElementStyleFrame);
2520 bool isChild = mRootElementStyleFrame &&
2521 mRootElementStyleFrame->GetParent() == contentFrame;
2522 if (!isChild) {
2523 mRootElementStyleFrame = mRootElementFrame;
2524 }
2525
2526 if (processChildren) {
2527 // Still need to process the child content
2528 nsFrameList childList;
2529
2530 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", 2532); MOZ_PretendNoReturn
(); } } while (0)
2531 !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", 2532); MOZ_PretendNoReturn
(); } } while (0)
2532 "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", 2532); MOZ_PretendNoReturn
(); } } while (0)
;
2533
2534 nsFrameConstructorSaveState floatSaveState;
2535 state.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
2536
2537 ProcessChildren(state, aDocElement, computedStyle, contentFrame, true,
2538 childList, false);
2539
2540 // Set the initial child lists
2541 contentFrame->SetInitialChildList(FrameChildListID::Principal,
2542 std::move(childList));
2543 }
2544
2545 nsIFrame* newFrame = frameList.FirstChild();
2546 // set the primary frame
2547 aDocElement->SetPrimaryFrame(contentFrame);
2548 mDocElementContainingBlock->AppendFrames(FrameChildListID::Principal,
2549 std::move(frameList));
2550
2551 // NOTE(emilio): This is in the reverse order compared to normal anonymous
2552 // children. We usually generate anonymous kids first, then non-anonymous,
2553 // but we generate the doc element frame the other way around. This is fine
2554 // either way, but generating anonymous children in a different order requires
2555 // changing nsCanvasFrame (and a whole lot of other potentially unknown code)
2556 // to look at the last child to find the root frame rather than the first
2557 // child.
2558 ConstructAnonymousContentForRoot(state, mCanvasFrame,
2559 mRootElementFrame->GetContent(), frameList);
2560 mCanvasFrame->AppendFrames(FrameChildListID::Principal, std::move(frameList));
2561
2562 return newFrame;
2563}
2564
2565RestyleManager* nsCSSFrameConstructor::RestyleManager() const {
2566 return mPresShell->GetPresContext()->RestyleManager();
2567}
2568
2569ViewportFrame* nsCSSFrameConstructor::ConstructRootFrame() {
2570 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ConstructRootFrame",mozilla::AutoProfilerLabelHot raiiObject2571( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
2571 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject2571( "nsCSSFrameConstructor::ConstructRootFrame"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
2572 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
2573
2574 ServoStyleSet* styleSet = mPresShell->StyleSet();
2575
2576 // --------- BUILD VIEWPORT -----------
2577 RefPtr<ComputedStyle> viewportPseudoStyle =
2578 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2579 PseudoStyleType::MozViewport);
2580 ViewportFrame* viewportFrame =
2581 NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2582
2583 // XXXbz do we _have_ to pass a null content pointer to that frame?
2584 // Would it really kill us to pass in the root element or something?
2585 // What would that break?
2586 viewportFrame->Init(nullptr, nullptr, nullptr);
2587
2588 viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2589
2590 mPresShell->SetNeedsWindowPropertiesSync();
2591
2592 // Make it an absolute container for fixed-pos elements
2593 viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2594 viewportFrame->MarkAsAbsoluteContainingBlock();
2595
2596 return viewportFrame;
2597}
2598
2599void nsCSSFrameConstructor::SetUpDocElementContainingBlock(
2600 nsIContent* aDocElement) {
2601 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"
, 2601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement"
") (" "No element?" ")"); do { MOZ_CrashSequence(__null, 2601
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2602 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"
, 2602); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aDocElement->GetParent()"
") (" "Not root content?" ")"); do { MOZ_CrashSequence(__null
, 2602); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2603 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", 2603
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()"
") (" "Not in a document?" ")"); do { MOZ_CrashSequence(__null
, 2603); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2604 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"
, 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2605); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2605 "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"
, 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocElement->GetUncomposedDoc()->GetRootElement() == aDocElement"
") (" "Not the root of the document?" ")"); do { MOZ_CrashSequence
(__null, 2605); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2606
2607 /*
2608 how the root frame hierarchy should look
2609
2610 Galley presentation, with scrolling:
2611
2612 ViewportFrame [fixed-cb]
2613 ScrollContainerFrame (if needed)
2614 nsCanvasFrame [abs-cb]
2615 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2616 nsTableWrapperFrame, nsPlaceholderFrame,
2617 nsFlexContainerFrame, nsGridContainerFrame)
2618
2619 Print presentation, non-XUL
2620
2621 ViewportFrame
2622 nsCanvasFrame
2623 nsPageSequenceFrame
2624 PrintedSheetFrame
2625 nsPageFrame
2626 nsPageContentFrame [fixed-cb]
2627 nsCanvasFrame [abs-cb]
2628 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2629 nsTableWrapperFrame, nsPlaceholderFrame,
2630 nsFlexContainerFrame,
2631 nsGridContainerFrame)
2632
2633 Print-preview presentation, non-XUL
2634
2635 ViewportFrame
2636 ScrollContainerFrame
2637 nsCanvasFrame
2638 nsPageSequenceFrame
2639 PrintedSheetFrame
2640 nsPageFrame
2641 nsPageContentFrame [fixed-cb]
2642 nsCanvasFrame [abs-cb]
2643 root element frame (nsBlockFrame, SVGOuterSVGFrame,
2644 nsTableWrapperFrame,
2645 nsPlaceholderFrame,
2646 nsFlexContainerFrame,
2647 nsGridContainerFrame)
2648
2649 Print/print preview of XUL is not supported.
2650 [fixed-cb]: the default containing block for fixed-pos content
2651 [abs-cb]: the default containing block for abs-pos content
2652
2653 Meaning of nsCSSFrameConstructor fields:
2654 mRootElementFrame is "root element frame". This is the primary frame for
2655 the root element.
2656 mDocElementContainingBlock is the parent of mRootElementFrame
2657 (i.e. nsCanvasFrame)
2658 mPageSequenceFrame is the nsPageSequenceFrame, or null if there isn't
2659 one
2660 */
2661
2662 // --------- CREATE ROOT FRAME -------
2663
2664 // Create the root frame. The document element's frame is a child of the
2665 // root frame.
2666 //
2667 // The root frame serves two purposes:
2668 // - reserves space for any margins needed for the document element's frame
2669 // - renders the document element's background. This ensures the background
2670 // covers the entire canvas as specified by the CSS2 spec
2671
2672 nsPresContext* presContext = mPresShell->GetPresContext();
2673 const bool isPaginated = presContext->IsRootPaginatedDocument();
2674
2675 const bool isHTML = aDocElement->IsHTMLElement();
2676 const bool isXUL = !isHTML && aDocElement->IsXULElement();
2677
2678 const bool isScrollable = [&] {
2679 if (isPaginated) {
2680 return presContext->HasPaginatedScrolling();
2681 }
2682 // Never create scrollbars for XUL documents or top level XHTML documents
2683 // that disable scrolling.
2684 if (isXUL) {
2685 return false;
2686 }
2687 if (aDocElement->OwnerDoc()->ChromeRulesEnabled() &&
2688 aDocElement->AsElement()->AttrValueIs(
2689 kNameSpaceID_None, nsGkAtoms::scrolling, nsGkAtoms::_false,
2690 eCaseMatters)) {
2691 return false;
2692 }
2693 return true;
2694 }();
2695
2696 nsContainerFrame* viewportFrame =
2697 static_cast<nsContainerFrame*>(GetRootFrame());
2698 ComputedStyle* viewportPseudoStyle = viewportFrame->Style();
2699
2700 nsCanvasFrame* rootCanvasFrame =
2701 NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2702 mCanvasFrame = rootCanvasFrame;
2703 mDocElementContainingBlock = rootCanvasFrame;
2704
2705 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2706
2707 // If the device supports scrolling (e.g., in galley mode on the screen and
2708 // for print-preview, but not when printing), then create a scroll frame that
2709 // will act as the scrolling mechanism for the viewport.
2710 // XXX Do we even need a viewport when printing to a printer?
2711
2712 // We no longer need to do overflow propagation here. It's taken care of
2713 // when we construct frames for the element whose overflow might be
2714 // propagated
2715 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", 2716); MOZ_PretendNoReturn
(); } } while (0)
2716 "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", 2716); MOZ_PretendNoReturn
(); } } while (0)
;
2717
2718 nsContainerFrame* newFrame = rootCanvasFrame;
2719 RefPtr<ComputedStyle> rootPseudoStyle;
2720 // we must create a state because if the scrollbars are GFX it needs the
2721 // state to build the scrollbar frames.
2722 nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
2723
2724 // Start off with the viewport as parent; we'll adjust it as needed.
2725 nsContainerFrame* parentFrame = viewportFrame;
2726
2727 ServoStyleSet* styleSet = mPresShell->StyleSet();
2728 // If paginated, make sure we don't put scrollbars in
2729 if (!isScrollable) {
2730 rootPseudoStyle = styleSet->ResolveNonInheritingAnonymousBoxStyle(
2731 PseudoStyleType::MozCanvas);
2732 } else {
2733 // Build the frame. We give it the content we are wrapping which is the
2734 // document element, the root frame, the parent view port frame, and we
2735 // should get back the new frame and the scrollable view if one was
2736 // created.
2737
2738 // Resolve a style for the scrollframe
2739 RefPtr<ComputedStyle> computedStyle =
2740 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2741 PseudoStyleType::MozViewportScroll);
2742
2743 newFrame = nullptr;
2744 rootPseudoStyle = BeginBuildingScrollContainerFrame(
2745 state, aDocElement, computedStyle, viewportFrame, true, newFrame);
2746 parentFrame = newFrame;
2747 }
2748
2749 rootCanvasFrame->SetComputedStyleWithoutNotification(rootPseudoStyle);
2750 rootCanvasFrame->Init(aDocElement, parentFrame, nullptr);
2751
2752 if (isScrollable) {
2753 FinishBuildingScrollContainerFrame(parentFrame, rootCanvasFrame);
2754 }
2755
2756 if (isPaginated) {
2757 // Create a page sequence frame
2758 {
2759 RefPtr<ComputedStyle> pageSequenceStyle =
2760 styleSet->ResolveInheritingAnonymousBoxStyle(
2761 PseudoStyleType::MozPageSequence, viewportPseudoStyle);
2762 mPageSequenceFrame =
2763 NS_NewPageSequenceFrame(mPresShell, pageSequenceStyle);
2764 mPageSequenceFrame->Init(aDocElement, rootCanvasFrame, nullptr);
2765 SetInitialSingleChild(rootCanvasFrame, mPageSequenceFrame);
2766 }
2767
2768 // Create the first printed sheet frame, as the sole child (for now) of our
2769 // page sequence frame (mPageSequenceFrame).
2770 auto* printedSheetFrame =
2771 ConstructPrintedSheetFrame(mPresShell, mPageSequenceFrame, nullptr);
2772 SetInitialSingleChild(mPageSequenceFrame, printedSheetFrame);
2773
2774 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", 2775
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2775); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2775 "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", 2775
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNextPageContentFramePageName"
") (" "Next page name should not have been set." ")"); do { MOZ_CrashSequence
(__null, 2775); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2776
2777 // Create the first page, as the sole child (for now) of the printed sheet
2778 // frame that we just created.
2779 nsCanvasFrame* canvasFrame;
2780 nsContainerFrame* pageFrame =
2781 ConstructPageFrame(mPresShell, printedSheetFrame, nullptr, canvasFrame);
2782 pageFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
2783 SetInitialSingleChild(printedSheetFrame, pageFrame);
2784
2785 // The eventual parent of the document element frame.
2786 // XXX should this be set for every new page (in ConstructPageFrame)?
2787 mDocElementContainingBlock = canvasFrame;
2788 }
2789
2790 if (viewportFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
2791 SetInitialSingleChild(viewportFrame, newFrame);
2792 } else {
2793 viewportFrame->AppendFrames(FrameChildListID::Principal,
2794 nsFrameList(newFrame, newFrame));
2795 }
2796}
2797
2798void nsCSSFrameConstructor::ConstructAnonymousContentForRoot(
2799 nsFrameConstructorState& aState, nsContainerFrame* aCanvasFrame,
2800 nsIContent* aDocElement, nsFrameList& aFrameList) {
2801 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", 2801); MOZ_PretendNoReturn
(); } } while (0)
;
2802 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", 2802); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mRootElementFrame->GetContent() == aDocElement"
")"); do { MOZ_CrashSequence(__null, 2802); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2803
2804 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
2805 GetAnonymousContent(aDocElement, aCanvasFrame, anonymousItems);
2806
2807 // If we get here, we are rebuilding the anonymous content of the root
2808 // element. In this case, we also need to deal with the custom content
2809 // container.
2810 if (auto* container =
2811 aState.mPresContext->Document()->GetCustomContentContainer()) {
2812 // FIXME(emilio, bug 1852735): This is only needed because of the sync frame
2813 // construction from PresShell::Initialize. See the similar code-path in
2814 // ConstructDocElementFrame.
2815 if (!container->HasServoData()) {
2816 mPresShell->StyleSet()->StyleNewSubtree(container);
2817 }
2818 anonymousItems.AppendElement(container);
2819 }
2820
2821 if (anonymousItems.IsEmpty()) {
2822 return;
2823 }
2824
2825 AutoFrameConstructionItemList itemsToConstruct(this);
2826 AutoFrameConstructionPageName pageNameTracker(aState, aCanvasFrame);
2827 AddFCItemsForAnonymousContent(aState, aCanvasFrame, anonymousItems,
2828 itemsToConstruct, pageNameTracker);
2829 ConstructFramesFromItemList(aState, itemsToConstruct, aCanvasFrame,
2830 /* aParentIsWrapperAnonBox = */ false,
2831 aFrameList);
2832}
2833
2834PrintedSheetFrame* nsCSSFrameConstructor::ConstructPrintedSheetFrame(
2835 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2836 nsIFrame* aPrevSheetFrame) {
2837 RefPtr<ComputedStyle> printedSheetPseudoStyle =
2838 aPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
2839 PseudoStyleType::MozPrintedSheet);
2840
2841 auto* printedSheetFrame =
2842 NS_NewPrintedSheetFrame(aPresShell, printedSheetPseudoStyle);
2843
2844 printedSheetFrame->Init(nullptr, aParentFrame, aPrevSheetFrame);
2845
2846 return printedSheetFrame;
2847}
2848
2849nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
2850 PresShell* aPresShell, nsContainerFrame* aParentFrame,
2851 nsIFrame* aPrevPageFrame, nsCanvasFrame*& aCanvasFrame) {
2852 ServoStyleSet* styleSet = aPresShell->StyleSet();
2853
2854 RefPtr<ComputedStyle> pagePseudoStyle =
2855 styleSet->ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::MozPage);
2856
2857 nsContainerFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2858
2859 // Initialize the page frame and force it to have a view. This makes printing
2860 // of the pages easier and faster.
2861 pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame);
2862
2863 RefPtr<const nsAtom> pageName;
2864 if (mNextPageContentFramePageName) {
2865 pageName = mNextPageContentFramePageName.forget();
2866 } else if (aPrevPageFrame) {
2867 pageName = aPrevPageFrame->ComputePageValue();
2868 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", 2869
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2869 "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", 2869
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageName" ") (" "Page name from prev-in-flow should not have been null"
")"); do { MOZ_CrashSequence(__null, 2869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2870 }
2871 RefPtr<ComputedStyle> pageContentPseudoStyle =
2872 styleSet->ResolvePageContentStyle(pageName,
2873 StylePagePseudoClassFlags::NONE);
2874
2875 nsContainerFrame* pageContentFrame = NS_NewPageContentFrame(
2876 aPresShell, pageContentPseudoStyle, pageName.forget());
2877
2878 nsPageContentFrame* prevPageContentFrame = nullptr;
2879 if (aPrevPageFrame) {
2880 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"
, 2880); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevPageFrame->IsPageFrame()"
")"); do { MOZ_CrashSequence(__null, 2880); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2881 prevPageContentFrame =
2882 static_cast<nsPageFrame*>(aPrevPageFrame)->PageContentFrame();
2883 }
2884 pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame);
2885 if (!prevPageContentFrame) {
2886 // The canvas is an inheriting anon box, so needs to be "owned" by the page
2887 // content.
2888 pageContentFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES |
2889 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
2890 // Make it an absolute container for fixed-pos elements
2891 pageContentFrame->MarkAsAbsoluteContainingBlock();
2892 } else {
2893 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"
, 2896); 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, 2896
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2894 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"
, 2896); 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, 2896
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2895 "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"
, 2896); 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, 2896
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2896 "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"
, 2896); 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, 2896
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2897 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"
, 2899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2899
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2898 "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"
, 2899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2899
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2899 "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"
, 2899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pageContentFrame->GetAbsoluteContainingBlock()"
") (" "nsIFrame::Init() should've constructed AbsoluteContainingBlock "
"for continuations!" ")"); do { MOZ_CrashSequence(__null, 2899
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2900 }
2901 SetInitialSingleChild(pageFrame, pageContentFrame);
2902
2903 RefPtr<ComputedStyle> canvasPseudoStyle =
2904 styleSet->ResolveNonInheritingAnonymousBoxStyle(
2905 PseudoStyleType::MozCanvas);
2906 aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2907
2908 nsIFrame* prevCanvasFrame = nullptr;
2909 if (prevPageContentFrame) {
2910 prevCanvasFrame = prevPageContentFrame->PrincipalChildList().FirstChild();
2911 NS_ASSERTION(prevCanvasFrame, "missing canvas frame")do { if (!(prevCanvasFrame)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "missing canvas frame", "prevCanvasFrame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 2911); MOZ_PretendNoReturn(); } } while (0)
;
2912 }
2913 aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame);
2914 SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2915 return pageFrame;
2916}
2917
2918/* static */
2919nsIFrame* nsCSSFrameConstructor::CreatePlaceholderFrameFor(
2920 PresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame,
2921 nsContainerFrame* aParentFrame, nsIFrame* aPrevInFlow,
2922 nsFrameState aTypeBit) {
2923 RefPtr<ComputedStyle> placeholderStyle =
2924 aPresShell->StyleSet()->ResolveStyleForPlaceholder();
2925
2926 // The placeholder frame gets a pseudo style.
2927 nsPlaceholderFrame* placeholderFrame =
2928 NS_NewPlaceholderFrame(aPresShell, placeholderStyle, aTypeBit);
2929
2930 placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2931
2932 // Associate the placeholder/out-of-flow with each other.
2933 placeholderFrame->SetOutOfFlowFrame(aFrame);
2934 aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
2935
2936 aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2937
2938 return placeholderFrame;
2939}
2940
2941// Clears any lazy bits set in the range [aStartContent, aEndContent). If
2942// aEndContent is null, that means to clear bits in all siblings starting with
2943// aStartContent. aStartContent must not be null unless aEndContent is also
2944// null. We do this so that when new children are inserted under elements whose
2945// frame is a leaf the new children don't cause us to try to construct frames
2946// for the existing children again.
2947static inline void ClearLazyBits(nsIContent* aStartContent,
2948 nsIContent* aEndContent) {
2949 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", 2950
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2950); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2950 "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", 2950
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent || !aEndContent"
") (" "Must have start child if we have an end child" ")"); do
{ MOZ_CrashSequence(__null, 2950); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2951
2952 for (nsIContent* cur = aStartContent; cur != aEndContent;
2953 cur = cur->GetNextSibling()) {
2954 cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2955 }
2956}
2957
2958/* static */
2959const nsCSSFrameConstructor::FrameConstructionData*
2960nsCSSFrameConstructor::FindSelectData(const Element& aElement,
2961 ComputedStyle& aStyle) {
2962 // Construct a frame-based listbox or combobox
2963 const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
2964 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"
, 2964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sel" ")"); do
{ MOZ_CrashSequence(__null, 2964); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2965 switch (aStyle.StyleDisplay()->EffectiveAppearance()) {
2966 case StyleAppearance::Base:
2967 case StyleAppearance::BaseSelect:
2968 return nullptr;
2969 default:
2970 break;
2971 }
2972 if (sel->IsCombobox()) {
2973 static constexpr FrameConstructionData sComboboxData{
2974 ToCreationFunc(NS_NewComboboxControlFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewComboboxControlFrame(aPs, aStyle); }
};
2975 return &sComboboxData;
2976 }
2977 // FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
2978 // and reuse ConstructScrollableBlock or so?
2979 static constexpr FrameConstructionData sListBoxData{
2980 &nsCSSFrameConstructor::ConstructListBoxSelectFrame};
2981 return &sListBoxData;
2982}
2983
2984nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
2985 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
2986 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
2987 nsFrameList& aFrameList) {
2988 nsContainerFrame* listFrame =
2989 NS_NewListControlFrame(mPresShell, aItem.mComputedStyle);
2990 InitAndRestoreFrame(aState, aItem.mContent,
2991 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
2992 listFrame);
2993 ConstructScrollableBlockWithScrollContainer(
2994 aState, aItem, aParentFrame, aStyleDisplay, aFrameList, listFrame);
2995 return listFrame;
2996}
2997
2998nsIFrame* nsCSSFrameConstructor::ConstructTextControl(
2999 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3000 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3001 nsFrameList& aFrameList) {
3002 nsContainerFrame* tcf =
3003 NS_NewTextControlFrame(mPresShell, aItem.mComputedStyle);
3004 InitAndRestoreFrame(aState, aItem.mContent,
3005 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3006 tcf);
3007 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
3008 aStyleDisplay, aFrameList, tcf);
3009 return tcf;
3010}
3011
3012nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
3013 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3014 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3015 nsFrameList& aFrameList) {
3016 AutoRestore<bool> savedHasRenderedLegend(aState.mHasRenderedLegend);
3017 aState.mHasRenderedLegend = false;
3018 nsIContent* const content = aItem.mContent;
3019 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3020
3021 nsContainerFrame* fieldsetFrame =
3022 NS_NewFieldSetFrame(mPresShell, computedStyle);
3023
3024 // Initialize it
3025 InitAndRestoreFrame(aState, content,
3026 aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
3027 fieldsetFrame);
3028
3029 fieldsetFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3030
3031 // Resolve style and initialize the frame
3032 RefPtr<ComputedStyle> fieldsetContentStyle =
3033 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3034 PseudoStyleType::MozFieldsetContent, computedStyle);
3035
3036 const nsStyleDisplay* fieldsetContentDisplay =
3037 fieldsetContentStyle->StyleDisplay();
3038 const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
3039 nsContainerFrame* scrollFrame = nullptr;
3040 if (isScrollable) {
3041 fieldsetContentStyle =
3042 BeginBuildingScrollContainerFrame(aState, content, fieldsetContentStyle,
3043 fieldsetFrame, false, scrollFrame);
3044 }
3045
3046 // Create the inner ::-moz-fieldset-content frame.
3047 nsContainerFrame* contentFrameTop;
3048 nsContainerFrame* contentFrame;
3049 auto* parent = scrollFrame ? scrollFrame : fieldsetFrame;
3050 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", 3051); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3051); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3051 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", 3051); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->DisplayOutside() == StyleDisplayOutside::Block"
")"); do { MOZ_CrashSequence(__null, 3051); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3052 switch (fieldsetContentDisplay->DisplayInside()) {
3053 case StyleDisplayInside::Flex:
3054 contentFrame = NS_NewFlexContainerFrame(mPresShell, fieldsetContentStyle);
3055 InitAndRestoreFrame(aState, content, parent, contentFrame);
3056 contentFrameTop = contentFrame;
3057 break;
3058 case StyleDisplayInside::Grid:
3059 contentFrame = NS_NewGridContainerFrame(mPresShell, fieldsetContentStyle);
3060 InitAndRestoreFrame(aState, content, parent, contentFrame);
3061 contentFrameTop = contentFrame;
3062 break;
3063 default: {
3064 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", 3065); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3065); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3065 "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", 3065); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "fieldsetContentDisplay->mDisplay == StyleDisplay::Block"
") (" "bug in StyleAdjuster::adjust_for_fieldset_content?" ")"
); do { MOZ_CrashSequence(__null, 3065); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3066
3067 contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle);
3068 if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) {
3069 contentFrameTop = BeginBuildingColumns(
3070 aState, content, parent, contentFrame, fieldsetContentStyle);
3071 } else {
3072 // No need to create column container. Initialize content frame.
3073 InitAndRestoreFrame(aState, content, parent, contentFrame);
3074 contentFrameTop = contentFrame;
3075 }
3076
3077 break;
3078 }
3079 }
3080
3081 aState.AddChild(fieldsetFrame, aFrameList, content, aParentFrame);
3082
3083 // Process children
3084 nsFrameConstructorSaveState absoluteSaveState;
3085 nsFrameList childList;
3086
3087 contentFrameTop->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3088 if (fieldsetFrame->IsAbsPosContainingBlock()) {
3089 aState.PushAbsoluteContainingBlock(contentFrameTop, fieldsetFrame,
3090 absoluteSaveState);
3091 }
3092
3093 nsFrameConstructorSaveState floatSaveState;
3094 aState.MaybePushFloatContainingBlock(contentFrame, floatSaveState);
3095
3096 ProcessChildren(aState, content, computedStyle, contentFrame, true, childList,
3097 true);
3098 nsFrameList fieldsetKids;
3099 fieldsetKids.AppendFrame(nullptr,
3100 scrollFrame ? scrollFrame : contentFrameTop);
3101
3102 if (!MayNeedToCreateColumnSpanSiblings(contentFrame, childList)) {
3103 // Set the inner frame's initial child lists.
3104 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3105 std::move(childList));
3106 } else {
3107 // Extract any initial non-column-span kids, and put them in inner frame's
3108 // child list.
3109 nsFrameList initialNonColumnSpanKids =
3110 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
3111 contentFrame->SetInitialChildList(FrameChildListID::Principal,
3112 std::move(initialNonColumnSpanKids));
3113
3114 if (childList.NotEmpty()) {
3115 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
3116 aState, contentFrame, childList,
3117 // Column content should never be a absolute/fixed positioned
3118 // containing block. Pass nullptr as aPositionedFrame.
3119 nullptr);
3120 FinishBuildingColumns(aState, contentFrameTop, contentFrame,
3121 columnSpanSiblings);
3122 }
3123 }
3124
3125 if (isScrollable) {
3126 FinishBuildingScrollContainerFrame(scrollFrame, contentFrameTop);
3127 }
3128
3129 // We use AppendFrames here because the rendered legend will already
3130 // be present in the principal child list if it exists.
3131 fieldsetFrame->AppendFrames(FrameChildListID::NoReflowPrincipal,
3132 std::move(fieldsetKids));
3133
3134 return fieldsetFrame;
3135}
3136
3137const nsCSSFrameConstructor::FrameConstructionData*
3138nsCSSFrameConstructor::FindDetailsData(const Element& aElement,
3139 ComputedStyle& aStyle) {
3140 if (!StaticPrefs::layout_details_force_block_layout()) {
3141 return nullptr;
3142 }
3143 static constexpr FrameConstructionData sBlockData[2] = {
3144 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3145 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3146 };
3147 return &sBlockData[aStyle.StyleDisplay()->IsScrollableOverflow()];
3148}
3149
3150nsIFrame* nsCSSFrameConstructor::ConstructBlockRubyFrame(
3151 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
3152 nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
3153 nsFrameList& aFrameList) {
3154 nsIContent* const content = aItem.mContent;
3155 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3156
3157 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, computedStyle);
3158 nsContainerFrame* newFrame = blockFrame;
3159 nsContainerFrame* geometricParent =
3160 aState.GetGeometricParent(*aStyleDisplay, aParentFrame);
3161 AutoFrameConstructionPageName pageNameTracker(aState, blockFrame);
3162 if ((aItem.mFCData->mBits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3163 aStyleDisplay->IsScrollableOverflow()) {
3164 nsContainerFrame* scrollframe = nullptr;
3165 BuildScrollContainerFrame(aState, content, computedStyle, blockFrame,
3166 geometricParent, scrollframe);
3167 newFrame = scrollframe;
3168 } else {
3169 InitAndRestoreFrame(aState, content, geometricParent, blockFrame);
3170 }
3171
3172 RefPtr<ComputedStyle> rubyStyle =
3173 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3174 PseudoStyleType::MozBlockRubyContent, computedStyle);
3175 nsContainerFrame* rubyFrame = NS_NewRubyFrame(mPresShell, rubyStyle);
3176 InitAndRestoreFrame(aState, content, blockFrame, rubyFrame);
3177 SetInitialSingleChild(blockFrame, rubyFrame);
3178 blockFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3179
3180 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
3181
3182 if (!mRootElementFrame) {
3183 mRootElementFrame = newFrame;
3184 }
3185
3186 nsFrameConstructorSaveState absoluteSaveState;
3187 blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3188 if (newFrame->IsAbsPosContainingBlock()) {
3189 aState.PushAbsoluteContainingBlock(blockFrame, blockFrame,
3190 absoluteSaveState);
3191 }
3192 nsFrameConstructorSaveState floatSaveState;
3193 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
3194
3195 nsFrameList childList;
3196 ProcessChildren(aState, content, rubyStyle, rubyFrame, true, childList, false,
3197 nullptr);
3198 rubyFrame->SetInitialChildList(FrameChildListID::Principal,
3199 std::move(childList));
3200
3201 return newFrame;
3202}
3203
3204static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) {
3205 for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3206 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"
, 3207); MOZ_PretendNoReturn(); } } while (0)
3207 "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"
, 3207); MOZ_PretendNoReturn(); } } while (0)
;
3208 auto pseudo = f->Style()->GetPseudoType();
3209 if (pseudo == PseudoStyleType::Before || pseudo == PseudoStyleType::After ||
3210 pseudo == PseudoStyleType::Marker ||
3211 pseudo == PseudoStyleType::Backdrop ||
3212 pseudo == PseudoStyleType::Checkmark ||
3213 pseudo == PseudoStyleType::PickerIcon) {
3214 return f;
3215 }
3216 }
3217 return nullptr;
3218}
3219
3220/* static */
3221const nsCSSFrameConstructor::FrameConstructionData*
3222nsCSSFrameConstructor::FindTextData(const Text& aTextContent,
3223 nsIFrame* aParentFrame) {
3224 if (aParentFrame && IsFrameForSVG(aParentFrame)) {
3225 if (!aParentFrame->IsInSVGTextSubtree()) {
3226 return nullptr;
3227 }
3228
3229 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
3230 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
3231 // really know how to deal with it. This kinda sucks. :(
3232 if (aParentFrame->GetContent() != aTextContent.GetParent()) {
3233 return nullptr;
3234 }
3235
3236 static constexpr FrameConstructionData sSVGTextData(
3237 NS_NewTextFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_SVG_TEXT0x80000);
3238 return &sSVGTextData;
3239 }
3240
3241 static constexpr FrameConstructionData sTextData(NS_NewTextFrame,
3242 FCDATA_IS_LINE_PARTICIPANT0x2000);
3243 return &sTextData;
3244}
3245
3246void nsCSSFrameConstructor::ConstructTextFrame(
3247 const FrameConstructionData* aData, nsFrameConstructorState& aState,
3248 nsIContent* aContent, nsContainerFrame* aParentFrame,
3249 ComputedStyle* aComputedStyle, nsFrameList& aFrameList) {
3250 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", 3250
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aData" ") (" "Must have frame construction data"
")"); do { MOZ_CrashSequence(__null, 3250); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3251
3252 nsIFrame* newFrame =
3253 (*aData->mFunc.mCreationFunc)(mPresShell, aComputedStyle);
3254
3255 InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame);
3256
3257 // We never need to create a view for a text frame.
3258
3259 if (newFrame->IsGeneratedContentFrame()) {
3260 UniquePtr<nsGenConInitializer> initializer(
3261 static_cast<nsGenConInitializer*>(
3262 aContent->TakeProperty(nsGkAtoms::genConInitializerProperty)));
3263 if (initializer) {
3264 if (initializer->mNode.release()->InitTextFrame(
3265 initializer->mList,
3266 FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3267 (this->*(initializer->mDirtyAll))();
3268 }
3269 }
3270 }
3271
3272 // Add the newly constructed frame to the flow
3273 aFrameList.AppendFrame(nullptr, newFrame);
3274
3275 if (!aState.mCreatingExtraFrames || (aContent->IsInNativeAnonymousSubtree() &&
3276 !aContent->GetPrimaryFrame())) {
3277 aContent->SetPrimaryFrame(newFrame);
3278 }
3279}
3280
3281/* static */
3282const nsCSSFrameConstructor::FrameConstructionData*
3283nsCSSFrameConstructor::FindDataByInt(int32_t aInt, const Element& aElement,
3284 ComputedStyle& aComputedStyle,
3285 const FrameConstructionDataByInt* aDataPtr,
3286 uint32_t aDataLength) {
3287 for (const FrameConstructionDataByInt *curData = aDataPtr,
3288 *endData = aDataPtr + aDataLength;
3289 curData != endData; ++curData) {
3290 if (curData->mInt == aInt) {
3291 const FrameConstructionData* data = &curData->mData;
3292 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3293 return data->mFunc.mDataGetter(aElement, aComputedStyle);
3294 }
3295
3296 return data;
3297 }
3298 }
3299
3300 return nullptr;
3301}
3302
3303/* static */
3304const nsCSSFrameConstructor::FrameConstructionData*
3305nsCSSFrameConstructor::FindDataByTag(const Element& aElement,
3306 ComputedStyle& aStyle,
3307 const FrameConstructionDataByTag* aDataPtr,
3308 uint32_t aDataLength) {
3309 const nsAtom* tag = aElement.NodeInfo()->NameAtom();
3310 for (const FrameConstructionDataByTag *curData = aDataPtr,
3311 *endData = aDataPtr + aDataLength;
3312 curData != endData; ++curData) {
3313 if (curData->mTag == tag) {
3314 const FrameConstructionData* data = &curData->mData;
3315 if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER0x2) {
3316 return data->mFunc.mDataGetter(aElement, aStyle);
3317 }
3318
3319 return data;
3320 }
3321 }
3322
3323 return nullptr;
3324}
3325
3326#define SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40) FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME0x40)
3327#define SIMPLE_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3328 {int32_t(_int), FrameConstructionData(_func)}
3329#define SIMPLE_INT_CHAIN(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3330 {int32_t(_int), FrameConstructionData(_func)}
3331#define COMPLEX_INT_CREATE(_int, _func){int32_t(_int), FrameConstructionData(_func)} \
3332 {int32_t(_int), FrameConstructionData(_func)}
3333
3334#define SIMPLE_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3335 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3336#define SIMPLE_TAG_CHAIN(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3337 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3338#define COMPLEX_TAG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData(_func)} \
3339 {nsGkAtoms::_tag, FrameConstructionData(_func)}
3340
3341static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) {
3342 auto pseudo = aFrame->Style()->GetPseudoType();
3343 if (pseudo == PseudoStyleType::MozFieldsetContent ||
3344 pseudo == PseudoStyleType::MozScrolledContent ||
3345 pseudo == PseudoStyleType::MozColumnSet ||
3346 pseudo == PseudoStyleType::MozColumnContent) {
3347 return GetFieldSetFrameFor(aFrame->GetParent());
3348 }
3349 return do_QueryFrame(aFrame);
3350}
3351
3352/* static */
3353const nsCSSFrameConstructor::FrameConstructionData*
3354nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
3355 nsIFrame* aParentFrame,
3356 ComputedStyle& aStyle) {
3357 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", 3357); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsHTMLElement()" ")"); do { MOZ_CrashSequence
(__null, 3357); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3358 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", 3362); MOZ_PretendNoReturn
(); } } while (0)
3359 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", 3362); MOZ_PretendNoReturn
(); } } while (0)
3360 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", 3362); MOZ_PretendNoReturn
(); } } while (0)
3361 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", 3362); MOZ_PretendNoReturn
(); } } while (0)
3362 "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", 3362); MOZ_PretendNoReturn
(); } } while (0)
;
3363
3364 switch (aStyle.GetPseudoType()) {
3365 case PseudoStyleType::ViewTransitionOld:
3366 case PseudoStyleType::ViewTransitionNew: {
3367 static constexpr FrameConstructionData sViewTransitionData(
3368 NS_NewImageFrameForViewTransition);
3369 return &sViewTransitionData;
3370 }
3371 case PseudoStyleType::MozSelectContent: {
3372 if (aParentFrame && aParentFrame->IsComboboxControlFrame()) {
3373 static constexpr FrameConstructionData sComboboxLabelData(
3374 NS_NewComboboxLabelFrame);
3375 return &sComboboxLabelData;
3376 }
3377 break;
3378 }
3379 case PseudoStyleType::MozFileContent: {
3380 if (aParentFrame && aParentFrame->IsFileControlFrame()) {
3381 static constexpr FrameConstructionData sFileLabelData(
3382 NS_NewFileControlLabelFrame);
3383 return &sFileLabelData;
3384 }
3385 break;
3386 }
3387 case PseudoStyleType::MozReveal:
3388 case PseudoStyleType::MozNumberSpinBox: {
3389 if (aParentFrame && aParentFrame->StyleDisplay()->EffectiveAppearance() ==
3390 StyleAppearance::Textfield) {
3391 // Suppress button-box pseudo-elements with appearance: textfield.
3392 static constexpr FrameConstructionData sSuppressData =
3393 SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
3394 return &sSuppressData;
3395 }
3396 break;
3397 }
3398 default:
3399 break;
3400 }
3401
3402 static constexpr FrameConstructionDataByTag sHTMLData[] = {
3403 SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData){nsGkAtoms::img, FrameConstructionData(nsCSSFrameConstructor::
FindImgData)}
,
3404 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,{nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
3405 nsCSSFrameConstructor::FindGeneratedImageData){nsGkAtoms::mozgeneratedcontentimage, FrameConstructionData(nsCSSFrameConstructor
::FindGeneratedImageData)}
,
3406 {nsGkAtoms::br,
3407 {NS_NewBRFrame, FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_IS_LINE_BREAK0x4000}},
3408 SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame){nsGkAtoms::wbr, FrameConstructionData(NS_NewWBRFrame)},
3409 SIMPLE_TAG_CHAIN(button, nsCSSFrameConstructor::FindHTMLButtonData){nsGkAtoms::button, FrameConstructionData(nsCSSFrameConstructor
::FindHTMLButtonData)}
,
3410 SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData){nsGkAtoms::input, FrameConstructionData(nsCSSFrameConstructor
::FindInputData)}
,
3411 SIMPLE_TAG_CREATE(textarea, &nsCSSFrameConstructor::ConstructTextControl){nsGkAtoms::textarea, FrameConstructionData(&nsCSSFrameConstructor
::ConstructTextControl)}
,
3412 SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData){nsGkAtoms::select, FrameConstructionData(nsCSSFrameConstructor
::FindSelectData)}
,
3413 SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::object, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3414 SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData){nsGkAtoms::embed, FrameConstructionData(nsCSSFrameConstructor
::FindObjectData)}
,
3415 COMPLEX_TAG_CREATE(fieldset,{nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
3416 &nsCSSFrameConstructor::ConstructFieldSetFrame){nsGkAtoms::fieldset, FrameConstructionData(&nsCSSFrameConstructor
::ConstructFieldSetFrame)}
,
3417 SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame){nsGkAtoms::frameset, FrameConstructionData(NS_NewHTMLFramesetFrame
)}
,
3418 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3419 SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData){nsGkAtoms::canvas, FrameConstructionData(nsCSSFrameConstructor
::FindCanvasData)}
,
3420 SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame){nsGkAtoms::video, FrameConstructionData(NS_NewHTMLVideoFrame
)}
,
3421 SIMPLE_TAG_CREATE(audio, NS_NewHTMLAudioFrame){nsGkAtoms::audio, FrameConstructionData(NS_NewHTMLAudioFrame
)}
,
3422 SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame){nsGkAtoms::progress, FrameConstructionData(NS_NewProgressFrame
)}
,
3423 SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame){nsGkAtoms::meter, FrameConstructionData(NS_NewMeterFrame)},
3424 SIMPLE_TAG_CHAIN(details, nsCSSFrameConstructor::FindDetailsData){nsGkAtoms::details, FrameConstructionData(nsCSSFrameConstructor
::FindDetailsData)}
,
3425 };
3426
3427 return FindDataByTag(aElement, aStyle, sHTMLData, std::size(sHTMLData));
3428}
3429
3430/* static */
3431const nsCSSFrameConstructor::FrameConstructionData*
3432nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
3433 ComputedStyle&) {
3434 if (!aElement.IsInNativeAnonymousSubtree()) {
3435 return nullptr;
3436 }
3437
3438 auto& generatedContent = static_cast<const GeneratedImageContent&>(aElement);
3439 if (generatedContent.IsForListStyleImageMarker()) {
3440 static constexpr FrameConstructionData sImgData(
3441 NS_NewImageFrameForListStyleImage);
3442 return &sImgData;
3443 }
3444
3445 static constexpr FrameConstructionData sImgData(
3446 NS_NewImageFrameForGeneratedContentIndex);
3447 return &sImgData;
3448}
3449
3450const nsCSSFrameConstructor::FrameConstructionData*
3451nsCSSFrameConstructor::FindHTMLButtonData(const Element&,
3452 ComputedStyle& aStyle) {
3453 // Buttons force a (maybe inline) block unless their display is flex or grid.
3454 // TODO(emilio): It'd be good to remove this restriction more broadly.
3455 // There are some tests that expect block baselines on e.g. a `display: table`
3456 // button, but seems like it would be doable.
3457 const auto* disp = aStyle.StyleDisplay();
3458 const bool respectDisplay = [&] {
3459 if (disp->IsInlineFlow()) {
3460 // For compat, `display: inline` and co need to create an inline-block.
3461 return false;
3462 }
3463 switch (disp->DisplayInside()) {
3464 case StyleDisplayInside::Flex:
3465 case StyleDisplayInside::Grid:
3466 case StyleDisplayInside::FlowRoot:
3467 return true;
3468 default:
3469 return false;
3470 }
3471 }();
3472 if (respectDisplay) {
3473 return nullptr;
3474 }
3475 static constexpr FrameConstructionData sBlockData[2] = {
3476 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
3477 {&nsCSSFrameConstructor::ConstructScrollableBlock},
3478 };
3479 return &sBlockData[disp->IsScrollableOverflow()];
3480}
3481
3482/* static */
3483const nsCSSFrameConstructor::FrameConstructionData*
3484nsCSSFrameConstructor::FindImgData(const Element& aElement,
3485 ComputedStyle& aStyle) {
3486 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3487 nsImageFrame::ImageFrameType::ForElementRequest) {
3488 // content: url gets handled by the generic code-path.
3489 return nullptr;
3490 }
3491
3492 static constexpr FrameConstructionData sImgData(NS_NewImageFrame);
3493 return &sImgData;
3494}
3495
3496/* static */
3497const nsCSSFrameConstructor::FrameConstructionData*
3498nsCSSFrameConstructor::FindImgControlData(const Element& aElement,
3499 ComputedStyle& aStyle) {
3500 if (nsImageFrame::ImageFrameTypeFor(aElement, aStyle) !=
3501 nsImageFrame::ImageFrameType::ForElementRequest) {
3502 return nullptr;
3503 }
3504
3505 static constexpr FrameConstructionData sImgControlData(
3506 NS_NewImageControlFrame);
3507 return &sImgControlData;
3508}
3509
3510/* static */
3511const nsCSSFrameConstructor::FrameConstructionData*
3512nsCSSFrameConstructor::FindInputData(const Element& aElement,
3513 ComputedStyle& aStyle) {
3514 static constexpr FrameConstructionDataByInt sInputData[] = {
3515 SIMPLE_INT_CREATE(FormControlType::InputCheckbox,{int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3516 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputCheckbox), FrameConstructionData
([](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3517 SIMPLE_INT_CREATE(FormControlType::InputRadio,{int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
3518 ToCreationFunc(NS_NewCheckboxRadioFrame)){int32_t(FormControlType::InputRadio), FrameConstructionData(
[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewCheckboxRadioFrame(aPs, aStyle); })}
,
3519 SIMPLE_INT_CREATE(FormControlType::InputFile, NS_NewFileControlFrame){int32_t(FormControlType::InputFile), FrameConstructionData(NS_NewFileControlFrame
)}
,
3520 SIMPLE_INT_CHAIN(FormControlType::InputImage,{int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
3521 nsCSSFrameConstructor::FindImgControlData){int32_t(FormControlType::InputImage), FrameConstructionData(
nsCSSFrameConstructor::FindImgControlData)}
,
3522 SIMPLE_INT_CREATE(FormControlType::InputEmail,{int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3523 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputEmail), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3524 SIMPLE_INT_CREATE(FormControlType::InputText,{int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3525 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputText), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3526 SIMPLE_INT_CREATE(FormControlType::InputTel,{int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3527 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputTel), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3528 SIMPLE_INT_CREATE(FormControlType::InputUrl,{int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3529 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputUrl), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3530 SIMPLE_INT_CREATE(FormControlType::InputRange, NS_NewRangeFrame){int32_t(FormControlType::InputRange), FrameConstructionData(
NS_NewRangeFrame)}
,
3531 SIMPLE_INT_CREATE(FormControlType::InputPassword,{int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3532 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputPassword), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3533 SIMPLE_INT_CREATE(FormControlType::InputColor, NS_NewColorControlFrame){int32_t(FormControlType::InputColor), FrameConstructionData(
NS_NewColorControlFrame)}
,
3534 SIMPLE_INT_CREATE(FormControlType::InputSearch,{int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3535 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputSearch), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3536 SIMPLE_INT_CREATE(FormControlType::InputNumber,{int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
3537 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputNumber), FrameConstructionData
(&nsCSSFrameConstructor::ConstructTextControl)}
,
3538 SIMPLE_INT_CREATE(FormControlType::InputTime, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputTime), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3539 SIMPLE_INT_CREATE(FormControlType::InputDate, NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDate), FrameConstructionData(NS_NewDateTimeControlFrame
)}
,
3540 SIMPLE_INT_CREATE(FormControlType::InputDatetimeLocal,{int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
3541 NS_NewDateTimeControlFrame){int32_t(FormControlType::InputDatetimeLocal), FrameConstructionData
(NS_NewDateTimeControlFrame)}
,
3542 // TODO: this is temporary until a frame is written: bug 888320
3543 SIMPLE_INT_CREATE(FormControlType::InputMonth,{int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
3544 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputMonth), FrameConstructionData(
&nsCSSFrameConstructor::ConstructTextControl)}
,
3545 // TODO: this is temporary until a frame is written: bug 888320
3546 SIMPLE_INT_CREATE(FormControlType::InputWeek,{int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
3547 &nsCSSFrameConstructor::ConstructTextControl){int32_t(FormControlType::InputWeek), FrameConstructionData(&
nsCSSFrameConstructor::ConstructTextControl)}
,
3548 SIMPLE_INT_CREATE(FormControlType::InputSubmit,{int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3549 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputSubmit), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3550 SIMPLE_INT_CREATE(FormControlType::InputReset,{int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
3551 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputReset), FrameConstructionData(
NS_NewInputButtonControlFrame)}
,
3552 SIMPLE_INT_CREATE(FormControlType::InputButton,{int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
3553 NS_NewInputButtonControlFrame){int32_t(FormControlType::InputButton), FrameConstructionData
(NS_NewInputButtonControlFrame)}
,
3554 // Keeping hidden inputs out of here on purpose for so they get frames by
3555 // display (in practice, none).
3556 };
3557
3558 auto controlType = HTMLInputElement::FromNode(aElement)->ControlType();
3559
3560 // radio and checkbox inputs with appearance:none should be constructed
3561 // by display type. (Note that we're not checking that appearance is
3562 // not (respectively) StyleAppearance::Radio and StyleAppearance::Checkbox.)
3563 if ((controlType == FormControlType::InputCheckbox ||
3564 controlType == FormControlType::InputRadio) &&
3565 !aStyle.StyleDisplay()->HasNativeAppearance()) {
3566 return nullptr;
3567 }
3568
3569 return FindDataByInt(int32_t(controlType), aElement, aStyle, sInputData,
3570 std::size(sInputData));
3571}
3572
3573/* static */
3574const nsCSSFrameConstructor::FrameConstructionData*
3575nsCSSFrameConstructor::FindObjectData(const Element& aElement,
3576 ComputedStyle& aStyle) {
3577 uint32_t type;
3578 nsCOMPtr<nsIObjectLoadingContent> objContent =
3579 do_QueryInterface(const_cast<Element*>(&aElement));
3580 NS_ASSERTION(objContent,do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3582); MOZ_PretendNoReturn(); } } while (0)
3581 "embed and object must implement "do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3582); MOZ_PretendNoReturn(); } } while (0)
3582 "nsIObjectLoadingContent!")do { if (!(objContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "embed and object must implement "
"nsIObjectLoadingContent!", "objContent", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 3582); MOZ_PretendNoReturn(); } } while (0)
;
3583 objContent->GetDisplayedType(&type);
3584
3585 static constexpr FrameConstructionDataByInt sObjectData[] = {
3586 // TODO(emilio): Can we remove the NS_NewEmptyFrame case and just use a
3587 // subdocument frame here?
3588 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,{int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
3589 NS_NewEmptyFrame){int32_t(nsIObjectLoadingContent::TYPE_LOADING), FrameConstructionData
(NS_NewEmptyFrame)}
,
3590 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,{int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
3591 NS_NewSubDocumentFrame){int32_t(nsIObjectLoadingContent::TYPE_DOCUMENT), FrameConstructionData
(NS_NewSubDocumentFrame)}
,
3592 // Nothing for TYPE_FALLBACK so we'll construct frames by display there
3593 };
3594
3595 return FindDataByInt((int32_t)type, aElement, aStyle, sObjectData,
3596 std::size(sObjectData));
3597}
3598
3599/* static */
3600const nsCSSFrameConstructor::FrameConstructionData*
3601nsCSSFrameConstructor::FindCanvasData(const Element& aElement,
3602 ComputedStyle& aStyle) {
3603 // We want to check whether script is enabled on the document that
3604 // could be painting to the canvas. That's the owner document of
3605 // the canvas, except when the owner document is a static document,
3606 // in which case it's the original document it was cloned from.
3607 Document* doc = aElement.OwnerDoc();
3608 if (doc->IsStaticDocument()) {
3609 doc = doc->GetOriginalDocument();
3610 }
3611 if (!doc->IsScriptEnabled()) {
3612 return nullptr;
3613 }
3614
3615 static constexpr FrameConstructionData sCanvasData(
3616 NS_NewHTMLCanvasFrame, 0, PseudoStyleType::MozHtmlCanvasContent);
3617 return &sCanvasData;
3618}
3619
3620static MOZ_NEVER_INLINE__attribute__((noinline)) void DestroyFramesInList(PresShell* aPs,
3621 nsFrameList& aList) {
3622 nsIFrame::DestroyContext context(aPs);
3623 aList.DestroyFrames(context);
3624}
3625
3626void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
3627 FrameConstructionItem& aItem, nsFrameConstructorState& aState,
3628 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
3629 const FrameConstructionData* data = aItem.mFCData;
3630 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",
3630); MOZ_PretendNoReturn(); } } while (0)
;
3631
3632 uint32_t bits = data->mBits;
3633
3634 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", 3635); MOZ_PretendNoReturn
(); } } while (0)
3635 "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", 3635); MOZ_PretendNoReturn
(); } } while (0)
;
3636
3637 // Some sets of bits are not compatible with each other
3638#define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3639 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", 3640); MOZ_PretendNoReturn
(); } } while (0)
3640 "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", 3640); MOZ_PretendNoReturn
(); } } while (0)
3641 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3642 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10);
3643 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
3644 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_SKIP_ABSPOS_PUSH0x200);
3645 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3646 FCDATA_DISALLOW_GENERATED_CONTENT0x400);
3647 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4, FCDATA_ALLOW_BLOCK_STYLES0x8000);
3648 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR0x4,
3649 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3650 CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS0x20,
3651 FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000);
3652#undef CHECK_ONLY_ONE_BIT
3653 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", 3655
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3655); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3654 !(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", 3655
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3655); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3655 "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", 3655
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(bits & 0x400000) || (bits & 0x10000)"
") (" "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"
")"); do { MOZ_CrashSequence(__null, 3655); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3656
3657 // Don't create a subdocument frame for iframes if we're creating extra frames
3658 if (aState.mCreatingExtraFrames &&
3659 aItem.mContent->IsHTMLElement(nsGkAtoms::iframe)) {
3660 return;
3661 }
3662
3663 nsIContent* const content = aItem.mContent;
3664 nsIFrame* newFrame;
3665 nsIFrame* primaryFrame;
3666 ComputedStyle* const computedStyle = aItem.mComputedStyle;
3667 const nsStyleDisplay* display = computedStyle->StyleDisplay();
3668 if (bits & FCDATA_FUNC_IS_FULL_CTOR0x4) {
3669 newFrame = (this->*(data->mFunc.mFullConstructor))(
3670 aState, aItem, aParentFrame, display, aFrameList);
3671 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", 3671
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ") (" "Full constructor failed"
")"); do { MOZ_CrashSequence(__null, 3671); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3672 primaryFrame = newFrame;
3673 } else {
3674 newFrame = (*data->mFunc.mCreationFunc)(mPresShell, computedStyle);
3675
3676 const bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8);
3677 nsContainerFrame* geometricParent =
3678 allowOutOfFlow ? aState.GetGeometricParent(*display, aParentFrame)
3679 : aParentFrame;
3680
3681 // In the non-scrollframe case, primaryFrame and newFrame are equal; in the
3682 // scrollframe case, newFrame is the scrolled frame while primaryFrame is
3683 // the scrollframe.
3684 if ((bits & FCDATA_MAY_NEED_SCROLLFRAME0x80) &&
3685 display->IsScrollableOverflow()) {
3686 nsContainerFrame* scrollframe = nullptr;
3687 BuildScrollContainerFrame(aState, content, computedStyle, newFrame,
3688 geometricParent, scrollframe);
3689 primaryFrame = scrollframe;
3690 } else {
3691 InitAndRestoreFrame(aState, content, geometricParent, newFrame);
3692 primaryFrame = newFrame;
3693 }
3694
3695 // If we need to create a block formatting context to wrap our
3696 // kids, do it now.
3697 nsIFrame* maybeAbsoluteContainingBlockStyleFrame = primaryFrame;
3698 nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3699 nsIFrame* possiblyLeafFrame = newFrame;
3700 nsContainerFrame* outerFrame = nullptr;
3701 if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS0x40000) {
3702 RefPtr<ComputedStyle> outerStyle =
3703 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
3704 data->mAnonBoxPseudo, computedStyle);
3705#ifdef DEBUG1
3706 nsContainerFrame* containerFrame = do_QueryFrame(newFrame);
3707 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", 3707); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "containerFrame" ")"); do { MOZ_CrashSequence
(__null, 3707); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3708#endif
3709 nsContainerFrame* container = static_cast<nsContainerFrame*>(newFrame);
3710 nsContainerFrame* innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
3711 InitAndRestoreFrame(aState, content, container, innerFrame);
3712 outerFrame = innerFrame;
3713
3714 SetInitialSingleChild(container, outerFrame);
3715
3716 container->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
3717
3718 // Now figure out whether newFrame or outerFrame should be the
3719 // absolute container.
3720 if (outerFrame->IsAbsPosContainingBlock()) {
3721 maybeAbsoluteContainingBlock = outerFrame;
3722 maybeAbsoluteContainingBlockStyleFrame = outerFrame;
3723 innerFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3724 }
3725
3726 // Our kids should go into the innerFrame.
3727 newFrame = innerFrame;
3728 }
3729
3730 aState.AddChild(primaryFrame, aFrameList, content, aParentFrame,
3731 allowOutOfFlow, allowOutOfFlow);
3732
3733 nsContainerFrame* newFrameAsContainer = do_QueryFrame(newFrame);
3734 if (newFrameAsContainer) {
3735 // Process the child content if requested
3736 nsFrameList childList;
3737 nsFrameConstructorSaveState absoluteSaveState;
3738
3739 if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10) {
3740 aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState);
3741 } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH0x200)) {
3742 maybeAbsoluteContainingBlock->AddStateBits(
3743 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
3744 if (maybeAbsoluteContainingBlockStyleFrame->IsAbsPosContainingBlock()) {
3745 auto* cf =
3746 static_cast<nsContainerFrame*>(maybeAbsoluteContainingBlock);
3747 aState.PushAbsoluteContainingBlock(
3748 cf, maybeAbsoluteContainingBlockStyleFrame, absoluteSaveState);
3749 }
3750 }
3751
3752 nsFrameConstructorSaveState floatSaveState;
3753 aState.MaybePushFloatContainingBlock(newFrameAsContainer, floatSaveState);
3754
3755 if (bits & FCDATA_USE_CHILD_ITEMS0x10000) {
3756 // At this point, we have not set up the auto value for this frame, and
3757 // no caller will have set it so it is not redundant and therefor will
3758 // not assert.
3759 AutoFrameConstructionPageName pageNameTracker(aState,
3760 newFrameAsContainer);
3761 ConstructFramesFromItemList(
3762 aState, aItem.mChildItems, newFrameAsContainer,
3763 bits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
3764 } else {
3765 // Process the child frames.
3766 ProcessChildren(aState, content, computedStyle, newFrameAsContainer,
3767 !(bits & FCDATA_DISALLOW_GENERATED_CONTENT0x400), childList,
3768 (bits & FCDATA_ALLOW_BLOCK_STYLES0x8000) != 0,
3769 possiblyLeafFrame);
3770 }
3771
3772 if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS0x20) {
3773 nsFrameList newList;
3774 nsFrameList currentBlockList;
3775 nsIFrame* f;
3776 while ((f = childList.FirstChild()) != nullptr) {
3777 bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f);
3778 if (!wrapFrame) {
3779 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3780 currentBlockList, newList);
3781 }
3782
3783 childList.RemoveFrame(f);
3784 if (wrapFrame) {
3785 currentBlockList.AppendFrame(nullptr, f);
3786 } else {
3787 newList.AppendFrame(nullptr, f);
3788 }
3789 }
3790 FlushAccumulatedBlock(aState, content, newFrameAsContainer,
3791 currentBlockList, newList);
3792
3793 if (childList.NotEmpty()) {
3794 // an error must have occurred, delete unprocessed frames
3795 DestroyFramesInList(mPresShell, childList);
3796 }
3797
3798 childList = std::move(newList);
3799 }
3800
3801 // Set the frame's initial child list. Note that MathML depends on this
3802 // being called even if childList is empty!
3803 newFrameAsContainer->SetInitialChildList(FrameChildListID::Principal,
3804 std::move(childList));
3805 }
3806 }
3807
3808 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", 3810); MOZ_PretendNoReturn
(); } } while (0)
3809 ((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", 3810); MOZ_PretendNoReturn
(); } } while (0)
3810 "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", 3810); MOZ_PretendNoReturn
(); } } while (0)
;
3811
3812 // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
3813 // generated content that doesn't have one yet. Note that we have to examine
3814 // the frame bit, because by this point mIsGeneratedContent has been cleared
3815 // on aItem.
3816 if ((!aState.mCreatingExtraFrames ||
3817 (aItem.mContent->IsRootOfNativeAnonymousSubtree() &&
3818 !aItem.mContent->GetPrimaryFrame())) &&
3819 !(bits & FCDATA_SKIP_FRAMESET0x1)) {
3820 aItem.mContent->SetPrimaryFrame(primaryFrame);
3821 ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
3822 }
3823}
3824
3825static void GatherSubtreeElements(Element* aElement,
3826 nsTArray<Element*>& aElements) {
3827 aElements.AppendElement(aElement);
3828 StyleChildrenIterator iter(aElement);
3829 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
3830 if (!c->IsElement()) {
3831 continue;
3832 }
3833 GatherSubtreeElements(c->AsElement(), aElements);
3834 }
3835}
3836
3837nsresult nsCSSFrameConstructor::GetAnonymousContent(
3838 nsIContent* aParent, nsIFrame* aParentFrame,
3839 nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) {
3840 nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3841 if (!creator) {
3842 return NS_OK;
3843 }
3844
3845 nsresult rv = creator->CreateAnonymousContent(aContent);
3846 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3847 // CreateAnonymousContent failed, e.g. because the page has a <use> loop.
3848 return rv;
3849 }
3850
3851 if (aContent.IsEmpty()) {
3852 return NS_OK;
3853 }
3854
3855 const bool devtoolsEventsEnabled =
3856 mDocument->DevToolsAnonymousAndShadowEventsEnabled();
3857
3858 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", 3858); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aParent->IsElement()" ")"); do { MOZ_CrashSequence
(__null, 3858); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3859 for (const auto& info : aContent) {
3860 // get our child's content and set its parent to our content
3861 nsIContent* content = info.mContent;
3862 content->SetIsNativeAnonymousRoot();
3863
3864 BindContext context(*aParent->AsElement(), BindContext::ForNativeAnonymous);
3865 rv = content->BindToTree(context, *aParent);
3866
3867 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3868 content->UnbindFromTree();
3869 return rv;
3870 }
3871
3872 if (devtoolsEventsEnabled) {
3873 content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
3874 }
3875 }
3876
3877 // Some situations where we don't cache anonymous content styles:
3878 //
3879 // * when visibility or pointer-events is anything other than the initial
3880 // value; we rely on visibility and pointer-events inheriting into anonymous
3881 // content, but don't bother adding this state to the AnonymousContentKey,
3882 // since it's not so common. Note that with overlay scrollbars, scrollbars
3883 // always start off with pointer-events: none so we don't need to check for
3884 // that in that case.
3885 //
3886 // * when the medium is anything other than screen; some UA style sheet rules
3887 // apply in e.g. print medium, and will give different results from the
3888 // cached styles
3889 Maybe<bool> computedAllowStyleCaching;
3890 auto ComputeAllowStyleCaching = [&] {
3891 if (!StaticPrefs::layout_css_cached_scrollbar_styles_enabled()) {
3892 return false;
3893 }
3894 if (aParentFrame->StyleVisibility()->mVisible != StyleVisibility::Visible) {
3895 return false;
3896 }
3897 nsPresContext* pc = mPresShell->GetPresContext();
3898 if (!pc->UseOverlayScrollbars() &&
3899 aParentFrame->StyleUI()->ComputedPointerEvents() !=
3900 StylePointerEvents::Auto) {
3901 return false;
3902 }
3903 if (pc->Medium() != nsGkAtoms::screen) {
3904 return false;
3905 }
3906 return true;
3907 };
3908
3909 auto AllowStyleCaching = [&] {
3910 if (computedAllowStyleCaching.isNothing()) {
3911 computedAllowStyleCaching.emplace(ComputeAllowStyleCaching());
3912 }
3913 return computedAllowStyleCaching.value();
3914 };
3915
3916 // Compute styles for the anonymous content tree.
3917 ServoStyleSet* styleSet = mPresShell->StyleSet();
3918 for (auto& info : aContent) {
3919 Element* e = Element::FromNode(info.mContent);
3920 if (!e) {
3921 continue;
3922 }
3923
3924 if (info.mKey == AnonymousContentKey::None || !AllowStyleCaching()) {
3925 // Most NAC subtrees do not use caching of computed styles. Just go
3926 // ahead and eagerly style the subtree.
3927 styleSet->StyleNewSubtree(e);
3928 continue;
3929 }
3930
3931 // We have a NAC subtree for which we can use cached styles.
3932 AutoTArray<RefPtr<ComputedStyle>, 2> cachedStyles;
3933 AutoTArray<Element*, 2> elements;
3934
3935 GatherSubtreeElements(e, elements);
3936 styleSet->GetCachedAnonymousContentStyles(info.mKey, cachedStyles);
3937
3938 if (cachedStyles.IsEmpty()) {
3939 // We haven't stored cached styles for this kind of NAC subtree yet.
3940 // Eagerly compute those styles, then cache them for later.
3941 styleSet->StyleNewSubtree(e);
3942 for (Element* e : elements) {
3943 if (e->HasServoData()) {
3944 cachedStyles.AppendElement(ServoStyleSet::ResolveServoStyle(*e));
3945 } else {
3946 cachedStyles.AppendElement(nullptr);
3947 }
3948 }
3949 styleSet->PutCachedAnonymousContentStyles(info.mKey,
3950 std::move(cachedStyles));
3951 continue;
3952 }
3953
3954 // We previously stored cached styles for this kind of NAC subtree.
3955 // Iterate over them and set them on the subtree's elements.
3956 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"
, 3957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3957 "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"
, 3957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles.Length() == elements.Length()"
") (" "should always produce the same size NAC subtree" ")")
; do { MOZ_CrashSequence(__null, 3957); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3958 for (size_t i = 0, len = cachedStyles.Length(); i != len; ++i) {
3959 if (cachedStyles[i]) {
3960#ifdef DEBUG1
3961 // Assert that our cached style is the same as one we could compute.
3962 RefPtr<ComputedStyle> cs = styleSet->ResolveStyleLazily(*elements[i]);
3963 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"
, 3966); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3966); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3964 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"
, 3966); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3966); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3965 "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"
, 3966); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3966); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
3966 "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"
, 3966); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cachedStyles[i]->EqualForCachedAnonymousContentStyle(*cs)"
") (" "cached anonymous content styles should be identical to those we "
"would compute normally" ")"); do { MOZ_CrashSequence(__null
, 3966); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3967 // All overlay scrollbars start off as inactive, so we can rely on their
3968 // pointer-events value being always none.
3969 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", 3971); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3971); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3970 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", 3971); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3971); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3971 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", 3971); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mPresShell->GetPresContext()->UseOverlayScrollbars() || cs->StyleUI()->ComputedPointerEvents() == StylePointerEvents::None"
")"); do { MOZ_CrashSequence(__null, 3971); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3972#endif
3973 Servo_SetExplicitStyle(elements[i], cachedStyles[i]);
3974 }
3975 }
3976 }
3977
3978 return NS_OK;
3979}
3980
3981/* static */
3982const nsCSSFrameConstructor::FrameConstructionData*
3983nsCSSFrameConstructor::FindXULTagData(const Element& aElement,
3984 ComputedStyle& aStyle) {
3985 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", 3985); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsXULElement()" ")"); do { MOZ_CrashSequence
(__null, 3985); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3986 static constexpr FrameConstructionData kPopupData(NS_NewMenuPopupFrame);
3987
3988 static constexpr FrameConstructionDataByTag sXULTagData[] = {
3989 SIMPLE_TAG_CREATE(image, NS_NewXULImageFrame){nsGkAtoms::image, FrameConstructionData(NS_NewXULImageFrame)
}
,
3990 SIMPLE_TAG_CREATE(treechildren, NS_NewTreeBodyFrame){nsGkAtoms::treechildren, FrameConstructionData(NS_NewTreeBodyFrame
)}
,
3991 SIMPLE_TAG_CHAIN(label,{nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindXULLabelOrDescriptionData)}
3992 nsCSSFrameConstructor::FindXULLabelOrDescriptionData){nsGkAtoms::label, FrameConstructionData(nsCSSFrameConstructor
::FindXULLabelOrDescriptionData)}
,
3993 SIMPLE_TAG_CHAIN(description,{nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindXULLabelOrDescriptionData)}
3994 nsCSSFrameConstructor::FindXULLabelOrDescriptionData){nsGkAtoms::description, FrameConstructionData(nsCSSFrameConstructor
::FindXULLabelOrDescriptionData)}
,
3995 SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame){nsGkAtoms::iframe, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3996 SIMPLE_TAG_CREATE(editor, NS_NewSubDocumentFrame){nsGkAtoms::editor, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3997 SIMPLE_TAG_CREATE(browser, NS_NewSubDocumentFrame){nsGkAtoms::browser, FrameConstructionData(NS_NewSubDocumentFrame
)}
,
3998 SIMPLE_TAG_CREATE(splitter, NS_NewSplitterFrame){nsGkAtoms::splitter, FrameConstructionData(NS_NewSplitterFrame
)}
,
3999 SIMPLE_TAG_CREATE(scrollbar, NS_NewScrollbarFrame){nsGkAtoms::scrollbar, FrameConstructionData(NS_NewScrollbarFrame
)}
,
4000 SIMPLE_TAG_CREATE(slider, NS_NewSliderFrame){nsGkAtoms::slider, FrameConstructionData(NS_NewSliderFrame)},
4001 SIMPLE_TAG_CREATE(thumb, NS_NewSimpleXULLeafFrame){nsGkAtoms::thumb, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4002 SIMPLE_TAG_CREATE(scrollcorner, NS_NewSimpleXULLeafFrame){nsGkAtoms::scrollcorner, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4003 SIMPLE_TAG_CREATE(resizer, NS_NewSimpleXULLeafFrame){nsGkAtoms::resizer, FrameConstructionData(NS_NewSimpleXULLeafFrame
)}
,
4004 SIMPLE_TAG_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame){nsGkAtoms::scrollbarbutton, FrameConstructionData(NS_NewScrollbarButtonFrame
)}
,
4005 {nsGkAtoms::panel, kPopupData},
4006 {nsGkAtoms::menupopup, kPopupData},
4007 {nsGkAtoms::tooltip, kPopupData},
4008 };
4009
4010 return FindDataByTag(aElement, aStyle, sXULTagData, std::size(sXULTagData));
4011}
4012
4013/* static */
4014const nsCSSFrameConstructor::FrameConstructionData*
4015nsCSSFrameConstructor::FindXULLabelOrDescriptionData(const Element& aElement,
4016 ComputedStyle&) {
4017 // Follow CSS display value if no value attribute
4018 if (!aElement.HasAttr(nsGkAtoms::value)) {
4019 return nullptr;
4020 }
4021
4022 // Follow CSS display if there's no crop="center".
4023 if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::crop,
4024 nsGkAtoms::center, eCaseMatters)) {
4025 return nullptr;
4026 }
4027
4028 static constexpr FrameConstructionData sMiddleCroppingData(
4029 NS_NewMiddleCroppingLabelFrame);
4030 return &sMiddleCroppingData;
4031}
4032
4033already_AddRefed<ComputedStyle>
4034nsCSSFrameConstructor::BeginBuildingScrollContainerFrame(
4035 nsFrameConstructorState& aState, nsIContent* aContent,
4036 ComputedStyle* aContentStyle, nsContainerFrame* aParentFrame, bool aIsRoot,
4037 nsContainerFrame*& aNewFrame) {
4038 nsContainerFrame* scrollContainerFrame = aNewFrame;
4039
4040 if (!scrollContainerFrame) {
4041 scrollContainerFrame =
4042 NS_NewScrollContainerFrame(mPresShell, aContentStyle, aIsRoot);
4043 InitAndRestoreFrame(aState, aContent, aParentFrame, scrollContainerFrame);
4044 }
4045
4046 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", 4046); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "scrollContainerFrame" ")"); do { MOZ_CrashSequence
(__null, 4046); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4047
4048 // if there are any anonymous children for the scroll frame, create
4049 // frames for them.
4050 //
4051 // We can't take the normal ProcessChildren path, because the NAC needs to
4052 // be parented to the scrollframe, and everything else needs to be parented
4053 // to the scrolledframe.
4054 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
4055 DebugOnly<nsresult> rv =
4056 GetAnonymousContent(aContent, scrollContainerFrame, scrollNAC);
4057 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"
, 4057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4057); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4058 nsFrameList anonymousList;
4059 if (!scrollNAC.IsEmpty()) {
4060 nsFrameConstructorSaveState floatSaveState;
4061 aState.MaybePushFloatContainingBlock(scrollContainerFrame, floatSaveState);
4062
4063 AutoFrameConstructionItemList items(this);
4064 AutoFrameConstructionPageName pageNameTracker(aState, scrollContainerFrame);
4065 AddFCItemsForAnonymousContent(aState, scrollContainerFrame, scrollNAC,
4066 items, pageNameTracker);
4067 ConstructFramesFromItemList(aState, items, scrollContainerFrame,
4068 /* aParentIsWrapperAnonBox = */ false,
4069 anonymousList);
4070 }
4071
4072 aNewFrame = scrollContainerFrame;
4073 scrollContainerFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4074
4075 // we used the style that was passed in. So resolve another one.
4076 ServoStyleSet* styleSet = mPresShell->StyleSet();
4077 RefPtr<ComputedStyle> scrolledChildStyle =
4078 styleSet->ResolveInheritingAnonymousBoxStyle(
4079 PseudoStyleType::MozScrolledContent, aContentStyle);
4080
4081 scrollContainerFrame->SetInitialChildList(FrameChildListID::Principal,
4082 std::move(anonymousList));
4083
4084 return scrolledChildStyle.forget();
4085}
4086
4087void nsCSSFrameConstructor::FinishBuildingScrollContainerFrame(
4088 nsContainerFrame* aScrollContainerFrame, nsIFrame* aScrolledFrame) {
4089 aScrollContainerFrame->AppendFrames(
4090 FrameChildListID::Principal, nsFrameList(aScrolledFrame, aScrolledFrame));
4091}
4092
4093void nsCSSFrameConstructor::BuildScrollContainerFrame(
4094 nsFrameConstructorState& aState, nsIContent* aContent,
4095 ComputedStyle* aContentStyle, nsIFrame* aScrolledFrame,
4096 nsContainerFrame* aParentFrame, nsContainerFrame*& aNewFrame) {
4097 RefPtr<ComputedStyle> scrolledContentStyle =
4098 BeginBuildingScrollContainerFrame(aState, aContent, aContentStyle,
4099 aParentFrame, false, aNewFrame);
4100
4101 aScrolledFrame->SetComputedStyleWithoutNotification(scrolledContentStyle);
4102 InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame);
4103
4104 FinishBuildingScrollContainerFrame(aNewFrame, aScrolledFrame);
4105}
4106
4107const nsCSSFrameConstructor::FrameConstructionData*
4108nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
4109 const Element& aElement) {
4110 static_assert(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET28)),
4111 "Check eParentTypeCount should not overflow");
4112
4113 // The style system ensures that floated and positioned frames are
4114 // block-level.
4115 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", 4118); MOZ_PretendNoReturn
(); } } while (0)
4116 !(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", 4118); MOZ_PretendNoReturn
(); } } while (0)
4117 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", 4118); MOZ_PretendNoReturn
(); } } while (0)
4118 "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", 4118); MOZ_PretendNoReturn
(); } } while (0)
;
4119
4120 // If this is "body", try propagating its scroll style to the viewport
4121 // Note that we need to do this even if the body is NOT scrollable;
4122 // it might have dynamically changed from scrollable to not scrollable,
4123 // and that might need to be propagated.
4124 // XXXbz is this the right place to do this? If this code moves,
4125 // make this function static.
4126 bool propagatedScrollToViewport = false;
4127 if (aElement.IsHTMLElement(nsGkAtoms::body)) {
4128 if (nsPresContext* presContext = mPresShell->GetPresContext()) {
4129 propagatedScrollToViewport =
4130 presContext->UpdateViewportScrollStylesOverride() == &aElement;
4131 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", 4133); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4132 !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", 4133); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4133 "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", 4133); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!propagatedScrollToViewport || !mPresShell->GetPresContext()->IsPaginated()"
") (" "Shouldn't propagate scroll in paginated contexts" ")"
); do { MOZ_CrashSequence(__null, 4133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4134 }
4135 }
4136
4137 switch (aDisplay.DisplayInside()) {
4138 case StyleDisplayInside::Flow:
4139 case StyleDisplayInside::FlowRoot: {
4140 if (aDisplay.IsInlineFlow()) {
4141 static constexpr FrameConstructionData data(
4142 &nsCSSFrameConstructor::ConstructInline,
4143 FCDATA_IS_INLINE0x1000 | FCDATA_IS_LINE_PARTICIPANT0x2000);
4144 return &data;
4145 }
4146
4147 // If the frame is a block-level frame and is scrollable, then wrap it in
4148 // a scroll frame. Except we don't want to do that for paginated contexts
4149 // for frames that are block-outside and aren't frames for native
4150 // anonymous stuff.
4151 // XXX Ignore tables for the time being (except caption)
4152 const uint32_t kCaptionCtorFlags =
4153 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28);
4154 const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
4155 const bool needScrollFrame =
4156 aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport;
4157 if (needScrollFrame) {
4158 const bool suppressScrollFrame =
4159 mPresShell->GetPresContext()->IsPaginated() &&
4160 aDisplay.IsBlockOutsideStyle() &&
4161 !aElement.IsInNativeAnonymousSubtree();
4162 if (!suppressScrollFrame) {
4163 static constexpr FrameConstructionData sScrollableBlockData[2] = {
4164 {&nsCSSFrameConstructor::ConstructScrollableBlock},
4165 {&nsCSSFrameConstructor::ConstructScrollableBlock,
4166 kCaptionCtorFlags}};
4167 return &sScrollableBlockData[caption];
4168 }
4169 }
4170
4171 // Handle various non-scrollable blocks.
4172 static constexpr FrameConstructionData sNonScrollableBlockData[2] = {
4173 {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
4174 {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
4175 kCaptionCtorFlags}};
4176 return &sNonScrollableBlockData[caption];
4177 }
4178 case StyleDisplayInside::Table: {
4179 static constexpr FrameConstructionData data(
4180 &nsCSSFrameConstructor::ConstructTable);
4181 return &data;
4182 }
4183 // NOTE: In the unlikely event that we add another table-part here that
4184 // has a desired-parent-type (& hence triggers table fixup), we'll need to
4185 // also update the flexbox chunk in ComputedStyle::ApplyStyleFixups().
4186 case StyleDisplayInside::TableRowGroup: {
4187 static constexpr FrameConstructionData data(
4188 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4189 FCDATA_IS_TABLE_PART0x800 |
4190 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4191 return &data;
4192 }
4193 case StyleDisplayInside::TableColumn: {
4194 static constexpr FrameConstructionData data(
4195 &nsCSSFrameConstructor::ConstructTableCol,
4196 FCDATA_IS_TABLE_PART0x800 |
4197 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup)(((uint32_t)(eTypeColGroup)) << 28));
4198 return &data;
4199 }
4200 case StyleDisplayInside::TableColumnGroup: {
4201 static constexpr FrameConstructionData data(
4202 ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
4203 FCDATA_IS_TABLE_PART0x800 | FCDATA_DISALLOW_OUT_OF_FLOW0x8 |
4204 FCDATA_SKIP_ABSPOS_PUSH0x200 |
4205 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4206 return &data;
4207 }
4208 case StyleDisplayInside::TableHeaderGroup: {
4209 static constexpr FrameConstructionData data(
4210 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4211 FCDATA_IS_TABLE_PART0x800 |
4212 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4213 return &data;
4214 }
4215 case StyleDisplayInside::TableFooterGroup: {
4216 static constexpr FrameConstructionData data(
4217 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4218 FCDATA_IS_TABLE_PART0x800 |
4219 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28));
4220 return &data;
4221 }
4222 case StyleDisplayInside::TableRow: {
4223 static constexpr FrameConstructionData data(
4224 &nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
4225 FCDATA_IS_TABLE_PART0x800 |
4226 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28));
4227 return &data;
4228 }
4229 case StyleDisplayInside::TableCell: {
4230 static constexpr FrameConstructionData data(
4231 &nsCSSFrameConstructor::ConstructTableCell,
4232 FCDATA_IS_TABLE_PART0x800 | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28));
4233 return &data;
4234 }
4235 case StyleDisplayInside::Flex:
4236 case StyleDisplayInside::WebkitBox: {
4237 static constexpr FrameConstructionData nonScrollableData(
4238 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
);
4239 static constexpr FrameConstructionData data(
4240 ToCreationFunc(NS_NewFlexContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewFlexContainerFrame(aPs, aStyle); }
,
4241 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4242 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4243 : &data;
4244 }
4245 case StyleDisplayInside::Grid: {
4246 static constexpr FrameConstructionData nonScrollableData(
4247 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
);
4248 static constexpr FrameConstructionData data(
4249 ToCreationFunc(NS_NewGridContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewGridContainerFrame(aPs, aStyle); }
,
4250 FCDATA_MAY_NEED_SCROLLFRAME0x80);
4251 return MOZ_UNLIKELY(propagatedScrollToViewport)(__builtin_expect(!!(propagatedScrollToViewport), 0)) ? &nonScrollableData
4252 : &data;
4253 }
4254 case StyleDisplayInside::Ruby: {
4255 static constexpr FrameConstructionData data[] = {
4256 {&nsCSSFrameConstructor::ConstructBlockRubyFrame,
4257 FCDATA_MAY_NEED_SCROLLFRAME0x80},
4258 {ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
, FCDATA_IS_LINE_PARTICIPANT0x2000}};
4259 bool isInline = aDisplay.DisplayOutside() == StyleDisplayOutside::Inline;
4260 return &data[isInline];
4261 }
4262 case StyleDisplayInside::RubyBase: {
4263 static constexpr FrameConstructionData data(
4264 ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
4265 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4266 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28));
4267 return &data;
4268 }
4269 case StyleDisplayInside::RubyBaseContainer: {
4270 static constexpr FrameConstructionData data(
4271 ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
4272 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4273 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4274 return &data;
4275 }
4276 case StyleDisplayInside::RubyText: {
4277 static constexpr FrameConstructionData data(
4278 ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
4279 FCDATA_IS_LINE_PARTICIPANT0x2000 |
4280 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28));
4281 return &data;
4282 }
4283 case StyleDisplayInside::RubyTextContainer: {
4284 static constexpr FrameConstructionData data(
4285 ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
4286 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28));
4287 return &data;
4288 }
4289 default:
4290 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"
, 4290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown 'display' value" ")"); do
{ MOZ_CrashSequence(__null, 4290); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4291 return nullptr;
4292 }
4293}
4294
4295nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
4296 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4297 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4298 nsFrameList& aFrameList) {
4299 nsContainerFrame* newFrame = nullptr;
4300 ConstructScrollableBlockWithScrollContainer(aState, aItem, aParentFrame,
4301 aDisplay, aFrameList, newFrame);
4302 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFrame" ")"
); do { MOZ_CrashSequence(__null, 4302); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4303 return newFrame;
4304}
4305
4306void nsCSSFrameConstructor::ConstructScrollableBlockWithScrollContainer(
4307 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4308 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4309 nsFrameList& aFrameList, nsContainerFrame*& aNewFrame) {
4310 nsIContent* const content = aItem.mContent;
4311 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4312 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", 4312); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aNewFrame->IsScrollContainerOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 4312); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4313
4314 RefPtr<ComputedStyle> scrolledContentStyle =
4315 BeginBuildingScrollContainerFrame(
4316 aState, content, computedStyle,
4317 aState.GetGeometricParent(*aDisplay, aParentFrame), false, aNewFrame);
4318
4319 // Create our block frame
4320 // pass a temporary stylecontext, the correct one will be set later
4321 nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4322
4323 // Make sure to AddChild before we call ConstructBlock so that we
4324 // end up before our descendants in fixed-pos lists as needed.
4325 aState.AddChild(aNewFrame, aFrameList, content, aParentFrame);
4326
4327 nsFrameList blockList;
4328 ConstructBlock(aState, content, aNewFrame, aNewFrame, scrolledContentStyle,
4329 &scrolledFrame, blockList,
4330 aNewFrame->IsAbsPosContainingBlock() ? aNewFrame : nullptr);
4331
4332 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", 4333
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4333 "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", 4333
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockList.OnlyChild() == scrolledFrame"
") (" "Scrollframe's frameList should be exactly the scrolled frame!"
")"); do { MOZ_CrashSequence(__null, 4333); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4334 FinishBuildingScrollContainerFrame(aNewFrame, scrolledFrame);
4335}
4336
4337nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
4338 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4339 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4340 nsFrameList& aFrameList) {
4341 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4342 nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
4343 ConstructBlock(aState, aItem.mContent,
4344 aState.GetGeometricParent(*aDisplay, aParentFrame),
4345 aParentFrame, computedStyle, &newFrame, aFrameList,
4346 newFrame->IsAbsPosContainingBlock() ? newFrame : nullptr);
4347 return newFrame;
4348}
4349
4350void nsCSSFrameConstructor::InitAndRestoreFrame(
4351 const nsFrameConstructorState& aState, nsIContent* aContent,
4352 nsContainerFrame* aParentFrame, nsIFrame* aNewFrame,
4353 AllowCounters aAllowCounters) {
4354 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", 4354
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewFrame" ") (" "Null frame cannot be initialized"
")"); do { MOZ_CrashSequence(__null, 4354); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4355
4356 // Initialize the frame
4357 aNewFrame->Init(aContent, aParentFrame, nullptr);
4358 aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4359
4360 if (aState.mFrameState) {
4361 // Restore frame state for just the newly created frame.
4362 RestoreFrameStateFor(aNewFrame, aState.mFrameState);
4363 }
4364
4365 if (aAllowCounters == AllowCounters::Yes &&
4366 mContainStyleScopeManager.AddCounterChanges(aNewFrame)) {
4367 CountersDirty();
4368 }
4369}
4370
4371already_AddRefed<ComputedStyle> nsCSSFrameConstructor::ResolveComputedStyle(
4372 nsIContent* aContent) {
4373 if (auto* element = Element::FromNode(aContent)) {
4374 return ServoStyleSet::ResolveServoStyle(*element);
4375 }
4376
4377 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", 4379
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4378 "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", 4379
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4379 "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", 4379
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText()"
") (" "shouldn't waste time creating ComputedStyles for " "comments and processing instructions"
")"); do { MOZ_CrashSequence(__null, 4379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4380
4381 Element* parent = aContent->GetFlattenedTreeParentElement();
4382 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", 4382
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "Text out of the flattened tree?"
")"); do { MOZ_CrashSequence(__null, 4382); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4383
4384 // FIXME(emilio): The const_cast is unfortunate, but it's not worse than what
4385 // we did before.
4386 //
4387 // We could use ResolveServoStyle, but that would involve extra unnecessary
4388 // refcount traffic...
4389 auto* parentStyle =
4390 const_cast<ComputedStyle*>(Servo_Element_GetMaybeOutOfDateStyle(parent));
4391 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", 4392); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4392); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4392 "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", 4392); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentStyle" ") (" "How are we inserting text frames in an unstyled element?"
")"); do { MOZ_CrashSequence(__null, 4392); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4393 return mPresShell->StyleSet()->ResolveStyleForText(aContent, parentStyle);
4394}
4395
4396// MathML Mod - RBS
4397void nsCSSFrameConstructor::FlushAccumulatedBlock(
4398 nsFrameConstructorState& aState, nsIContent* aContent,
4399 nsContainerFrame* aParentFrame, nsFrameList& aBlockList,
4400 nsFrameList& aNewList) {
4401 if (aBlockList.IsEmpty()) {
4402 // Nothing to do
4403 return;
4404 }
4405
4406 auto anonPseudo = PseudoStyleType::MozMathmlAnonymousBlock;
4407
4408 ComputedStyle* parentContext =
4409 nsIFrame::CorrectStyleParentFrame(aParentFrame, anonPseudo)->Style();
4410 ServoStyleSet* styleSet = mPresShell->StyleSet();
4411 RefPtr<ComputedStyle> blockContext =
4412 styleSet->ResolveInheritingAnonymousBoxStyle(anonPseudo, parentContext);
4413
4414 // then, create a block frame that will wrap the child frames. Make it a
4415 // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4416 // is not a suitable block.
4417 nsContainerFrame* blockFrame =
4418 NS_NewMathMLmathBlockFrame(mPresShell, blockContext);
4419
4420 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
4421 ReparentFrames(this, blockFrame, aBlockList, false);
4422 // We have to walk over aBlockList before we hand it over to blockFrame.
4423 for (nsIFrame* f : aBlockList) {
4424 f->SetParentIsWrapperAnonBox();
4425 }
4426 // abs-pos and floats are disabled in MathML children so we don't have to
4427 // worry about messing up those.
4428 blockFrame->SetInitialChildList(FrameChildListID::Principal,
4429 std::move(aBlockList));
4430 aNewList.AppendFrame(nullptr, blockFrame);
4431}
4432
4433// Only <math> elements can be floated or positioned. All other MathML
4434// should be in-flow.
4435#define MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 } \
4436 FrameConstructionData { \
4437 _func, FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | \
4438 FCDATA_WRAP_KIDS_IN_BLOCKS0x20 \
4439 }
4440
4441#define SIMPLE_MATHML_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData { _func, 0x8 | 0x10 |
0x20 }}
{nsGkAtoms::_tag, MATHML_DATA(_func)FrameConstructionData { _func, 0x8 | 0x10 | 0x20 }}
4442
4443/* static */
4444const nsCSSFrameConstructor::FrameConstructionData*
4445nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
4446 ComputedStyle& aStyle) {
4447 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", 4447); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsMathMLElement()" ")"); do { MOZ_CrashSequence
(__null, 4447); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4448
4449 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4450
4451 // Handle <math> specially, because it sometimes produces inlines
4452 if (tag == nsGkAtoms::math) {
4453 // The IsBlockOutsideStyle() check must match what
4454 // specified::Display::equivalent_block_display is checking for
4455 // already-block-outside things. Though the behavior here for the
4456 // display:table case is pretty weird...
4457 if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
4458 static constexpr FrameConstructionData sBlockMathData(
4459 ToCreationFunc(NS_NewMathMLmathBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathBlockFrame(aPs, aStyle); }
,
4460 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4461 return &sBlockMathData;
4462 }
4463
4464 static constexpr FrameConstructionData sInlineMathData(
4465 ToCreationFunc(NS_NewMathMLmathInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewMathMLmathInlineFrame(aPs, aStyle); }
,
4466 FCDATA_FORCE_NULL_ABSPOS_CONTAINER0x10 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4467 FCDATA_WRAP_KIDS_IN_BLOCKS0x20);
4468 return &sInlineMathData;
4469 }
4470
4471 // Special case for elements with a display value other than none
4472 // specified in mathml.css that are not handled by this function.
4473 // These shouldn't be rendered as an mrow.
4474 if (tag == nsGkAtoms::mtable || tag == nsGkAtoms::mtr ||
4475 tag == nsGkAtoms::mlabeledtr || tag == nsGkAtoms::mtd) {
4476 return nullptr;
4477 }
4478
4479 static constexpr FrameConstructionDataByTag sMathMLData[] = {
4480 SIMPLE_MATHML_CREATE(annotation, NS_NewMathMLTokenFrame){nsGkAtoms::annotation, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4481 SIMPLE_MATHML_CREATE(annotation_xml, NS_NewMathMLmrowFrame){nsGkAtoms::annotation_xml, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4482 SIMPLE_MATHML_CREATE(mi, NS_NewMathMLTokenFrame){nsGkAtoms::mi, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4483 SIMPLE_MATHML_CREATE(mn, NS_NewMathMLTokenFrame){nsGkAtoms::mn, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4484 SIMPLE_MATHML_CREATE(ms, NS_NewMathMLTokenFrame){nsGkAtoms::ms, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4485 SIMPLE_MATHML_CREATE(mtext, NS_NewMathMLTokenFrame){nsGkAtoms::mtext, FrameConstructionData { NS_NewMathMLTokenFrame
, 0x8 | 0x10 | 0x20 }}
,
4486 SIMPLE_MATHML_CREATE(mo, NS_NewMathMLmoFrame){nsGkAtoms::mo, FrameConstructionData { NS_NewMathMLmoFrame, 0x8
| 0x10 | 0x20 }}
,
4487 SIMPLE_MATHML_CREATE(mfrac, NS_NewMathMLmfracFrame){nsGkAtoms::mfrac, FrameConstructionData { NS_NewMathMLmfracFrame
, 0x8 | 0x10 | 0x20 }}
,
4488 SIMPLE_MATHML_CREATE(msup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4489 SIMPLE_MATHML_CREATE(msub, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msub, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4490 SIMPLE_MATHML_CREATE(msubsup, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::msubsup, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4491 SIMPLE_MATHML_CREATE(munder, NS_NewMathMLmunderoverFrame){nsGkAtoms::munder, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4492 SIMPLE_MATHML_CREATE(mover, NS_NewMathMLmunderoverFrame){nsGkAtoms::mover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4493 SIMPLE_MATHML_CREATE(munderover, NS_NewMathMLmunderoverFrame){nsGkAtoms::munderover, FrameConstructionData { NS_NewMathMLmunderoverFrame
, 0x8 | 0x10 | 0x20 }}
,
4494 SIMPLE_MATHML_CREATE(mphantom, NS_NewMathMLmrowFrame){nsGkAtoms::mphantom, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4495 SIMPLE_MATHML_CREATE(mpadded, NS_NewMathMLmpaddedFrame){nsGkAtoms::mpadded, FrameConstructionData { NS_NewMathMLmpaddedFrame
, 0x8 | 0x10 | 0x20 }}
,
4496 SIMPLE_MATHML_CREATE(mspace, NS_NewMathMLmspaceFrame){nsGkAtoms::mspace, FrameConstructionData { NS_NewMathMLmspaceFrame
, 0x8 | 0x10 | 0x20 }}
,
4497 SIMPLE_MATHML_CREATE(none, NS_NewMathMLmrowFrame){nsGkAtoms::none, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4498 SIMPLE_MATHML_CREATE(mprescripts, NS_NewMathMLmrowFrame){nsGkAtoms::mprescripts, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4499 SIMPLE_MATHML_CREATE(mfenced, NS_NewMathMLmrowFrame){nsGkAtoms::mfenced, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4500 SIMPLE_MATHML_CREATE(mmultiscripts, NS_NewMathMLmmultiscriptsFrame){nsGkAtoms::mmultiscripts, FrameConstructionData { NS_NewMathMLmmultiscriptsFrame
, 0x8 | 0x10 | 0x20 }}
,
4501 SIMPLE_MATHML_CREATE(mstyle, NS_NewMathMLmrowFrame){nsGkAtoms::mstyle, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4502 SIMPLE_MATHML_CREATE(msqrt, NS_NewMathMLmrootFrame){nsGkAtoms::msqrt, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4503 SIMPLE_MATHML_CREATE(mroot, NS_NewMathMLmrootFrame){nsGkAtoms::mroot, FrameConstructionData { NS_NewMathMLmrootFrame
, 0x8 | 0x10 | 0x20 }}
,
4504 SIMPLE_MATHML_CREATE(maction, NS_NewMathMLmrowFrame){nsGkAtoms::maction, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4505 SIMPLE_MATHML_CREATE(mrow, NS_NewMathMLmrowFrame){nsGkAtoms::mrow, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4506 SIMPLE_MATHML_CREATE(merror, NS_NewMathMLmrowFrame){nsGkAtoms::merror, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
,
4507 SIMPLE_MATHML_CREATE(menclose, NS_NewMathMLmencloseFrame){nsGkAtoms::menclose, FrameConstructionData { NS_NewMathMLmencloseFrame
, 0x8 | 0x10 | 0x20 }}
,
4508 SIMPLE_MATHML_CREATE(semantics, NS_NewMathMLmrowFrame){nsGkAtoms::semantics, FrameConstructionData { NS_NewMathMLmrowFrame
, 0x8 | 0x10 | 0x20 }}
};
4509
4510 if (const auto* data = FindDataByTag(aElement, aStyle, sMathMLData,
4511 std::size(sMathMLData))) {
4512 return data;
4513 }
4514 // Unknown MathML elements render as an mrow, see:
4515 // https://w3c.github.io/mathml-core/#ref-for-dfn-unknown-mathml-element-2
4516 static constexpr FrameConstructionData sMrowData =
4517 MATHML_DATA(NS_NewMathMLmrowFrame)FrameConstructionData { NS_NewMathMLmrowFrame, 0x8 | 0x10 | 0x20
}
;
4518 return &sMrowData;
4519}
4520
4521nsContainerFrame* nsCSSFrameConstructor::ConstructSVGFrameWithAnonymousChild(
4522 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4523 nsContainerFrame* aParentFrame, nsFrameList& aFrameList,
4524 ContainerFrameCreationFunc aConstructor,
4525 ContainerFrameCreationFunc aInnerConstructor, PseudoStyleType aInnerPseudo,
4526 bool aCandidateRootFrame) {
4527 nsIContent* const content = aItem.mContent;
4528 ComputedStyle* const computedStyle = aItem.mComputedStyle;
4529
4530 // Create the outer frame:
4531 nsContainerFrame* newFrame = aConstructor(mPresShell, computedStyle);
4532
4533 InitAndRestoreFrame(aState, content,
4534 aCandidateRootFrame
4535 ? aState.GetGeometricParent(
4536 *computedStyle->StyleDisplay(), aParentFrame)
4537 : aParentFrame,
4538 newFrame);
4539 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
4540
4541 // Create the pseudo SC for the anonymous wrapper child as a child of the SC:
4542 RefPtr<ComputedStyle> scForAnon =
4543 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(aInnerPseudo,
4544 computedStyle);
4545
4546 // Create the anonymous inner wrapper frame
4547 nsContainerFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon);
4548
4549 InitAndRestoreFrame(aState, content, newFrame, innerFrame);
4550
4551 // Put the newly created frames into the right child list
4552 SetInitialSingleChild(newFrame, innerFrame);
4553
4554 aState.AddChild(newFrame, aFrameList, content, aParentFrame,
4555 aCandidateRootFrame, aCandidateRootFrame);
4556
4557 if (!mRootElementFrame && aCandidateRootFrame) {
4558 mRootElementFrame = newFrame;
4559 }
4560
4561 nsFrameConstructorSaveState floatSaveState;
4562 aState.MaybePushFloatContainingBlock(innerFrame, floatSaveState);
4563
4564 nsFrameList childList;
4565
4566 // Process children
4567 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS0x10000) {
4568 ConstructFramesFromItemList(
4569 aState, aItem.mChildItems, innerFrame,
4570 aItem.mFCData->mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000, childList);
4571 } else {
4572 ProcessChildren(aState, content, computedStyle, innerFrame,
4573 /* aCanHaveGeneratedContent = */ false, childList, false);
4574 }
4575
4576 // Set the inner wrapper frame's initial primary list
4577 innerFrame->SetInitialChildList(FrameChildListID::Principal,
4578 std::move(childList));
4579
4580 return newFrame;
4581}
4582
4583nsIFrame* nsCSSFrameConstructor::ConstructOuterSVG(
4584 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4585 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4586 nsFrameList& aFrameList) {
4587 return ConstructSVGFrameWithAnonymousChild(
4588 aState, aItem, aParentFrame, aFrameList, NS_NewSVGOuterSVGFrame,
4589 NS_NewSVGOuterSVGAnonChildFrame, PseudoStyleType::MozSvgOuterSvgAnonChild,
4590 true);
4591}
4592
4593nsIFrame* nsCSSFrameConstructor::ConstructMarker(
4594 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
4595 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
4596 nsFrameList& aFrameList) {
4597 return ConstructSVGFrameWithAnonymousChild(
4598 aState, aItem, aParentFrame, aFrameList, NS_NewSVGMarkerFrame,
4599 NS_NewSVGMarkerAnonChildFrame, PseudoStyleType::MozSvgMarkerAnonChild,
4600 false);
4601}
4602
4603// Only outer <svg> elements can be floated or positioned. All other SVG
4604// should be in-flow.
4605#define SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
\
4606 FrameConstructionData(ToCreationFunc(_func)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
_func(aPs, aStyle); }
, \
4607 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | \
4608 FCDATA_SKIP_ABSPOS_PUSH0x200 | \
4609 FCDATA_DISALLOW_GENERATED_CONTENT0x400)
4610#define SIMPLE_SVG_CREATE(_tag, _func){nsGkAtoms::_tag, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8
| 0x200 | 0x400)}
\
4611 {nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return _func(aPs, aStyle); }, 0x8 | 0x200
| 0x400)
}
4612
4613/* static */
4614const nsCSSFrameConstructor::FrameConstructionData*
4615nsCSSFrameConstructor::FindSVGData(const Element& aElement,
4616 nsIFrame* aParentFrame,
4617 bool aIsWithinSVGText,
4618 bool aAllowsTextPathChild,
4619 ComputedStyle& aStyle) {
4620 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", 4620); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aElement.IsSVGElement()" ")"); do { MOZ_CrashSequence
(__null, 4620); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4621
4622 static constexpr FrameConstructionData sSuppressData = SUPPRESS_FCDATA()FrameConstructionData(nullptr, 0x40);
4623 static constexpr FrameConstructionData sContainerData =
4624 SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame)FrameConstructionData([](PresShell* aPs, ComputedStyle* aStyle
) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)
;
4625
4626 bool parentIsSVG = aIsWithinSVGText;
4627 nsIContent* parentContent =
4628 aParentFrame ? aParentFrame->GetContent() : nullptr;
4629
4630 nsAtom* tag = aElement.NodeInfo()->NameAtom();
4631
4632 if (aElement.OwnerDoc()->IsSVGGlyphsDocument()) {
4633 // SVG elements that are explicitly not supported in svg-glyphs documents.
4634 // (Partially applies the restrictions mentioned at
4635 // https://learn.microsoft.com/en-us/typography/opentype/spec/svg#svg-capability-requirements-and-restrictions
4636 if (tag == nsGkAtoms::text || tag == nsGkAtoms::tspan ||
4637 tag == nsGkAtoms::textPath || tag == nsGkAtoms::a ||
4638 tag == nsGkAtoms::foreignObject || tag == nsGkAtoms::svgSwitch ||
4639 tag == nsGkAtoms::view) {
4640 return &sSuppressData;
4641 }
4642 }
4643
4644 // XXXbz should this really be based on the tag of the parent frame's content?
4645 // Should it not be based on the type of the parent frame (e.g. whether it's
4646 // an SVG frame)?
4647 if (parentContent) {
4648 // It's not clear whether the SVG spec intends to allow any SVG
4649 // content within svg:foreignObject at all (SVG 1.1, section
4650 // 23.2), but if it does, it better be svg:svg. So given that
4651 // we're allowing it, treat it as a non-SVG parent.
4652 parentIsSVG =
4653 parentContent->IsSVGElement() &&
4654 parentContent->NodeInfo()->NameAtom() != nsGkAtoms::foreignObject;
4655 }
4656
4657 if ((tag != nsGkAtoms::svg && !parentIsSVG) ||
4658 (tag == nsGkAtoms::desc || tag == nsGkAtoms::title ||
4659 tag == nsGkAtoms::metadata)) {
4660 // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4661 // svg:svg not contained within svg:svg are incorrect, although they
4662 // don't seem to specify error handling. Ignore them, since many of
4663 // our frame classes can't deal. It *may* be that the document
4664 // should at that point be considered in error according to F.2, but
4665 // it's hard to tell.
4666 //
4667 // We don't currently handle any UI for desc/title/metadata
4668 return &sSuppressData;
4669 }
4670
4671 // We don't need frames for animation elements
4672 if (aElement.IsSVGAnimationElement()) {
4673 return &sSuppressData;
4674 }
4675
4676 if (tag == nsGkAtoms::svg && !parentIsSVG) {
4677 // We need outer <svg> elements to have an SVGOuterSVGFrame regardless
4678 // of whether they fail conditional processing attributes, since various
4679 // SVG frames assume that one exists. We handle the non-rendering
4680 // of failing outer <svg> element contents like <switch> statements,
4681 // and do the PassesConditionalProcessingTests call in
4682 // SVGOuterSVGFrame::Init.
4683 static constexpr FrameConstructionData sOuterSVGData(
4684 &nsCSSFrameConstructor::ConstructOuterSVG);
4685 return &sOuterSVGData;
4686 }
4687
4688 if (tag == nsGkAtoms::marker) {
4689 static constexpr FrameConstructionData sMarkerSVGData(
4690 &nsCSSFrameConstructor::ConstructMarker);
4691 return &sMarkerSVGData;
4692 }
4693
4694 if (!aElement.PassesConditionalProcessingTests()) {
4695 // Elements with failing conditional processing attributes never get
4696 // rendered. Note that this is not where we select which frame in a
4697 // <switch> to render! That happens in SVGSwitchFrame::PaintSVG.
4698 if (aIsWithinSVGText) {
4699 // SVGTextFrame doesn't handle conditional processing attributes,
4700 // so don't create frames for descendants of <text> with failing
4701 // attributes. We need frames not to be created so that text layout
4702 // is correct.
4703 return &sSuppressData;
4704 }
4705 // If we're not inside <text>, create an SVGContainerFrame (which is a
4706 // frame that doesn't render) so that paint servers can still be referenced,
4707 // even if they live inside an element with failing conditional processing
4708 // attributes.
4709 return &sContainerData;
4710 }
4711
4712 // Ensure that a stop frame is a child of a gradient and that gradients
4713 // can only have stop children.
4714 bool parentIsGradient = aParentFrame && static_cast<SVGGradientFrame*>(
4715 do_QueryFrame(aParentFrame));
4716 bool stop = (tag == nsGkAtoms::stop);
4717 if ((parentIsGradient && !stop) || (!parentIsGradient && stop)) {
4718 return &sSuppressData;
4719 }
4720
4721 // Prevent bad frame types being children of filters or parents of filter
4722 // primitives. If aParentFrame is null, we know that the frame that will
4723 // be created will be an nsInlineFrame, so it can never be a filter.
4724 bool parentIsFilter = aParentFrame && aParentFrame->IsSVGFilterFrame();
4725 if ((parentIsFilter && !aElement.IsSVGFilterPrimitiveElement()) ||
4726 (!parentIsFilter && aElement.IsSVGFilterPrimitiveElement())) {
4727 return &sSuppressData;
4728 }
4729
4730 // Prevent bad frame types being children of filter primitives or parents of
4731 // filter primitive children. If aParentFrame is null, we know that the frame
4732 // that will be created will be an nsInlineFrame, so it can never be a filter
4733 // primitive.
4734 bool parentIsFEContainerFrame =
4735 aParentFrame && aParentFrame->IsSVGFEContainerFrame();
4736 if ((parentIsFEContainerFrame &&
4737 !aElement.IsSVGFilterPrimitiveChildElement()) ||
4738 (!parentIsFEContainerFrame &&
4739 aElement.IsSVGFilterPrimitiveChildElement())) {
4740 return &sSuppressData;
4741 }
4742
4743 // Special cases for text/tspan/textPath, because the kind of frame
4744 // they get depends on the parent frame. We ignore 'a' elements when
4745 // determining the parent, however.
4746 if (aIsWithinSVGText) {
4747 // If aIsWithinSVGText is true, then we know that the "SVG text uses
4748 // CSS frames" pref was true when this SVG fragment was first constructed.
4749 //
4750 // FIXME(bug 1588477) Don't render stuff in display: contents / Shadow DOM
4751 // subtrees, because TextCorrespondenceRecorder in the SVG text code doesn't
4752 // really know how to deal with it. This kinda sucks. :(
4753 if (aParentFrame && aParentFrame->GetContent() != aElement.GetParent()) {
4754 return &sSuppressData;
4755 }
4756
4757 // We don't use ConstructInline because we want different behavior
4758 // for generated content.
4759 static constexpr FrameConstructionData sTSpanData(
4760 ToCreationFunc(NS_NewInlineFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewInlineFrame(aPs, aStyle); }
,
4761 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_SKIP_ABSPOS_PUSH0x200 |
4762 FCDATA_DISALLOW_GENERATED_CONTENT0x400 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
4763 FCDATA_IS_INLINE0x1000 | FCDATA_USE_CHILD_ITEMS0x10000);
4764 if (tag == nsGkAtoms::textPath) {
4765 if (aAllowsTextPathChild) {
4766 return &sTSpanData;
4767 }
4768 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::a) {
4769 return &sTSpanData;
4770 }
4771 return &sSuppressData;
4772 } else if (tag == nsGkAtoms::tspan || tag == nsGkAtoms::textPath) {
4773 return &sSuppressData;
4774 }
4775
4776 static constexpr FrameConstructionDataByTag sSVGData[] = {
4777 SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame){nsGkAtoms::svg, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGInnerSVGFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4778 SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame){nsGkAtoms::g, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4779 SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame){nsGkAtoms::svgSwitch, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGSwitchFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4780 SIMPLE_SVG_CREATE(symbol, NS_NewSVGSymbolFrame){nsGkAtoms::symbol, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGSymbolFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4781 SIMPLE_SVG_CREATE(polygon, NS_NewSVGGeometryFrame){nsGkAtoms::polygon, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4782 SIMPLE_SVG_CREATE(polyline, NS_NewSVGGeometryFrame){nsGkAtoms::polyline, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4783 SIMPLE_SVG_CREATE(circle, NS_NewSVGGeometryFrame){nsGkAtoms::circle, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4784 SIMPLE_SVG_CREATE(ellipse, NS_NewSVGGeometryFrame){nsGkAtoms::ellipse, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4785 SIMPLE_SVG_CREATE(line, NS_NewSVGGeometryFrame){nsGkAtoms::line, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4786 SIMPLE_SVG_CREATE(rect, NS_NewSVGGeometryFrame){nsGkAtoms::rect, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4787 SIMPLE_SVG_CREATE(path, NS_NewSVGGeometryFrame){nsGkAtoms::path, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGGeometryFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4788 SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame){nsGkAtoms::defs, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGContainerFrame(aPs
, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4789 {nsGkAtoms::text,
4790 {NS_NewSVGTextFrame,
4791 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_ALLOW_BLOCK_STYLES0x8000 |
4792 FCDATA_DISALLOW_GENERATED_CONTENT0x400,
4793 PseudoStyleType::MozSvgText}},
4794 {nsGkAtoms::foreignObject,
4795 {ToCreationFunc(NS_NewSVGForeignObjectFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewSVGForeignObjectFrame(aPs, aStyle); }
,
4796 FCDATA_DISALLOW_OUT_OF_FLOW0x8, PseudoStyleType::MozSvgForeignContent}},
4797 SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame){nsGkAtoms::a, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGAFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4798 SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame){nsGkAtoms::linearGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGLinearGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4799 SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame){nsGkAtoms::radialGradient, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGRadialGradientFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4800 SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame){nsGkAtoms::stop, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGStopFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4801 SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame){nsGkAtoms::use, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGUseFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4802 SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame){nsGkAtoms::view, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGViewFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4803 SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame){nsGkAtoms::image, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGImageFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4804 SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame){nsGkAtoms::clipPath, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGClipPathFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4805 SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame){nsGkAtoms::filter, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFilterFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4806 SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame){nsGkAtoms::pattern, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGPatternFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4807 SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame){nsGkAtoms::mask, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGMaskFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4808 SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feDistantLight, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4809 SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::fePointLight, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4810 SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feSpotLight, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4811 SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame){nsGkAtoms::feBlend, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4812 SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feColorMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4813 SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncR, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4814 SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncG, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4815 SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncB, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4816 SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feFuncA, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4817 SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame){nsGkAtoms::feComposite, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4818 SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame){nsGkAtoms::feComponentTransfer, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4819 SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame){nsGkAtoms::feConvolveMatrix, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4820 SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feDiffuseLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4821 SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame){nsGkAtoms::feDisplacementMap, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4822 SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame){nsGkAtoms::feDropShadow, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4823 SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame){nsGkAtoms::feFlood, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4824 SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame){nsGkAtoms::feGaussianBlur, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4825 SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame){nsGkAtoms::feImage, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEImageFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4826 SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame){nsGkAtoms::feMerge, FrameConstructionData([](PresShell* aPs,
ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4827 SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame){nsGkAtoms::feMergeNode, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEUnstyledLeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4828 SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame){nsGkAtoms::feMorphology, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4829 SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame){nsGkAtoms::feOffset, FrameConstructionData([](PresShell* aPs
, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4830 SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame){nsGkAtoms::feSpecularLighting, FrameConstructionData([](PresShell
* aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFEContainerFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
,
4831 SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame){nsGkAtoms::feTile, FrameConstructionData([](PresShell* aPs, ComputedStyle
* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame(aPs, aStyle
); }, 0x8 | 0x200 | 0x400)}
,
4832 SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame){nsGkAtoms::feTurbulence, FrameConstructionData([](PresShell*
aPs, ComputedStyle* aStyle) -> nsIFrame* { return NS_NewSVGFELeafFrame
(aPs, aStyle); }, 0x8 | 0x200 | 0x400)}
};
4833
4834 const FrameConstructionData* data =
4835 FindDataByTag(aElement, aStyle, sSVGData, std::size(sSVGData));
4836
4837 if (!data) {
4838 data = &sContainerData;
4839 }
4840
4841 return data;
4842}
4843
4844void nsCSSFrameConstructor::AppendPageBreakItem(
4845 nsIContent* aContent, FrameConstructionItemList& aItems) {
4846 RefPtr<ComputedStyle> pseudoStyle =
4847 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
4848 PseudoStyleType::MozPageBreak);
4849
4850 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"
, 4851); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4851); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
4851 "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"
, 4851); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block"
") (" "Unexpected display" ")"); do { MOZ_CrashSequence(__null
, 4851); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4852
4853 static constexpr FrameConstructionData sPageBreakData(NS_NewPageBreakFrame,
4854 FCDATA_SKIP_FRAMESET0x1);
4855 aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
4856 true);
4857}
4858
4859bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
4860 nsFrameConstructorState& aState, nsIContent* aContent,
4861 nsContainerFrame* aParentFrame) {
4862 aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
4863 // XXX the GetContent() != aContent check is needed due to bug 135040.
4864 // Remove it once that's fixed.
4865 if (aContent->GetPrimaryFrame() &&
4866 aContent->GetPrimaryFrame()->GetContent() == aContent &&
4867 !aState.mCreatingExtraFrames) {
4868 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"
, 4870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4869 "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"
, 4870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4870 "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"
, 4870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"asked to create frame construction item for a node that " "already has a frame"
")"); do { MOZ_CrashSequence(__null, 4870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4871 return false;
4872 }
4873
4874 // don't create a whitespace frame if aParent doesn't want it
4875 if (!NeedFrameFor(aState, aParentFrame, aContent)) {
4876 return false;
4877 }
4878
4879 // never create frames for comments or PIs
4880 if (aContent->IsComment() || aContent->IsProcessingInstruction()) {
4881 return false;
4882 }
4883
4884 return true;
4885}
4886
4887void nsCSSFrameConstructor::AddFrameConstructionItems(
4888 nsFrameConstructorState& aState, nsIContent* aContent,
4889 bool aSuppressWhiteSpaceOptimizations, const ComputedStyle& aParentStyle,
4890 const InsertionPoint& aInsertion, FrameConstructionItemList& aItems,
4891 ItemFlags aFlags) {
4892 nsContainerFrame* parentFrame = aInsertion.mParentFrame;
4893 if (!ShouldCreateItemsForChild(aState, aContent, parentFrame)) {
4894 return;
4895 }
4896
4897 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(aContent);
4898 auto flags = aFlags + ItemFlag::AllowPageBreak;
4899 if (parentFrame) {
4900 if (parentFrame->IsInSVGTextSubtree()) {
4901 flags += ItemFlag::IsWithinSVGText;
4902 }
4903 if (parentFrame->IsBlockFrame() && parentFrame->GetParent() &&
4904 parentFrame->GetParent()->IsSVGTextFrame()) {
4905 flags += ItemFlag::AllowTextPathChild;
4906 }
4907 }
4908 AddFrameConstructionItemsInternal(aState, aContent, parentFrame,
4909 aSuppressWhiteSpaceOptimizations,
4910 computedStyle, flags, aItems);
4911}
4912
4913// Whether we should suppress frames for a child under a <select> element.
4914// Right now we need this for two things:
4915// * To implement <option label>'s suppression of descendants (sad!)
4916// * To implement hiding of the <select>'s text content (hopefully going away
4917// soon enough, see https://github.com/whatwg/html/issues/12717).
4918static bool ShouldSuppressFrameForSelect(const nsIContent* aParent,
4919 const nsIContent& aChild) {
4920 if (!aParent) {
4921 return false;
4922 }
4923
4924 if (aChild.IsRootOfNativeAnonymousSubtree()) {
4925 // Allow native anonymous content no matter what.
4926 return false;
4927 }
4928
4929 if (aParent->IsHTMLElement(nsGkAtoms::option)) {
4930 // Options with labels have their label text added in ::before by forms.css.
4931 // Suppress frames for their children.
4932 // TODO(emilio): This should probably be done with shadow DOM instead (but a
4933 // ShadowRoot per option seems unfortunate...).
4934 return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
4935 }
4936
4937 if (const auto* select = HTMLSelectElement::FromNode(aParent)) {
4938 // Direct text descendants of listbox <select> are not expected to render.
4939 return !select->IsCombobox() && aChild.IsText() &&
4940 aParent == aChild.GetParent();
4941 }
4942
4943 return false;
4944}
4945
4946const nsCSSFrameConstructor::FrameConstructionData*
4947nsCSSFrameConstructor::FindDataForContent(nsIContent& aContent,
4948 ComputedStyle& aStyle,
4949 nsIFrame* aParentFrame,
4950 ItemFlags aFlags) {
4951 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", 4953
); 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, 4953); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4952 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", 4953
); 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, 4953); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4953 "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", 4953
); 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, 4953); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4954
4955 if (auto* text = Text::FromNode(aContent)) {
4956 return FindTextData(*text, aParentFrame);
4957 }
4958
4959 return FindElementData(*aContent.AsElement(), aStyle, aParentFrame, aFlags);
4960}
4961
4962const nsCSSFrameConstructor::FrameConstructionData*
4963nsCSSFrameConstructor::FindElementData(const Element& aElement,
4964 ComputedStyle& aStyle,
4965 nsIFrame* aParentFrame,
4966 ItemFlags aFlags) {
4967 // Don't create frames for non-SVG element children of SVG elements.
4968 if (!aElement.IsSVGElement()) {
4969 // NOTE: Anon content is allowed, the native code should know what it's
4970 // doing. In practice we care about ::backdrop and the
4971 // custom-content-container.
4972 if (aParentFrame && IsFrameForSVG(aParentFrame) &&
4973 !aParentFrame->IsSVGForeignObjectFrame() &&
4974 !aElement.IsRootOfNativeAnonymousSubtree()) {
4975 return nullptr;
4976 }
4977 if (aFlags.contains(ItemFlag::IsWithinSVGText)) {
4978 return nullptr;
4979 }
4980 }
4981
4982 if (auto* data = FindElementTagData(aElement, aStyle, aParentFrame, aFlags)) {
4983 return data;
4984 }
4985
4986 // Check for 'content: <image-url>' on the element (which makes us ignore
4987 // 'display' values other than 'none' or 'contents').
4988 if (nsImageFrame::ShouldCreateImageFrameForContentProperty(aElement,
4989 aStyle)) {
4990 static constexpr FrameConstructionData sImgData(
4991 NS_NewImageFrameForContentProperty);
4992 return &sImgData;
4993 }
4994
4995 const bool shouldBlockify = aFlags.contains(ItemFlag::IsForRenderedLegend) ||
4996 aFlags.contains(ItemFlag::IsForOutsideMarker);
4997 if (shouldBlockify && !aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
4998 // Make a temp copy of StyleDisplay and blockify its mDisplay value.
4999 auto display = *aStyle.StyleDisplay();
5000 bool isRootElement = false;
5001 uint16_t rawDisplayValue =
5002 Servo_ComputedValues_BlockifiedDisplay(&aStyle, isRootElement);
5003 display.mDisplay = StyleDisplay{rawDisplayValue};
5004 return FindDisplayData(display, aElement);
5005 }
5006
5007 const auto& display = *aStyle.StyleDisplay();
5008 return FindDisplayData(display, aElement);
5009}
5010
5011const nsCSSFrameConstructor::FrameConstructionData*
5012nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
5013 ComputedStyle& aStyle,
5014 nsIFrame* aParentFrame,
5015 ItemFlags aFlags) {
5016 switch (aElement.GetNameSpaceID()) {
5017 case kNameSpaceID_XHTML3:
5018 return FindHTMLData(aElement, aParentFrame, aStyle);
5019 case kNameSpaceID_MathML6:
5020 return FindMathMLData(aElement, aStyle);
5021 case kNameSpaceID_SVG9:
5022 return FindSVGData(aElement, aParentFrame,
5023 aFlags.contains(ItemFlag::IsWithinSVGText),
5024 aFlags.contains(ItemFlag::AllowTextPathChild), aStyle);
5025 case kNameSpaceID_XUL8:
5026 return FindXULTagData(aElement, aStyle);
5027 default:
5028 return nullptr;
5029 }
5030}
5031
5032void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
5033 nsFrameConstructorState& aState, nsIContent* aContent,
5034 nsContainerFrame* aParentFrame, bool aSuppressWhiteSpaceOptimizations,
5035 ComputedStyle* aComputedStyle, ItemFlags aFlags,
5036 FrameConstructionItemList& aItems) {
5037 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"
, 5038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5038); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5038 "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"
, 5038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsText() || aContent->IsElement()"
") (" "Shouldn't get anything else here!" ")"); do { MOZ_CrashSequence
(__null, 5038); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5039 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"
, 5039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsInComposedDoc()"
")"); do { MOZ_CrashSequence(__null, 5039); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5040 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", 5041); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
")"); do { MOZ_CrashSequence(__null, 5041); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5041 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", 5041); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames || aContent->NodeInfo()->NameAtom() == nsGkAtoms::area"
")"); do { MOZ_CrashSequence(__null, 5041); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5042
5043 const bool withinSVGText = aFlags.contains(ItemFlag::IsWithinSVGText);
5044 const bool isGeneratedContent = aFlags.contains(ItemFlag::IsGeneratedContent);
5045 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"
, 5046); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5046); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
5046 "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"
, 5046); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isGeneratedContent || aComputedStyle->IsPseudoElement()"
") (" "Generated content should be a pseudo-element" ")"); do
{ MOZ_CrashSequence(__null, 5046); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5047
5048 FrameConstructionItem* item = nullptr;
5049 auto cleanupGeneratedContent = mozilla::MakeScopeExit([&]() {
5050 if (isGeneratedContent && !item) {
5051 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"
, 5053); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5053
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5052 "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"
, 5053); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5053
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
5053 "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"
, 5053); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDisplayContents(aContent)"
") (" "This would need to change if we support display: contents "
"in generated content" ")"); do { MOZ_CrashSequence(__null, 5053
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5054 aContent->UnbindFromTree();
5055 }
5056 });
5057
5058 // 'display:none' elements never creates any frames at all.
5059 const nsStyleDisplay& display = *aComputedStyle->StyleDisplay();
5060 if (display.mDisplay == StyleDisplay::None) {
5061 return;
5062 }
5063
5064 if (display.mDisplay == StyleDisplay::Contents) {
5065 // See the mDisplay fixup code in StyleAdjuster::adjust.
5066 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", 5067); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5067); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5067 "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", 5067); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aContent->AsElement()->IsRootOfNativeAnonymousSubtree()"
") (" "display:contents on anonymous content is unsupported"
")"); do { MOZ_CrashSequence(__null, 5067); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5068
5069 // FIXME(bug 1588477): <svg:text>'s TextNodeCorrespondenceRecorder has
5070 // trouble with everything that looks like display: contents.
5071 if (withinSVGText) {
5072 return;
5073 }
5074
5075 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5076 *aComputedStyle, PseudoStyleType::Before,
5077 aItems);
5078
5079 FlattenedChildIterator iter(aContent);
5080 InsertionPoint insertion(aParentFrame, aContent);
5081 for (nsIContent* child = iter.GetNextChild(); child;
5082 child = iter.GetNextChild()) {
5083 AddFrameConstructionItems(aState, child, aSuppressWhiteSpaceOptimizations,
5084 *aComputedStyle, insertion, aItems, aFlags);
5085 }
5086 aItems.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
5087
5088 CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
5089 *aComputedStyle, PseudoStyleType::After, aItems);
5090 return;
5091 }
5092
5093 nsIContent* parent = aParentFrame ? aParentFrame->GetContent() : nullptr;
5094 if (ShouldSuppressFrameForSelect(parent, *aContent)) {
5095 return;
5096 }
5097
5098 if (aContent->IsHTMLElement(nsGkAtoms::legend) && aParentFrame) {
5099 const nsFieldSetFrame* const fs = GetFieldSetFrameFor(aParentFrame);
5100 if (fs && !fs->GetLegend() && !aState.mHasRenderedLegend &&
5101 !aComputedStyle->StyleDisplay()->IsFloatingStyle() &&
5102 !aComputedStyle->StyleDisplay()->IsAbsolutelyPositionedStyle()) {
5103 aState.mHasRenderedLegend = true;
5104 aFlags += ItemFlag::IsForRenderedLegend;
5105 }
5106 }
5107
5108 const FrameConstructionData* const data =
5109 FindDataForContent(*aContent, *aComputedStyle, aParentFrame, aFlags);
5110 if (!data) {
5111 return;
5112 }
5113 const uint32_t bits = data->mBits;
5114 if (bits & FCDATA_SUPPRESS_FRAME0x40) {
5115 return;
5116 }
5117 // Create our shadow tree lazily if needed.
5118 // NOTE(emilio): This is rather hacky, we should ideally remove this and make
5119 // shadow tree creation faster, see bug 2017005.
5120 if (const RefPtr input = HTMLInputElement::FromNode(aContent)) {
5121 if (auto* sr = input->CreateShadowTreeFromLayoutIfNeeded()) {
5122 StyleNewChildRange(sr->GetFirstChild(), nullptr);
5123 }
5124 }
5125
5126 const bool canHavePageBreak =
5127 aFlags.contains(ItemFlag::AllowPageBreak) &&
5128 aState.mPresContext->IsPaginated() &&
5129 !display.IsAbsolutelyPositionedStyle() &&
5130 !(aParentFrame && aParentFrame->IsFlexOrGridContainer()) &&
5131 !(bits & FCDATA_IS_TABLE_PART0x800) && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5132 if (canHavePageBreak && display.BreakBefore()) {
5133 AppendPageBreakItem(aContent, aItems);
5134 }
5135
5136 if (!item) {
5137 item = aItems.AppendItem(this, data, aContent, do_AddRef(aComputedStyle),
5138 aSuppressWhiteSpaceOptimizations);
5139 if (aFlags.contains(ItemFlag::IsForRenderedLegend)) {
5140 item->mIsRenderedLegend = true;
5141 }
5142 }
5143 item->mIsText = !aContent->IsElement();
5144 item->mIsGeneratedContent = isGeneratedContent;
5145 if (isGeneratedContent) {
5146 // We need to keep this alive until the frame takes ownership.
5147 // This corresponds to the Release in ConstructFramesFromItem.
5148 item->mContent->AddRef();
5149 }
5150
5151 if (canHavePageBreak && display.BreakAfter()) {
5152 AppendPageBreakItem(aContent, aItems);
5153 }
5154
5155 if (bits & FCDATA_IS_INLINE0x1000) {
5156 // To correctly set item->mIsAllInline we need to build up our child items
5157 // right now.
5158 BuildInlineChildItems(aState, *item,
5159 aFlags.contains(ItemFlag::IsWithinSVGText),
5160 aFlags.contains(ItemFlag::AllowTextPathChild));
5161 item->mIsBlock = false;
5162 } else {
5163 // Compute a boolean isInline which is guaranteed to be false for blocks
5164 // (but may also be false for some inlines).
5165 const bool isInline =
5166 // Table-internal things are inline-outside if and only if they're kids
5167 // of inlines, since they'll trigger construction of inline-table
5168 // pseudos.
5169 ((bits & FCDATA_IS_TABLE_PART0x800) &&
5170 (!aParentFrame || // No aParentFrame means inline
5171 aParentFrame->StyleDisplay()->IsInlineFlow())) ||
5172 // Things that are inline-outside but aren't inline frames are inline
5173 display.IsInlineOutsideStyle();
5174
5175 // Set mIsAllInline conservatively. It just might be that even an inline
5176 // that has mIsAllInline false doesn't need an {ib} split. So this is just
5177 // an optimization to keep from doing too much work in cases when we can
5178 // show that mIsAllInline is true..
5179 item->mIsAllInline =
5180 isInline ||
5181 // Figure out whether we're guaranteed this item will be out of flow.
5182 // This is not a precise test, since one of our ancestor inlines might
5183 // add an absolute containing block (if it's relatively positioned) when
5184 // there wasn't such a containing block before. But it's conservative
5185 // in the sense that anything that will really end up as an in-flow
5186 // non-inline will test false here. In other words, if this test is
5187 // true we're guaranteed to be inline; if it's false we don't know what
5188 // we'll end up as.
5189 //
5190 // If we make this test precise, we can remove some of the code dealing
5191 // with the imprecision in ConstructInline and adjust the comments on
5192 // mIsAllInline and mIsBlock in the header.
5193 (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
5194 aState.GetGeometricParent(display, nullptr));
5195
5196 // Set mIsBlock conservatively. It's OK to set it false for some real
5197 // blocks, but not OK to set it true for things that aren't blocks. Since
5198 // isOutOfFlow might be false even in cases when the frame will end up
5199 // out-of-flow, we can't use it here. But we _can_ say that the frame will
5200 // for sure end up in-flow if it's not floated or absolutely positioned.
5201 item->mIsBlock = !isInline && !display.IsAbsolutelyPositionedStyle() &&
5202 !display.IsFloatingStyle() && !(bits & FCDATA_IS_SVG_TEXT0x80000);
5203 }
5204
5205 if (item->mIsAllInline) {
5206 aItems.InlineItemAdded();
5207 } else if (item->mIsBlock) {
5208 aItems.BlockItemAdded();
5209 }
5210}
5211
5212/**
5213 * Return true if the frame construction item pointed to by aIter will
5214 * create a frame adjacent to a line boundary in the frame tree, and that
5215 * line boundary is induced by a content node adjacent to the frame's
5216 * content node in the content tree. The latter condition is necessary so
5217 * that ContentAppended/ContentInserted/ContentWillBeRemoved can easily find any
5218 * text nodes that were suppressed here.
5219 */
5220bool nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) {
5221 if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5222 return false;
5223 }
5224
5225 if (aIter.AtStart()) {
5226 if (aIter.List()->HasLineBoundaryAtStart() &&
5227 !aIter.item().mContent->GetPreviousSibling()) {
5228 return true;
5229 }
5230 } else {
5231 FCItemIterator prev = aIter;
5232 prev.Prev();
5233 if (prev.item().IsLineBoundary() &&
5234 !prev.item().mSuppressWhiteSpaceOptimizations &&
5235 aIter.item().mContent->GetPreviousSibling() == prev.item().mContent) {
5236 return true;
5237 }
5238 }
5239
5240 FCItemIterator next = aIter;
5241 next.Next();
5242 if (next.IsDone()) {
5243 if (aIter.List()->HasLineBoundaryAtEnd() &&
5244 !aIter.item().mContent->GetNextSibling()) {
5245 return true;
5246 }
5247 } else {
5248 if (next.item().IsLineBoundary() &&
5249 !next.item().mSuppressWhiteSpaceOptimizations &&
5250 aIter.item().mContent->GetNextSibling() == next.item().mContent) {
5251 return true;
5252 }
5253 }
5254
5255 return false;
5256}
5257
5258void nsCSSFrameConstructor::ConstructFramesFromItem(
5259 nsFrameConstructorState& aState, FCItemIterator& aIter,
5260 nsContainerFrame* aParentFrame, nsFrameList& aFrameList) {
5261 FrameConstructionItem& item = aIter.item();
5262 ComputedStyle* computedStyle = item.mComputedStyle;
5263 if (item.mIsText) {
5264 // If this is collapsible whitespace next to a line boundary,
5265 // don't create a frame. item.IsWhitespace() also sets the
5266 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5267 // end up creating a frame, nsTextFrame::Init will clear the flag.)
5268 // We don't do this for generated content, because some generated
5269 // text content is empty text nodes that are about to be initialized.
5270 // (We check mAdditionalStateBits because only the generated content
5271 // container's frame construction item is marked with
5272 // mIsGeneratedContent, and we might not have an aParentFrame.)
5273 // We don't do it for content that may have Shadow DOM siblings / insertion
5274 // points, because they make it difficult to correctly create the frame due
5275 // to dynamic changes.
5276 // We don't do it for SVG text, since we might need to position and
5277 // measure the white space glyphs due to x/y/dx/dy attributes.
5278 if (AtLineBoundary(aIter) &&
5279 !computedStyle->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
5280 aIter.List()->ParentHasNoShadowDOM() &&
5281 !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
5282 (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) &&
5283 !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT0x80000) &&
5284 !mAlwaysCreateFramesForIgnorableWhitespace &&
5285 item.IsWhitespace(aState)) {
5286 return;
5287 }
5288
5289 ConstructTextFrame(item.mFCData, aState, item.mContent, aParentFrame,
5290 computedStyle, aFrameList);
5291 return;
5292 }
5293
5294 AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
5295 if (item.mIsGeneratedContent) {
5296 // Ensure that frames created here are all tagged with
5297 // NS_FRAME_GENERATED_CONTENT.
5298 aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
5299 }
5300
5301 // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5302 ConstructFrameFromItemInternal(item, aState, aParentFrame, aFrameList);
5303
5304 if (item.mIsGeneratedContent) {
5305 // This corresponds to the AddRef in AddFrameConstructionItemsInternal.
5306 // The frame owns the generated content now.
5307 item.mContent->Release();
5308
5309 // Now that we've passed ownership of item.mContent to the frame, unset
5310 // our generated content flag so we don't release or unbind it ourselves.
5311 item.mIsGeneratedContent = false;
5312 }
5313}
5314
5315nsContainerFrame* nsCSSFrameConstructor::GetAbsoluteContainingBlock(
5316 nsIFrame* aFrame, ContainingBlockType aType) {
5317 // Starting with aFrame, look for a frame that is absolutely positioned or
5318 // relatively positioned (and transformed, if aType is FIXED)
5319 for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
5320 if (frame->IsMathMLFrame()) {
5321 // If it's mathml, bail out -- no absolute positioning out from inside
5322 // mathml frames. Note that we don't make this part of the loop
5323 // condition because of the stuff at the end of this method...
5324 return nullptr;
5325 }
5326
5327 // Look for the ICB.
5328 if (aType == FIXED_POS &&
5329 (frame->IsViewportFrame() || frame->IsPageContentFrame())) {
5330 return static_cast<nsContainerFrame*>(frame);
5331 }
5332
5333 // If the frame is positioned, we will probably return it as the containing
5334 // block (see the exceptions below). Otherwise, we'll start looking at the
5335 // parent frame, unless we're dealing with a scrollframe.
5336 // Scrollframes are special since they're not positioned, but their
5337 // scrolledframe might be. So, we need to check this special case to return
5338 // the correct containing block (the scrolledframe) in that case.
5339 // If we're looking for a fixed-pos containing block and the frame is
5340 // not transformed, skip it.
5341 if (!frame->IsAbsPosContainingBlock()) {
5342 continue;
5343 }
5344 if (aType == FIXED_POS && !frame->IsFixedPosContainingBlock()) {
5345 continue;
5346 }
5347 nsIFrame* absPosCBCandidate = frame;
5348 if (absPosCBCandidate->IsFieldSetFrame()) {
5349 absPosCBCandidate =
5350 static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner();
5351 if (!absPosCBCandidate) {
5352 continue;
5353 }
5354 }
5355 if (absPosCBCandidate->IsScrollContainerFrame()) {
5356 ScrollContainerFrame* scrollContainerFrame =
5357 do_QueryFrame(absPosCBCandidate);
5358 absPosCBCandidate = scrollContainerFrame->GetScrolledFrame();
5359 if (!absPosCBCandidate) {
5360 continue;
5361 }
5362 }
5363 // Only first continuations or first IB-split siblings can be containing
5364 // blocks.
5365 absPosCBCandidate =
5366 nsLayoutUtils::FirstContinuationOrIBSplitSibling(absPosCBCandidate);
5367 // Is the frame really an absolute container?
5368 if (!absPosCBCandidate->IsAbsoluteContainer()) {
5369 continue;
5370 }
5371
5372 // For tables, skip the inner frame and consider the table wrapper frame.
5373 if (absPosCBCandidate->IsTableFrame()) {
5374 continue;
5375 }
5376 // For table wrapper frames, we can just return absPosCBCandidate.
5377 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", 5378
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5378); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5378 "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", 5378
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(absPosCBCandidate)"
") (" "abs.pos. containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5378); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5379 return static_cast<nsContainerFrame*>(absPosCBCandidate);
5380 }
5381
5382 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"
, 5382); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aType != FIXED_POS"
") (" "no ICB in this frame tree?" ")"); do { MOZ_CrashSequence
(__null, 5382); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5383
5384 // It is possible for the search for the containing block to fail, because
5385 // no absolute container can be found in the parent chain. In those cases,
5386 // we fall back to the document element's containing block.
5387 return mDocElementContainingBlock;
5388}
5389
5390nsContainerFrame* nsCSSFrameConstructor::GetFloatContainingBlock(
5391 nsIFrame* aFrame) {
5392 // Starting with aFrame, look for a frame that is a float containing block.
5393 // If we hit a frame which prevents its descendants from floating, bail out.
5394 // The logic here needs to match the logic in MaybePushFloatContainingBlock().
5395 for (nsIFrame* containingBlock = aFrame;
5396 containingBlock && !ShouldSuppressFloatingOfDescendants(containingBlock);
5397 containingBlock = containingBlock->GetParent()) {
5398 if (containingBlock->IsFloatContainingBlock()) {
5399 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", 5400
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5400 "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", 5400
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(nsContainerFrame*)do_QueryFrame(containingBlock)"
") (" "float containing block must be nsContainerFrame sub-class"
")"); do { MOZ_CrashSequence(__null, 5400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5401 return static_cast<nsContainerFrame*>(containingBlock);
5402 }
5403 }
5404
5405 // If we didn't find a containing block, then there just isn't
5406 // one.... return null
5407 return nullptr;
5408}
5409
5410/**
5411 * Finds the right parent frame to append content to aParentFrame.
5412 *
5413 * Cannot return or receive null.
5414 */
5415static nsContainerFrame* ContinuationToAppendTo(
5416 nsContainerFrame* aParentFrame) {
5417 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"
, 5417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 5417); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5418
5419 if (IsFramePartOfIBSplit(aParentFrame)) {
5420 // If the frame we are manipulating is a ib-split frame (that is, one that's
5421 // been created as a result of a block-in-inline situation) then we need to
5422 // append to the last ib-split sibling, not to the frame itself.
5423 //
5424 // Always make sure to look at the last continuation of the frame for the
5425 // {ib} case, even if that continuation is empty.
5426 //
5427 // We don't do this for the non-ib-split-frame case, since in the other
5428 // cases appending to the last nonempty continuation is fine and in fact not
5429 // doing that can confuse code that doesn't know to pull kids from
5430 // continuations other than its next one.
5431 return static_cast<nsContainerFrame*>(
5432 GetLastIBSplitSibling(aParentFrame)->LastContinuation());
5433 }
5434
5435 return nsLayoutUtils::LastContinuationWithChild(aParentFrame);
5436}
5437
5438/**
5439 * This function will get the next sibling for a frame insert operation given
5440 * the parent and previous sibling. aPrevSibling may be null.
5441 */
5442static nsIFrame* GetInsertNextSibling(nsIFrame* aParentFrame,
5443 nsIFrame* aPrevSibling) {
5444 if (aPrevSibling) {
5445 return aPrevSibling->GetNextSibling();
5446 }
5447
5448 return aParentFrame->PrincipalChildList().FirstChild();
5449}
5450
5451void nsCSSFrameConstructor::AppendFramesToParent(
5452 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
5453 nsFrameList& aFrameList, nsIFrame* aPrevSibling, bool aIsRecursiveCall) {
5454 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"
, 5457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5457); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5455 !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"
, 5457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5457); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5456 !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"
, 5457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5457); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5457 "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"
, 5457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame) || !GetIBSplitSibling(aParentFrame) || !GetIBSplitSibling(aParentFrame)->PrincipalChildList().FirstChild()"
") (" "aParentFrame has a ib-split sibling with kids?" ")");
do { MOZ_CrashSequence(__null, 5457); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5458 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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5459); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5459 "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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevSibling || aPrevSibling->GetParent() == aParentFrame"
") (" "Parent and prevsibling don't match" ")"); do { MOZ_CrashSequence
(__null, 5459); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5460 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"
, 5464); 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, 5464); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5461 !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"
, 5464); 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, 5464); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5462 !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"
, 5464); 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, 5464); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5463 "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"
, 5464); 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, 5464); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
5464 "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"
, 5464); 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, 5464); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
5465
5466 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
5467
5468 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", 5473); MOZ_PretendNoReturn
(); } } while (0)
5469 !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", 5473); MOZ_PretendNoReturn
(); } } while (0)
5470 ->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", 5473); MOZ_PretendNoReturn
(); } } while (0)
5471 .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", 5473); MOZ_PretendNoReturn
(); } } while (0)
5472 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", 5473); MOZ_PretendNoReturn
(); } } while (0)
5473 "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", 5473); MOZ_PretendNoReturn
(); } } while (0)
;
5474 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", 5479); MOZ_PretendNoReturn
(); } } while (0)
5475 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", 5479); MOZ_PretendNoReturn
(); } } while (0)
5476 (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", 5479); MOZ_PretendNoReturn
(); } } while (0)
5477 !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", 5479); MOZ_PretendNoReturn
(); } } while (0)
5478 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", 5479); MOZ_PretendNoReturn
(); } } while (0)
5479 "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", 5479); MOZ_PretendNoReturn
(); } } while (0)
;
5480
5481 // If we're inserting a list of frames at the end of the trailing inline
5482 // of an {ib} split, we may need to create additional {ib} siblings to parent
5483 // them.
5484 if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) {
5485 // When we get here, our frame list might start with a block. If it does
5486 // so, and aParentFrame is an inline, and it and all its previous
5487 // continuations have no siblings, then put the initial blocks from the
5488 // frame list into the previous block of the {ib} split. Note that we
5489 // didn't want to stop at the block part of the split when figuring out
5490 // initial parent, because that could screw up float parenting; it's easier
5491 // to do this little fixup here instead.
5492 if (aFrameList.NotEmpty() && aFrameList.FirstChild()->IsBlockOutside()) {
5493 // See whether our trailing inline is empty
5494 nsIFrame* firstContinuation = aParentFrame->FirstContinuation();
5495 if (firstContinuation->PrincipalChildList().IsEmpty()) {
5496 // Our trailing inline is empty. Collect our starting blocks from
5497 // aFrameList, get the right parent frame for them, and put them in.
5498 nsFrameList blockKids =
5499 aFrameList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
5500 NS_ASSERTION(blockKids.NotEmpty(), "No blocks?")do { if (!(blockKids.NotEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "No blocks?", "blockKids.NotEmpty()", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 5500); MOZ_PretendNoReturn(); } } while (0)
;
5501
5502 nsContainerFrame* prevBlock = GetIBSplitPrevSibling(firstContinuation);
5503 prevBlock =
5504 static_cast<nsContainerFrame*>(prevBlock->LastContinuation());
5505 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"
, 5505); MOZ_PretendNoReturn(); } } while (0)
;
5506
5507 MoveChildrenTo(aParentFrame, prevBlock, blockKids);
5508 }
5509 }
5510
5511 // We want to put some of the frames into this inline frame.
5512 nsFrameList inlineKids =
5513 aFrameList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
5514
5515 if (!inlineKids.IsEmpty()) {
5516 AppendFrames(aParentFrame, FrameChildListID::Principal,
5517 std::move(inlineKids));
5518 }
5519
5520 if (!aFrameList.IsEmpty()) {
5521 nsFrameList ibSiblings;
5522 CreateIBSiblings(aState, aParentFrame,
5523 aParentFrame->IsAbsPosContainingBlock(), aFrameList,
5524 ibSiblings);
5525
5526 // Make sure to trigger reflow of the inline that used to be our
5527 // last one and now isn't anymore, since its GetSkipSides() has
5528 // changed.
5529 mPresShell->FrameNeedsReflow(aParentFrame,
5530 IntrinsicDirty::FrameAndAncestors,
5531 NS_FRAME_HAS_DIRTY_CHILDREN);
5532
5533 // Recurse so we create new ib siblings as needed for aParentFrame's
5534 // parent
5535 return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
5536 aParentFrame, true);
5537 }
5538 return;
5539 }
5540
5541 // If we're appending a list of frames to the last continuations of a
5542 // ::-moz-column-content, we may need to create column-span siblings for them.
5543 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
5544 // Extract any initial non-column-span kids, and append them to
5545 // ::-moz-column-content's child list.
5546 nsFrameList initialNonColumnSpanKids =
5547 aFrameList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
5548 AppendFrames(aParentFrame, FrameChildListID::Principal,
5549 std::move(initialNonColumnSpanKids));
5550
5551 if (aFrameList.IsEmpty()) {
5552 // No more kids to process (there weren't any column-span kids).
5553 return;
5554 }
5555
5556 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
5557 aState, aParentFrame, aFrameList,
5558 // Column content should never be a absolute/fixed positioned containing
5559 // block. Pass nullptr as aPositionedFrame.
5560 nullptr);
5561
5562 nsContainerFrame* columnSetWrapper = aParentFrame->GetParent();
5563 while (!columnSetWrapper->IsColumnSetWrapperFrame()) {
5564 columnSetWrapper = columnSetWrapper->GetParent();
5565 }
5566 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", 5567
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5567); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5567 "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", 5567
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSetWrapper"
") (" "No ColumnSetWrapperFrame ancestor for -moz-column-content?"
")"); do { MOZ_CrashSequence(__null, 5567); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5568
5569 FinishBuildingColumns(aState, columnSetWrapper, aParentFrame,
5570 columnSpanSiblings);
5571
5572 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", 5573
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5573); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5573 "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", 5573
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 5573); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5574 return;
5575 }
5576
5577 // Insert the frames after our aPrevSibling
5578 InsertFrames(aParentFrame, FrameChildListID::Principal, aPrevSibling,
5579 std::move(aFrameList));
5580}
5581
5582template <nsCSSFrameConstructor::SiblingDirection aDirection>
5583nsIFrame* nsCSSFrameConstructor::FindSiblingInternal(
5584 FlattenedChildIterator& aIter) {
5585 auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
5586 return aDirection == SiblingDirection::Forward ? aIter.GetNextChild()
5587 : aIter.GetPreviousChild();
5588 };
5589
5590 auto getInsideMarkerFrame = [](const nsIContent* aContent) -> nsIFrame* {
5591 auto* marker = nsLayoutUtils::GetMarkerFrame(aContent);
5592 const bool isInsideMarker =
5593 marker && marker->GetInFlowParent()->StyleList()->mListStylePosition ==
5594 StyleListStylePosition::Inside;
5595 return isInsideMarker ? marker : nullptr;
5596 };
5597
5598 auto getNearPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5599 if (aDirection == SiblingDirection::Forward) {
5600 if (auto* backdrop = nsLayoutUtils::GetBackdropFrame(aContent)) {
5601 return backdrop;
5602 }
5603 if (auto* marker = getInsideMarkerFrame(aContent)) {
5604 return marker;
5605 }
5606 return nsLayoutUtils::GetBeforeFrame(aContent);
5607 }
5608 return nsLayoutUtils::GetAfterFrame(aContent);
5609 };
5610
5611 auto getFarPseudo = [&](const nsIContent* aContent) -> nsIFrame* {
5612 if (aDirection == SiblingDirection::Forward) {
5613 if (auto* pickerIcon = nsLayoutUtils::GetPickerIconFrame(aContent)) {
5614 return pickerIcon;
5615 }
5616 return nsLayoutUtils::GetAfterFrame(aContent);
5617 }
5618 if (auto* before = nsLayoutUtils::GetBeforeFrame(aContent)) {
5619 return before;
5620 }
5621 if (auto* marker = getInsideMarkerFrame(aContent)) {
5622 return marker;
5623 }
5624 return nsLayoutUtils::GetBackdropFrame(aContent);
5625 };
5626
5627 while (nsIContent* sibling = nextDomSibling(aIter)) {
5628 // NOTE(emilio): It's important to check GetPrimaryFrame() before
5629 // IsDisplayContents to get the correct insertion point when multiple
5630 // siblings go from display: non-none to display: contents.
5631 if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
5632 // XXX the GetContent() == sibling check is needed due to bug 135040.
5633 // Remove it once that's fixed.
5634 // The rendered legend check is needed because it is conceptually out of
5635 // flow. There can only be one rendered legend at a time, and we reframe
5636 // when that changes, so this is ok. Table captions are a similar case,
5637 // but there can be multiple of them and they instead get pulled out (and
5638 // the sibling fixed up) after building the frame list.
5639 if (primaryFrame->GetContent() == sibling &&
5640 !primaryFrame->IsRenderedLegend()) [[likely]] {
5641 return primaryFrame;
5642 }
5643 }
5644
5645 if (IsDisplayContents(sibling)) {
5646 if (nsIFrame* frame = getNearPseudo(sibling)) {
5647 return frame;
5648 }
5649
5650 const bool startFromBeginning = aDirection == SiblingDirection::Forward;
5651 FlattenedChildIterator iter(sibling, startFromBeginning);
5652 nsIFrame* sibling = FindSiblingInternal<aDirection>(iter);
5653 if (sibling) {
5654 return sibling;
5655 }
5656 }
5657 }
5658
5659 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"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.ParentNode()->IsContent()"
")"); do { MOZ_CrashSequence(__null, 5659); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5660 return getFarPseudo(aIter.ParentNode()->AsContent());
5661}
5662
5663nsIFrame* nsCSSFrameConstructor::AdjustSiblingFrame(
5664 nsIFrame* aSibling, SiblingDirection aDirection) {
5665 if (!aSibling) {
5666 return nullptr;
5667 }
5668
5669 if (aSibling->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
5670 aSibling = aSibling->GetPlaceholderFrame();
5671 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"
, 5671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSibling" ")"
); do { MOZ_CrashSequence(__null, 5671); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5672 }
5673
5674 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"
, 5674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aSibling->GetPrevContinuation()"
") (" "How?" ")"); do { MOZ_CrashSequence(__null, 5674); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
5675 if (aDirection == SiblingDirection::Backward) {
5676 // The frame may be a ib-split frame (a split inline frame that contains a
5677 // block). Get the last part of that split.
5678 if (IsFramePartOfIBSplit(aSibling)) {
5679 aSibling = GetLastIBSplitSibling(aSibling);
5680 }
5681
5682 // The frame may have a continuation. If so, we want the last
5683 // non-overflow-container continuation as our previous sibling.
5684 aSibling = aSibling->GetTailContinuation();
5685 }
5686
5687 return aSibling;
5688}
5689
5690nsIFrame* nsCSSFrameConstructor::FindPreviousSibling(
5691 const FlattenedChildIterator& aIter) {
5692 return AdjustSiblingFrame(FindSibling<SiblingDirection::Backward>(aIter),
5693 SiblingDirection::Backward);
5694}
5695
5696nsIFrame* nsCSSFrameConstructor::FindNextSibling(
5697 const FlattenedChildIterator& aIter) {
5698 return AdjustSiblingFrame(FindSibling<SiblingDirection::Forward>(aIter),
5699 SiblingDirection::Forward);
5700}
5701
5702template <nsCSSFrameConstructor::SiblingDirection aDirection>
5703nsIFrame* nsCSSFrameConstructor::FindSibling(
5704 const FlattenedChildIterator& aIter) {
5705 FlattenedChildIterator siblingIter = aIter;
5706 nsIFrame* sibling = FindSiblingInternal<aDirection>(siblingIter);
5707 if (sibling) {
5708 return sibling;
5709 }
5710
5711 // Our siblings (if any) do not have a frame to guide us. The frame for the
5712 // target content should be inserted whereever a frame for the container would
5713 // be inserted. This is needed when inserting into display: contents nodes.
5714 const nsIContent* current = aIter.ParentNode()->AsContent();
5715 while (IsDisplayContents(current)) {
5716 const nsIContent* parent = current->GetFlattenedTreeParent();
5717 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", 5717
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ") (" "No display: contents on the root"
")"); do { MOZ_CrashSequence(__null, 5717); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5718
5719 FlattenedChildIterator iter(parent);
5720 iter.Seek(current);
5721 sibling = FindSiblingInternal<aDirection>(iter);
5722 if (sibling) {
5723 return sibling;
5724 }
5725
5726 current = parent;
5727 }
5728
5729 return nullptr;
5730}
5731
5732nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
5733 InsertionPoint* aInsertion, nsIContent* aChild, bool* aIsAppend) {
5734 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"
, 5734); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInsertion->mParentFrame"
") (" "Must have parent frame to start with" ")"); do { MOZ_CrashSequence
(__null, 5734); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5735
5736 *aIsAppend = false;
5737
5738 // Find the frame that precedes the insertion point.
5739 FlattenedChildIterator iter(aInsertion->mContainer);
5740 if (!aChild->IsRootOfNativeAnonymousSubtree()) {
5741 // The check for IsRootOfNativeAnonymousSubtree() is because editor is
5742 // severely broken and calls us directly for native anonymous
5743 // nodes that it creates.
5744 iter.Seek(aChild);
5745 } else {
5746 // Prime the iterator for the call to FindPreviousSibling.
5747 (void)iter.GetNextChild();
5748 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"
, 5750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5750); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5749 "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"
, 5750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5750); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
5750 "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"
, 5750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetProperty(nsGkAtoms::restylableAnonymousNode)"
") (" "Someone passed native anonymous content directly into frame "
"construction. Stop doing that!" ")"); do { MOZ_CrashSequence
(__null, 5750); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5751 }
5752
5753 // Note that FindPreviousSibling is passed the iterator by value, so that
5754 // the later usage of the iterator starts from the same place.
5755 nsIFrame* prevSibling = FindPreviousSibling(iter);
5756
5757 // Now, find the geometric parent so that we can handle continuations
5758 // properly. Use the prev sibling if we have it; otherwise use the next
5759 // sibling.
5760 if (prevSibling) {
5761 aInsertion->mParentFrame =
5762 prevSibling->GetParent()->GetContentInsertionFrame();
5763
5764 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5765 // Special-case anonymous flex / grid items: Elements are blockified
5766 // inside those containers, so the anonymous item is unlikely to be the
5767 // right parent unless we're inserting a non-whitespace text-node.
5768 //
5769 // If we guess wrong, we catch this in WipeContainingBlock, but with a
5770 // performance penalty (and sometimes correctness too, see bug 2014986).
5771 //
5772 // TODO(emilio): Are there other situations where this is worth doing
5773 // (some table anon boxes or something?). Seems hard to do at this stage
5774 // where we still don't _quite_ know the details of what aChild is (in or
5775 // out of flow, display inside or outside...). Maybe WipeContainingBlock
5776 // should be able to fix-up the insertion point at the last minute? But
5777 // that seems more sketchy since some code does rely on looking at the
5778 // insertion point to decide what to construct.
5779 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5780 if (!prevSibling->GetNextSibling() &&
5781 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5782 prevSibling = aInsertion->mParentFrame->GetTailContinuation();
5783 aInsertion->mParentFrame = prevSibling->GetParent();
5784 }
5785 }
5786
5787 *aIsAppend =
5788 !::GetInsertNextSibling(aInsertion->mParentFrame, prevSibling) &&
5789 !nsLayoutUtils::GetNextContinuationOrIBSplitSibling(
5790 aInsertion->mParentFrame) &&
5791 !IsWrapperPseudo(aInsertion->mParentFrame);
5792 } else if (nsIFrame* nextSibling = FindNextSibling(iter)) {
5793 // If there is no previous sibling, then find the frame that follows
5794 aInsertion->mParentFrame =
5795 nextSibling->GetParent()->GetContentInsertionFrame();
5796 if (IsAnonymousItem(aInsertion->mParentFrame)) {
5797 // See the prevSibling special-case above.
5798 AssertAnonymousFlexOrGridItemParent(aInsertion->mParentFrame);
5799 if (!nextSibling->GetPrevSibling() &&
5800 (!aChild->IsText() || aChild->TextIsOnlyWhitespace())) {
5801 aInsertion->mParentFrame =
5802 aInsertion->mParentFrame->FirstContinuation()->GetParent();
5803 }
5804 }
5805 } else {
5806 // No previous or next sibling, so treat this like an appended frame.
5807 *aIsAppend = true;
5808
5809 aInsertion->mParentFrame =
5810 ::ContinuationToAppendTo(aInsertion->mParentFrame);
5811
5812 prevSibling = aInsertion->mParentFrame->PrincipalChildList().LastChild();
5813 }
5814
5815 return prevSibling;
5816}
5817
5818nsContainerFrame* nsCSSFrameConstructor::GetContentInsertionFrameFor(
5819 nsIContent* aContent) {
5820 nsIFrame* frame;
5821 while (!(frame = aContent->GetPrimaryFrame())) {
5822 if (!IsDisplayContents(aContent)) {
5823 return nullptr;
5824 }
5825
5826 aContent = aContent->GetFlattenedTreeParent();
5827 if (!aContent) {
5828 return nullptr;
5829 }
5830 }
5831
5832 // If the content of the frame is not the desired content then this is not
5833 // really a frame for the desired content.
5834 // XXX This check is needed due to bug 135040. Remove it once that's fixed.
5835 if (frame->GetContent() != aContent) {
5836 return nullptr;
5837 }
5838
5839 nsContainerFrame* insertionFrame = frame->GetContentInsertionFrame();
5840
5841 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", 5843); MOZ_PretendNoReturn
(); } } while (0)
5842 "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", 5843); MOZ_PretendNoReturn
(); } } while (0)
5843 "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", 5843); MOZ_PretendNoReturn
(); } } while (0)
;
5844
5845 return insertionFrame;
5846}
5847
5848static bool IsSpecialFramesetChild(nsIContent* aContent) {
5849 // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
5850 return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
5851}
5852
5853static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode);
5854
5855void nsCSSFrameConstructor::AddTextItemIfNeeded(
5856 nsFrameConstructorState& aState, const ComputedStyle& aParentStyle,
5857 const InsertionPoint& aInsertion, nsIContent* aPossibleTextContent,
5858 FrameConstructionItemList& aItems) {
5859 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"
, 5859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPossibleTextContent"
") (" "Must have node" ")"); do { MOZ_CrashSequence(__null, 5859
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
5860 if (!aPossibleTextContent->IsText() ||
5861 !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5862 aPossibleTextContent->HasFlag(NODE_NEEDS_FRAME)) {
5863 // Not text, or not suppressed due to being all-whitespace (if it were being
5864 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5865 // going to be reframed anyway.
5866 return;
5867 }
5868 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", 5869
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5869 "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", 5869
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPossibleTextContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5870 AddFrameConstructionItems(aState, aPossibleTextContent, false, aParentStyle,
5871 aInsertion, aItems);
5872}
5873
5874void nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aContent) {
5875 if (!aContent->IsText() ||
5876 !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) ||
5877 aContent->HasFlag(NODE_NEEDS_FRAME)) {
5878 // Not text, or not suppressed due to being all-whitespace (if it were being
5879 // suppressed, it would have the NS_CREATE_FRAME_IF_NON_WHITESPACE flag), or
5880 // going to be reframed anyway.
5881 return;
5882 }
5883 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", 5884
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5884 "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", 5884
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContent->GetPrimaryFrame()"
") (" "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"
")"); do { MOZ_CrashSequence(__null, 5884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5885 ContentInserted(aContent, InsertionKind::Async);
5886}
5887
5888#ifdef DEBUG1
5889void nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(
5890 nsIContent* aParent) {
5891 // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
5892 // we want to assert, but leaf frames that process their own children and may
5893 // ignore anonymous children (eg framesets) make this complicated. So we set
5894 // these two booleans if we encounter these situations and unset them if we
5895 // hit a node with a leaf frame.
5896 //
5897 // It's fine if one of node without primary frame is in a display:none
5898 // subtree.
5899 //
5900 // Also, it's fine if one of the nodes without primary frame is a display:
5901 // contents node.
5902 bool noPrimaryFrame = false;
5903 bool needsFrameBitSet = false;
5904 nsIContent* content = aParent;
5905 while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
5906 if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
5907 noPrimaryFrame = needsFrameBitSet = false;
5908 }
5909 if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
5910 noPrimaryFrame = !IsDisplayContents(content);
5911 }
5912 if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
5913 needsFrameBitSet = true;
5914 }
5915
5916 content = content->GetFlattenedTreeParent();
5917 }
5918 if (content && content->GetPrimaryFrame() &&
5919 content->GetPrimaryFrame()->IsLeaf()) {
5920 noPrimaryFrame = needsFrameBitSet = false;
5921 }
5922 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", 5924
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5924); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5923 "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", 5924
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5924); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5924 "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", 5924
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!noPrimaryFrame" ") ("
"Ancestors of nodes with frames to be " "constructed lazily should have frames"
")"); do { MOZ_CrashSequence(__null, 5924); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5925 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", 5927
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5927); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5926 "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", 5927
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5927); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5927 "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", 5927
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!needsFrameBitSet"
") (" "Ancestors of nodes with frames to be " "constructed lazily should not have NEEDS_FRAME bit set"
")"); do { MOZ_CrashSequence(__null, 5927); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5928}
5929#endif
5930
5931// Returns true if this operation can be lazy, false if not.
5932//
5933// NOTE(emilio): This function assumes that the flattened tree
5934// parent of all the appended children is the same, which holds because this
5935// gets called after GetRangeInsertionPoint which notifies individually.
5936void nsCSSFrameConstructor::ConstructLazily(nsIContent* aStartChild,
5937 nsIContent* aEndChild) {
5938 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", 5938); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aStartChild->GetParent()" ")"); do { MOZ_CrashSequence
(__null, 5938); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
5939
5940 // We can construct lazily; just need to set suitable bits in the content
5941 // tree.
5942 Element* parent = aStartChild->GetFlattenedTreeParentElement();
5943 if (!parent) {
5944 // Not part of the flat tree, nothing to do.
5945 return;
5946 }
5947
5948 if (Servo_Element_IsDisplayNone(parent)) {
5949 // Nothing to do either.
5950 //
5951 // FIXME(emilio): This should be an assert, except for weird <frameset>
5952 // stuff that does its own frame construction. Such an assert would fire in
5953 // layout/style/crashtests/1411478.html, for example.
5954 return;
5955 }
5956
5957 // Set NODE_NEEDS_FRAME on the new nodes.
5958 for (nsIContent* child = aStartChild; child != aEndChild;
5959 child = child->GetNextSibling()) {
5960 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", 5965); MOZ_PretendNoReturn
(); } } while (0)
5961 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", 5965); MOZ_PretendNoReturn
(); } } while (0)
5962 // 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", 5965); MOZ_PretendNoReturn
(); } } while (0)
5963 // 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", 5965); MOZ_PretendNoReturn
(); } } while (0)
5964 // 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", 5965); MOZ_PretendNoReturn
(); } } while (0)
5965 "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", 5965); MOZ_PretendNoReturn
(); } } while (0)
;
5966 child->SetFlags(NODE_NEEDS_FRAME);
5967 }
5968
5969 CheckBitsForLazyFrameConstruction(parent);
5970 parent->NoteDescendantsNeedFramesForServo();
5971}
5972
5973void nsCSSFrameConstructor::IssueSingleInsertNofications(
5974 nsIContent* aStartChild, nsIContent* aEndChild,
5975 InsertionKind aInsertionKind) {
5976 for (nsIContent* child = aStartChild; child != aEndChild;
5977 child = child->GetNextSibling()) {
5978 // XXX the GetContent() != child check is needed due to bug 135040.
5979 // Remove it once that's fixed.
5980 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", 5981); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
")"); do { MOZ_CrashSequence(__null, 5981); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5981 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", 5981); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!child->GetPrimaryFrame() || child->GetPrimaryFrame()->GetContent() != child"
")"); do { MOZ_CrashSequence(__null, 5981); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5982
5983 // Call ContentRangeInserted with this node.
5984 ContentRangeInserted(child, child->GetNextSibling(), aInsertionKind);
5985 }
5986}
5987
5988nsCSSFrameConstructor::InsertionPoint
5989nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aStartChild,
5990 nsIContent* aEndChild,
5991 InsertionKind aInsertionKind) {
5992 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"
, 5992); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
")"); do { MOZ_CrashSequence(__null, 5992); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5993 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"
, 5993); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 5993); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5994
5995 // If the children of the container may be distributed to different insertion
5996 // points, insert them separately and bail out, letting ContentInserted handle
5997 // the mess.
5998 if (aStartChild->GetParentNode()->GetShadowRoot()) {
5999 IssueSingleInsertNofications(aStartChild, aEndChild, aInsertionKind);
6000 return {};
6001 }
6002
6003#ifdef DEBUG1
6004 {
6005 nsIContent* expectedParent = aStartChild->GetFlattenedTreeParent();
6006 for (nsIContent* child = aStartChild->GetNextSibling(); child;
6007 child = child->GetNextSibling()) {
6008 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"
, 6008); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->GetFlattenedTreeParent() == expectedParent"
")"); do { MOZ_CrashSequence(__null, 6008); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6009 }
6010 }
6011#endif
6012
6013 // Now the flattened tree parent of all the siblings is the same, just use the
6014 // same insertion point.
6015 return GetInsertionPoint(aStartChild);
6016}
6017
6018bool nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6019 nsIContent* aStartChild,
6020 nsIContent* aEndChild) {
6021 if (aParentFrame->IsFrameSetFrame()) {
6022 // Check whether we have any kids we care about.
6023 for (nsIContent* cur = aStartChild; cur != aEndChild;
6024 cur = cur->GetNextSibling()) {
6025 if (IsSpecialFramesetChild(cur)) {
6026 // Just reframe the parent, since framesets are weird like that.
6027 RecreateFramesForContent(aParentFrame->GetContent(),
6028 InsertionKind::Async);
6029 return true;
6030 }
6031 }
6032 }
6033 return false;
6034}
6035
6036void nsCSSFrameConstructor::LazilyStyleNewChildRange(nsIContent* aStartChild,
6037 nsIContent* aEndChild) {
6038 for (nsIContent* child = aStartChild; child != aEndChild;
6039 child = child->GetNextSibling()) {
6040 if (child->IsElement()) {
6041 child->AsElement()->NoteDirtyForServo();
6042 }
6043 }
6044}
6045
6046#ifdef DEBUG1
6047static bool IsFlattenedTreeChild(nsIContent* aParent, nsIContent* aChild) {
6048 FlattenedChildIterator iter(aParent);
6049 for (nsIContent* node = iter.GetNextChild(); node;
6050 node = iter.GetNextChild()) {
6051 if (node == aChild) {
6052 return true;
6053 }
6054 }
6055 return false;
6056}
6057#endif
6058
6059void nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
6060 nsIContent* aEndChild) {
6061 ServoStyleSet* styleSet = mPresShell->StyleSet();
6062
6063 for (nsIContent* child = aStartChild; child != aEndChild;
6064 child = child->GetNextSibling()) {
6065 if (!child->IsElement()) {
6066 continue;
6067 }
6068
6069 Element* childElement = child->AsElement();
6070
6071 // We only come in here from non-lazy frame construction, so the children
6072 // should be unstyled.
6073 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"
, 6073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!childElement->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 6073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6074
6075#ifdef DEBUG1
6076 {
6077 // Furthermore, all of them should have the same flattened tree parent
6078 // (GetRangeInsertionPoint ensures it). And that parent should be styled,
6079 // otherwise we would've never found an insertion point at all.
6080 Element* parent = childElement->GetFlattenedTreeParentElement();
6081 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"
, 6081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent" ")"
); do { MOZ_CrashSequence(__null, 6081); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6082 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", 6082); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parent->HasServoData()" ")"); do { MOZ_CrashSequence
(__null, 6082); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6083 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", 6085
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6085); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6084 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", 6085
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6085); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6085 "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", 6085
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFlattenedTreeChild(parent, child)"
") (" "GetFlattenedTreeParent and ChildIterator don't agree, fix this!"
")"); do { MOZ_CrashSequence(__null, 6085); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6086 }
6087#endif
6088
6089 styleSet->StyleNewSubtree(childElement);
6090 }
6091}
6092
6093// This is a bit slow, but sometimes we need it.
6094static bool ParentIsWrapperAnonBox(nsIFrame* aParent) {
6095 nsIFrame* maybeAnonBox = aParent;
6096 if (maybeAnonBox->Style()->GetPseudoType() ==
6097 PseudoStyleType::MozCellContent) {
6098 // The thing that would maybe be a wrapper anon box is the cell.
6099 maybeAnonBox = maybeAnonBox->GetParent();
6100 }
6101 return maybeAnonBox->Style()->IsWrapperAnonBox();
6102}
6103
6104void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
6105 InsertionKind aInsertionKind) {
6106 return ContentRangeInserted(aFirstNewContent, nullptr, aInsertionKind);
6107}
6108
6109void nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
6110 InsertionKind aInsertionKind) {
6111 ContentRangeInserted(aChild, aChild->GetNextSibling(), aInsertionKind);
6112}
6113
6114// It's very likely that we don't have any existing captions (because we only
6115// render one of them, see bug 144517). We also don't fragment table captions.
6116// So, prefer just walking the existing captions and searching it, rather than
6117// adding a special GetInsertionPrevSibling() version that skips everything but
6118// table captions.
6119static nsIFrame* FindCaptionPrevSibling(nsTableWrapperFrame* aTable,
6120 nsIContent* aCaptionContent) {
6121 nsIFrame* prevSibling = aTable->InnerTableFrame();
6122 if (nsIFrame* firstCaption = prevSibling->GetNextSibling()) {
6123 nsContentUtils::NodeIndexCache cache;
6124 for (auto* caption = firstCaption; caption;
6125 caption = caption->GetNextSibling()) {
6126 if (nsContentUtils::CompareTreePosition<TreeKind::Flat>(
6127 caption->GetContent(), aCaptionContent, nullptr, &cache) >= 0) {
6128 break;
6129 }
6130 prevSibling = caption;
6131 }
6132 }
6133 return prevSibling;
6134}
6135
6136// ContentRangeInserted handles creating frames for a range of nodes that
6137// might not be at the end of their childlist. ContentRangeInserted isn't a real
6138// content notification, but rather it handles regular ContentInserted calls
6139// for a single node as well as the lazy construction of frames for a range of
6140// nodes when called from CreateNeededFrames. For a range of nodes to be
6141// suitable to have its frames constructed all at once they must meet the same
6142// conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6143// these), plus more.
6144void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
6145 nsIContent* aEndChild,
6146 InsertionKind aInsertionKind) {
6147 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRangeInserted",mozilla::AutoProfilerLabelHot raiiObject6148( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6148 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6148( "nsCSSFrameConstructor::ContentRangeInserted"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6149 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6150
6151 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"
, 6151); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartChild"
") (" "must always pass a child" ")"); do { MOZ_CrashSequence
(__null, 6151); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6152
6153#ifdef DEBUG1
6154 if (gNoisyContentUpdates) {
6155 printf(
6156 "nsCSSFrameConstructor::ContentRangeInserted container=%p "
6157 "start-child=%p end-child=%p lazy=%d\n",
6158 aStartChild->GetParent(), aStartChild, aEndChild,
6159 aInsertionKind == InsertionKind::Async);
6160 if (gReallyNoisyContentUpdates) {
6161 if (aStartChild->GetParent()) {
6162 aStartChild->GetParent()->List(stdoutstdout, 0);
6163 } else {
6164 aStartChild->List(stdoutstdout, 0);
6165 }
6166 }
6167 }
6168
6169 for (nsIContent* child = aStartChild; child != aEndChild;
6170 child = child->GetNextSibling()) {
6171 // XXX the GetContent() != child check is needed due to bug 135040.
6172 // Remove it once that's fixed.
6173 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", 6176
); 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, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6174 !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", 6176
); 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, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6175 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", 6176
); 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, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6176 "asked to construct a frame for a node that already has a frame")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!child->GetPrimaryFrame() || 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", 6176
); 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, 6176); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6177 }
6178#endif
6179
6180 // If we have a null parent, then this must be the document element being
6181 // inserted, or some other child of the document in the DOM (might be a
6182 // processing instruction or comment).
6183 if (!aStartChild->GetParent()) {
6184 Element* docElement = mDocument->GetRootElement();
6185 const bool foundRoot = [&] {
6186 for (nsIContent* cur = aStartChild; cur != aEndChild;
6187 cur = cur->GetNextSibling()) {
6188 if (cur == docElement) {
6189 return true;
6190 }
6191 }
6192 return false;
6193 }();
6194
6195 if (!foundRoot) {
6196 // Not the root element (could be e.g. a comment), just bail out
6197 return;
6198 }
6199
6200 MOZ_ASSERT(!mRootElementFrame, "root element frame already created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRootElementFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRootElementFrame))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mRootElementFrame"
" (" "root element frame already created" ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 6200); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRootElementFrame"
") (" "root element frame already created" ")"); do { MOZ_CrashSequence
(__null, 6200); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6201 if (aInsertionKind == InsertionKind::Async) {
6202 docElement->SetFlags(NODE_NEEDS_FRAME);
6203 LazilyStyleNewChildRange(docElement, nullptr);
6204 return;
6205 }
6206
6207 // Create frames for the document element and its child elements
6208 if (ConstructDocElementFrame(docElement)) {
6209 InvalidateCanvasIfNeeded(mPresShell, docElement);
6210#ifdef DEBUG1
6211 if (gReallyNoisyContentUpdates) {
6212 printf(
6213 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6214 "model:\n");
6215 mRootElementFrame->List(stdoutstdout);
6216 }
6217#endif
6218 }
6219
6220#ifdef ACCESSIBILITY1
6221 if (nsAccessibilityService* accService = GetAccService()) {
6222 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6223 }
6224#endif
6225 return;
6226 }
6227
6228 const bool isSingleInsert = aStartChild->GetNextSibling() == aEndChild;
6229 InsertionPoint insertion;
6230 if (isSingleInsert) {
6231 // See if we have a Shadow DOM insertion point. If so, then that's our real
6232 // parent frame; if not, then the frame hasn't been built yet and we just
6233 // bail.
6234 insertion = GetInsertionPoint(aStartChild);
6235 } else {
6236 // Get our insertion point. If we need to issue single ContentInserteds
6237 // GetRangeInsertionPoint will take care of that for us.
6238 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6239 insertion = GetRangeInsertionPoint(aStartChild, aEndChild, aInsertionKind);
6240 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6241 }
6242
6243 if (!insertion.mParentFrame) {
6244 // We're punting on frame construction because there's no container frame.
6245 // The Servo-backed style system handles this case like the lazy frame
6246 // construction case, except when we're already constructing frames, in
6247 // which case we shouldn't need to do anything else.
6248 if (aInsertionKind == InsertionKind::Async) {
6249 LazilyStyleNewChildRange(aStartChild, aEndChild);
6250 }
6251 return;
6252 }
6253
6254 if (aInsertionKind == InsertionKind::Async) {
6255 ConstructLazily(aStartChild, aEndChild);
6256 LazilyStyleNewChildRange(aStartChild, aEndChild);
6257 return;
6258 }
6259
6260 bool isAppend;
6261 nsIFrame* prevSibling =
6262 GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6263
6264 LayoutFrameType frameType = insertion.mParentFrame->Type();
6265 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6266 if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild,
6267 aEndChild)) {
6268 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6269 return;
6270 }
6271 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6272
6273 // Don't construct kids of leaves
6274 if (insertion.mParentFrame->IsLeaf()) {
6275 // Clear lazy bits so we don't try to construct again.
6276 ClearLazyBits(aStartChild, aEndChild);
6277 return;
6278 }
6279
6280 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6281 if (WipeInsertionParent(insertion.mParentFrame)) {
6282 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6283 return;
6284 }
6285 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6286
6287 nsFrameConstructorState state(
6288 mPresShell, GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
6289 GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
6290 GetFloatContainingBlock(insertion.mParentFrame),
6291 do_AddRef(mFrameTreeState));
6292
6293 // Recover state for the containing block - we need to know if
6294 // it has :first-letter or :first-line style applied to it. The
6295 // reason we care is that the internal structure in these cases
6296 // is not the normal structure and requires custom updating
6297 // logic.
6298 nsContainerFrame* containingBlock = state.mFloatedList.mContainingBlock;
6299 bool haveFirstLetterStyle = false;
6300 bool haveFirstLineStyle = false;
6301
6302 // In order to shave off some cycles, we only dig up the
6303 // containing block haveFirst* flags if the parent frame where
6304 // the insertion/append is occurring is an inline or block
6305 // container. For other types of containers this isn't relevant.
6306 StyleDisplayInside parentDisplayInside =
6307 insertion.mParentFrame->StyleDisplay()->DisplayInside();
6308
6309 // Examine the insertion.mParentFrame where the insertion is taking
6310 // place. If it's a certain kind of container then some special
6311 // processing is done.
6312 if (StyleDisplayInside::Flow == parentDisplayInside) {
6313 // Recover the special style flags for the containing block
6314 if (containingBlock) {
6315 haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
6316 haveFirstLineStyle = ShouldHaveFirstLineStyle(
6317 containingBlock->GetContent(), containingBlock->Style());
6318 }
6319
6320 if (haveFirstLetterStyle) {
6321 // If our current insertion.mParentFrame is a Letter frame, use its parent
6322 // as our new parent hint
6323 if (insertion.mParentFrame->IsLetterFrame()) {
6324 // If insertion.mParentFrame is out of flow, then we actually want the
6325 // parent of the placeholder frame.
6326 if (insertion.mParentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6327 nsPlaceholderFrame* placeholderFrame =
6328 insertion.mParentFrame->GetPlaceholderFrame();
6329 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"
, 6329); MOZ_PretendNoReturn(); } } while (0)
;
6330 insertion.mParentFrame = placeholderFrame->GetParent();
6331 } else {
6332 insertion.mParentFrame = insertion.mParentFrame->GetParent();
6333 }
6334 }
6335
6336 // Remove the old letter frames before doing the insertion
6337 RemoveLetterFrames(mPresShell, state.mFloatedList.mContainingBlock);
6338
6339 // Removing the letterframes messes around with the frame tree, removing
6340 // and creating frames. We need to reget our prevsibling, parent frame,
6341 // etc.
6342 prevSibling = GetInsertionPrevSibling(&insertion, aStartChild, &isAppend);
6343 frameType = insertion.mParentFrame->Type();
6344 }
6345 }
6346
6347 // This handles fallback to 'list-style-type' when a 'list-style-image' fails
6348 // to load.
6349 if (aStartChild->IsInNativeAnonymousSubtree() &&
6350 aStartChild->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
6351 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", 6351); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "isSingleInsert" ")"); do { MOZ_CrashSequence
(__null, 6351); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6352 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"
, 6354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6354); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6353 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"
, 6354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6354); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6354 "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"
, 6354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mParentFrame->Style()->GetPseudoType() == PseudoStyleType::Marker"
") (" "we can only handle ::marker fallback for now" ")"); do
{ MOZ_CrashSequence(__null, 6354); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6355 nsIContent* const nextSibling = aStartChild->GetNextSibling();
6356 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", 6357
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6357); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6357 "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", 6357
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextSibling && nextSibling->IsText()"
") (" "expected a text node after the list-style-image image"
")"); do { MOZ_CrashSequence(__null, 6357); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6358 DestroyContext context(mPresShell);
6359 RemoveFrame(context, FrameChildListID::Principal,
6360 nextSibling->GetPrimaryFrame());
6361 auto* const container = aStartChild->GetParent()->AsElement();
6362 nsIContent* firstNewChild = nullptr;
6363 auto InsertChild = [this, container, nextSibling,
6364 &firstNewChild](RefPtr<nsIContent>&& aChild) {
6365 // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
6366 // here; it would get set under AppendChildTo. But AppendChildTo might
6367 // think that we're going from not being anonymous to being anonymous and
6368 // do some extra work; setting the flag here avoids that.
6369 aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
6370 container->InsertChildBefore(aChild, nextSibling, false, IgnoreErrors());
6371 if (auto* childElement = Element::FromNode(aChild)) {
6372 // If we created any children elements, Servo needs to traverse them,
6373 // but the root is already set up.
6374 mPresShell->StyleSet()->StyleNewSubtree(childElement);
6375 }
6376 if (!firstNewChild) {
6377 firstNewChild = aChild;
6378 }
6379 };
6380 CreateGeneratedContentFromListStyleType(
6381 state, *insertion.mContainer->AsElement(),
6382 *insertion.mParentFrame->Style(), InsertChild);
6383 if (!firstNewChild) {
6384 // No fallback content - we're done.
6385 return;
6386 }
6387 aStartChild = firstNewChild;
6388 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"
, 6389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6389); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
6389 "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"
, 6389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstNewChild->GetNextSibling() == nextSibling"
") (" "list-style-type should only create one child" ")"); do
{ MOZ_CrashSequence(__null, 6389); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6390 }
6391
6392 AutoFrameConstructionItemList items(this);
6393 RefPtr<ComputedStyle> parentStyle =
6394 ResolveComputedStyle(insertion.mContainer);
6395 ParentType parentType = GetParentType(frameType);
6396 FlattenedChildIterator iter(insertion.mContainer);
6397 const bool haveNoShadowDOM =
6398 !iter.ShadowDOMInvolved() || !iter.GetNextChild();
6399 if (aStartChild->GetPreviousSibling() && parentType == eTypeBlock &&
6400 haveNoShadowDOM) {
6401 // If there's a text node in the normal content list just before the
6402 // new nodes, and it has no frame, make a frame construction item for
6403 // it, because it might need a frame now. No need to do this if our
6404 // parent type is not block, though, since WipeContainingBlock
6405 // already handles that situation.
6406 AddTextItemIfNeeded(state, *parentStyle, insertion,
6407 aStartChild->GetPreviousSibling(), items);
6408 }
6409
6410 const bool suppressWhiteSpaceOptimizations =
6411 isSingleInsert && aStartChild->IsRootOfNativeAnonymousSubtree();
6412 for (nsIContent* child = aStartChild; child != aEndChild;
6413 child = child->GetNextSibling()) {
6414 AddFrameConstructionItems(state, child, suppressWhiteSpaceOptimizations,
6415 *parentStyle, insertion, items);
6416 }
6417
6418 if (aEndChild && parentType == eTypeBlock && haveNoShadowDOM) {
6419 // If there's a text node in the normal content list just after the
6420 // new nodes, and it has no frame, make a frame construction item for
6421 // it, because it might need a frame now. No need to do this if our
6422 // parent type is not block, though, since WipeContainingBlock
6423 // already handles that situation.
6424 AddTextItemIfNeeded(state, *parentStyle, insertion, aEndChild, items);
6425 }
6426
6427 // Perform special check for diddling around with the frames in a special
6428 // inline frame. If we're appending before :after content, then we're not
6429 // really appending, so let WipeContainingBlock know that.
6430 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6431 if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
6432 isAppend, prevSibling)) {
6433 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6434 return;
6435 }
6436 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6437
6438 // If the parent is a block frame, and we're not in a special case
6439 // where frames can be moved around, determine if the list is for the
6440 // start or end of the block.
6441 if (insertion.mParentFrame->IsBlockFrameOrSubclass() &&
6442 !haveFirstLetterStyle && !haveFirstLineStyle &&
6443 !IsFramePartOfIBSplit(insertion.mParentFrame)) {
6444 items.SetLineBoundaryAtStart(!prevSibling ||
6445 !prevSibling->IsInlineOutside() ||
6446 prevSibling->IsBrFrame());
6447 auto* nextSibling =
6448 ::GetInsertNextSibling(insertion.mParentFrame, prevSibling);
6449 items.SetLineBoundaryAtEnd(!nextSibling ||
6450 !nextSibling->IsInlineOutside() ||
6451 nextSibling->IsBrFrame());
6452 }
6453 // To suppress whitespace-only text frames, we have to verify that
6454 // our container's DOM child list matches its flattened tree child list.
6455 items.SetParentHasNoShadowDOM(haveNoShadowDOM);
6456
6457 nsFrameConstructorSaveState floatSaveState;
6458 state.MaybePushFloatContainingBlock(insertion.mParentFrame, floatSaveState);
6459
6460 if (state.mPresContext->IsPaginated()) {
6461 // Because this function can be called outside frame construction, we need
6462 // to set state.mAutoPageNameValue based on what the parent frame's auto
6463 // value is.
6464 // Calling this from outside the frame constructor can violate many of the
6465 // expectations in AutoFrameConstructionPageName, and unlike during frame
6466 // construction we already have an auto value from parentFrame, so we do
6467 // not use AutoFrameConstructionPageName here.
6468 state.mAutoPageNameValue = insertion.mParentFrame->GetAutoPageValue();
6469#ifdef DEBUG1
6470 insertion.mParentFrame->mWasVisitedByAutoFrameConstructionPageName = true;
6471#endif
6472 }
6473
6474 // If the container is a table and a caption will be appended, it needs to be
6475 // put in the table wrapper frame's additional child list.
6476 // We make no attempt here to set flags to indicate whether the list
6477 // will be at the start or end of a block. It doesn't seem worthwhile.
6478 nsFrameList frameList, captionList;
6479 ConstructFramesFromItemList(state, items, insertion.mParentFrame,
6480 ParentIsWrapperAnonBox(insertion.mParentFrame),
6481 frameList);
6482
6483 if (frameList.NotEmpty()) {
6484 for (nsIContent* child = aStartChild; child != aEndChild;
6485 child = child->GetNextSibling()) {
6486 InvalidateCanvasIfNeeded(mPresShell, child);
6487 }
6488
6489 if (LayoutFrameType::Table == frameType ||
6490 LayoutFrameType::TableWrapper == frameType) {
6491 PullOutCaptionFrames(frameList, captionList);
6492 if (prevSibling && prevSibling->IsTableCaption()) {
6493 // This can happen, but only if the table is empty (otherwise
6494 // SafeToInsertPseudoNeedingChildren bails).
6495 prevSibling = nullptr;
6496 }
6497 }
6498 }
6499
6500 if (haveFirstLineStyle && insertion.mParentFrame == containingBlock &&
6501 isAppend) {
6502 // It's possible that the new frame goes into a first-line
6503 // frame. Look at it and see...
6504 AppendFirstLineFrames(state, containingBlock->GetContent(), containingBlock,
6505 frameList);
6506 } else if (insertion.mParentFrame->Style()->IsInFirstLineSubtree()) {
6507 CheckForFirstLineInsertion(insertion.mParentFrame, frameList);
6508 CheckForFirstLineInsertion(insertion.mParentFrame, captionList);
6509 }
6510
6511 // We might have captions; put them into the principal child list of the table
6512 // wrapper frame.
6513 if (captionList.NotEmpty()) {
6514 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", 6516); MOZ_PretendNoReturn
(); } } while (0)
6515 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", 6516); MOZ_PretendNoReturn
(); } } while (0)
6516 "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", 6516); MOZ_PretendNoReturn
(); } } while (0)
;
6517 // We need to determine where to put the caption items; start with the
6518 // the parent frame that has already been determined and get the insertion
6519 // prevsibling of the first caption item.
6520 nsContainerFrame* outerTable = insertion.mParentFrame->IsTableFrame()
6521 ? insertion.mParentFrame->GetParent()
6522 : insertion.mParentFrame;
6523
6524 // If the parent is not a table wrapper frame we will try to add frames
6525 // to a named child list that the parent does not honor and the frames
6526 // will get lost.
6527 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", 6529); 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, 6529); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6528 "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", 6529); 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, 6529); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6529 "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", 6529); 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, 6529); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6530
6531 nsIFrame* captionPrevSibling =
6532 FindCaptionPrevSibling(static_cast<nsTableWrapperFrame*>(outerTable),
6533 captionList.FirstChild()->GetContent());
6534 captionList.ApplySetParent(outerTable);
6535 if (!captionPrevSibling->GetNextSibling()) {
6536 AppendFrames(outerTable, FrameChildListID::Principal,
6537 std::move(captionList));
6538 } else {
6539 InsertFrames(outerTable, FrameChildListID::Principal, captionPrevSibling,
6540 std::move(captionList));
6541 }
6542 }
6543
6544 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6545 if (MaybeRecreateForColumnSpan(state, insertion.mParentFrame, frameList,
6546 prevSibling)) {
6547 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6548 return;
6549 }
6550 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6551
6552 if (frameList.NotEmpty()) {
6553 // Notify the parent frame
6554 if (isAppend) {
6555 AppendFramesToParent(state, insertion.mParentFrame, frameList,
6556 prevSibling);
6557 } else {
6558 InsertFrames(insertion.mParentFrame, FrameChildListID::Principal,
6559 prevSibling, std::move(frameList));
6560 }
6561 }
6562
6563 if (haveFirstLetterStyle) {
6564 // Recover the letter frames for the containing block when
6565 // it has first-letter style.
6566 RecoverLetterFrames(state.mFloatedList.mContainingBlock);
6567 }
6568
6569#ifdef DEBUG1
6570 if (gReallyNoisyContentUpdates && insertion.mParentFrame) {
6571 printf(
6572 "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6573 "model:\n");
6574 insertion.mParentFrame->List(stdoutstdout);
6575 }
6576#endif
6577
6578#ifdef ACCESSIBILITY1
6579 if (nsAccessibilityService* accService = GetAccService()) {
6580 accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
6581 }
6582#endif
6583}
6584
6585static bool IsWhitespaceFrame(const nsIFrame* aFrame) {
6586 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", 6586
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 6586); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6587 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
6588}
6589
6590static bool IsSyntheticColGroup(const nsIFrame* aFrame) {
6591 return aFrame->IsTableColGroupFrame() &&
6592 static_cast<const nsTableColGroupFrame*>(aFrame)->IsSynthetic();
6593}
6594
6595static bool IsOnlyNonWhitespaceFrameInList(
6596 const nsFrameList& aFrameList, const nsIFrame* aFrame,
6597 const nsIFrame* aIgnoreFrame = nullptr) {
6598 for (const nsIFrame* f : aFrameList) {
6599 if (f == aIgnoreFrame) {
6600 continue;
6601 }
6602 if (f == aFrame) {
6603 // If we have continuations, ignore them too.
6604 aFrame = aFrame->GetNextContinuation();
6605 } else if (!IsWhitespaceFrame(f) && !IsSyntheticColGroup(f)) {
6606 // Synthetic colgroups get created unconditionally, so let's not consider
6607 // them as giving us a non-whitespace frame.
6608 return false;
6609 }
6610 }
6611 return true;
6612}
6613
6614static bool AllChildListsAreEffectivelyEmpty(nsIFrame* aFrame) {
6615 for (auto& [list, listID] : aFrame->ChildLists()) {
6616 if (list.IsEmpty()) {
6617 continue;
6618 }
6619 // We have some existing frame, usually that would be considered as making
6620 // this list nonempty. But let's make an exception for the synthetic
6621 // colgroup that tables have, since that gets created unconditionally.
6622 if (listID == FrameChildListID::Principal && aFrame->IsTableFrame()) {
6623 if (nsIFrame* f = list.OnlyChild(); f && IsSyntheticColGroup(f)) {
6624 continue;
6625 }
6626 }
6627 return false;
6628 }
6629 return true;
6630}
6631
6632static bool SafeToInsertPseudoNeedingChildren(nsIFrame* aFrame) {
6633 return AllChildListsAreEffectivelyEmpty(aFrame);
6634}
6635
6636// Returns true if aFrame is the only meaningful child of aParent (which is
6637// known to be a wrapper-pseudo). This lets us determine whether aParent can be
6638// removed, as a result of aFrame being removed.
6639static bool IsOnlyMeaningfulChildOfWrapperPseudo(nsIFrame* aFrame,
6640 nsIFrame* aParent) {
6641 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", 6641); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "IsWrapperPseudo(aParent)" ")"); do { MOZ_CrashSequence
(__null, 6641); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6642 // Handle a few special cases with tables and colgroups / captions.
6643 if (aParent->IsTableFrame()) {
6644 auto* wrapper = aParent->GetParent();
6645 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"
, 6645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper" ")"
); do { MOZ_CrashSequence(__null, 6645); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6646 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"
, 6646); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wrapper->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6646); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6647 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", 6648
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6648); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6648 "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", 6648
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "Caption parent should be the wrapper" ")"); do { MOZ_CrashSequence
(__null, 6648); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6649 // We can't remove the table if there are any captions present (captions are
6650 // never anonymous themselves), because table wrapper always relies on
6651 // having a table frame.
6652 if (!wrapper->PrincipalChildList().OnlyChild()) {
6653 return false;
6654 }
6655 }
6656 if (aFrame->IsTableCaption()) {
6657 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"
, 6657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 6657); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6658 auto* table = static_cast<nsTableWrapperFrame*>(aParent)->InnerTableFrame();
6659 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"
, 6659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "table" ")")
; do { MOZ_CrashSequence(__null, 6659); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6660 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame,
6661 /* aIgnoreFrame = */ table) &&
6662 // This checks for both colgroups and the principal list of the table
6663 // frame.
6664 AllChildListsAreEffectivelyEmpty(table);
6665 }
6666 return IsOnlyNonWhitespaceFrameInList(aParent->PrincipalChildList(), aFrame);
6667}
6668
6669static bool CanRemoveWrapperPseudoForChildRemoval(nsIFrame* aFrame,
6670 nsIFrame* aParent) {
6671 if (!IsOnlyMeaningfulChildOfWrapperPseudo(aFrame, aParent)) {
6672 return false;
6673 }
6674 if (aParent->GetPrevContinuation() || aParent->GetNextContinuation()) {
6675 // If our parent is fragmented we're not really the only meaningful child.
6676 return false;
6677 }
6678 if (aParent->IsRubyBaseContainerFrame()) {
6679 // We can't remove the first ruby base container of a ruby frame unless
6680 // it has no siblings. See CreateNeededPseudoSiblings.
6681 return aParent->GetPrevSibling() || !aParent->GetNextSibling();
6682 }
6683 return true;
6684}
6685
6686bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild,
6687 RemovalKind aKind) {
6688 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"
, 6688); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 6688); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6689 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"
, 6691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6691); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6690 !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"
, 6691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6691); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
6691 "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"
, 6691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aChild->IsRootOfNativeAnonymousSubtree() || !aChild->GetNextSibling()"
") (" "Anonymous roots don't have siblings" ")"); do { MOZ_CrashSequence
(__null, 6691); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6692 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentWillBeRemoved",mozilla::AutoProfilerLabelHot raiiObject6693( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
6693 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject6693( "nsCSSFrameConstructor::ContentWillBeRemoved"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
6694 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
6695 nsPresContext* presContext = mPresShell->GetPresContext();
6696 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"
, 6696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Our presShell should have a valid presContext" ")"); do
{ MOZ_CrashSequence(__null, 6696); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
6697
6698 const bool wasRemovingContent = mRemovingContent;
6699 auto _ = MakeScopeExit([&] { mRemovingContent = wasRemovingContent; });
6700 mRemovingContent = true;
6701
6702 // We want to detect when the viewport override element stored in the
6703 // prescontext is in the subtree being removed. Except in fullscreen cases
6704 // (which are handled in Element::UnbindFromTree and do not get stored on the
6705 // prescontext), the override element is always either the root element or a
6706 // <body> child of the root element. So we can only be removing the stored
6707 // override element if the thing being removed is either the override element
6708 // itself or the root element (which can be a parent of the override element).
6709 //
6710 // The !wasRemovingContent check makes sure that we don't re-enter here from
6711 // other ContentWillBeRemoved calls, as that'd be useless work, and we don't
6712 // want to incorrectly pick aChild again as our viewport scroll style element
6713 // if it's getting removed from the DOM.
6714 if ((aChild == presContext->GetViewportScrollStylesOverrideElement() ||
6715 aChild->IsRootElement()) &&
6716 !wasRemovingContent) {
6717 // We might be removing the element that we propagated viewport scrollbar
6718 // styles from. Recompute those. (This clause covers two of the three
6719 // possible scrollbar-propagation sources: the <body> [as aChild or a
6720 // descendant] and the root node. The other possible scrollbar-propagation
6721 // source is a fullscreen element, and we have code elsewhere to update
6722 // scrollbars after fullscreen elements are removed -- specifically, it's
6723 // part of the fullscreen cleanup code called by Element::UnbindFromTree.
6724 // We don't handle the fullscreen case here, because it doesn't change the
6725 // scrollbar styles override element stored on the prescontext.)
6726 const Element* removingElement =
6727 aKind == RemovalKind::Dom ? aChild->AsElement() : nullptr;
6728 Element* newOverrideElement =
6729 presContext->UpdateViewportScrollStylesOverride(removingElement);
6730
6731 // If aChild is the root, then we don't need to do any reframing of
6732 // newOverrideElement, because we're about to tear down the whole frame tree
6733 // anyway. And we need to make sure we don't do any such reframing, because
6734 // reframing the <body> can trigger a reframe of the <html> and then reenter
6735 // here.
6736 //
6737 // But if aChild is not the root, and if newOverrideElement is not the root
6738 // and isn't aChild (which it could be if all we're doing here is reframing
6739 // the current override element), it needs reframing. In particular, it
6740 // used to have a scrollframe (because its overflow was not "visible"), but
6741 // now it will propagate its overflow to the viewport, so it should not need
6742 // a scrollframe anymore.
6743 if (aChild->GetParent() && newOverrideElement &&
6744 newOverrideElement->GetParent() && newOverrideElement != aChild) {
6745 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6746 RecreateFramesForContent(newOverrideElement, InsertionKind::Async);
6747 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6748 }
6749 }
6750
6751#ifdef DEBUG1
6752 if (gNoisyContentUpdates) {
6753 printf(
6754 "nsCSSFrameConstructor::ContentWillBeRemoved container=%p child=%p\n",
6755 aChild->GetParent(), aChild);
6756 if (gReallyNoisyContentUpdates) {
6757 aChild->GetParent()->List(stdoutstdout, 0);
6758 }
6759 }
6760#endif
6761
6762 nsIFrame* childFrame = aChild->GetPrimaryFrame();
6763 if (!childFrame || childFrame->GetContent() != aChild) {
6764 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
6765 // Remove it once that's fixed.
6766 childFrame = nullptr;
6767 }
6768
6769 // If we're removing the root, then make sure to remove things starting at
6770 // the viewport's child instead of the primary frame (which might even be
6771 // null if the root was display:none, even though the frames above it got
6772 // created). Detecting removal of a root is a little exciting; in particular,
6773 // having no parent is necessary but NOT sufficient.
6774 //
6775 // Due to how we process reframes, the content node might not even be in our
6776 // document by now. So explicitly check whether the viewport's first kid's
6777 // content node is aChild.
6778 //
6779 // FIXME(emilio): I think the "might not be in our document" bit is impossible
6780 // now.
6781 bool isRoot = false;
6782 if (!aChild->GetParent()) {
6783 if (nsIFrame* viewport = GetRootFrame()) {
6784 nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
6785 if (firstChild && firstChild->GetContent() == aChild) {
6786 isRoot = true;
6787 childFrame = firstChild;
6788 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", 6788); MOZ_PretendNoReturn
(); } } while (0)
;
6789 }
6790 }
6791 }
6792
6793 // We need to be conservative about when to determine whether something has
6794 // display: contents or not because at this point our actual display may be
6795 // different.
6796 //
6797 // Consider the case of:
6798 //
6799 // <div id="A" style="display: contents"><div id="B"></div></div>
6800 //
6801 // If we reconstruct A because its display changed to "none", we still need to
6802 // cleanup the frame on B, but A's display is now "none", so we can't poke at
6803 // the style of it.
6804 //
6805 // FIXME(emilio, bug 1450366): We can make this faster without adding much
6806 // complexity for the display: none -> other case, which right now
6807 // unnecessarily walks the content tree down.
6808 auto CouldHaveBeenDisplayContents = [aKind](nsIContent* aContent) -> bool {
6809 return aContent->IsElement() && (aKind != RemovalKind::Dom ||
6810 IsDisplayContents(aContent->AsElement()));
6811 };
6812
6813 if (!childFrame) {
6814 if (CouldHaveBeenDisplayContents(aChild)) {
6815 // NOTE(emilio): We may iterate through ::before and ::after here and they
6816 // may be gone after the respective ContentWillBeRemoved call. Right now
6817 // StyleChildrenIterator handles that properly, so it's not an issue.
6818 StyleChildrenIterator iter(aChild);
6819 for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
6820 if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(c)) {
6821 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6822 bool didReconstruct = ContentWillBeRemoved(c, aKind);
6823 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6824 if (didReconstruct) {
6825 return true;
6826 }
6827 }
6828 }
6829 }
6830 return false;
6831 }
6832
6833 if (aKind != RemovalKind::Dom) {
6834 // Before removing the frames associated with the content object,
6835 // ask them to save their state onto our state object.
6836 CaptureStateForFramesOf(aChild, mFrameTreeState);
6837 }
6838
6839 InvalidateCanvasIfNeeded(mPresShell, aChild);
6840
6841 // See whether we need to remove more than just childFrame
6842 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6843 if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
6844 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6845 return true;
6846 }
6847 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6848
6849 // Get the childFrame's parent frame
6850 nsIFrame* parentFrame = childFrame->GetParent();
6851 LayoutFrameType parentType = parentFrame->Type();
6852
6853 if (parentType == LayoutFrameType::FrameSet &&
6854 IsSpecialFramesetChild(aChild)) {
6855 // Just reframe the parent, since framesets are weird like that.
6856 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6857 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6858 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6859 return true;
6860 }
6861
6862 // If we're a child of MathML, then we should reframe the MathML content.
6863 // If we're non-MathML, then we would be wrapped in a block so we need to
6864 // check our grandparent in that case.
6865 nsIFrame* possibleMathMLAncestor = parentType == LayoutFrameType::Block
6866 ? parentFrame->GetParent()
6867 : parentFrame;
6868 if (possibleMathMLAncestor->IsMathMLFrame()) {
6869 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
6870 RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
6871 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
6872 return true;
6873 }
6874
6875#ifdef ACCESSIBILITY1
6876 if (aKind != RemovalKind::ForReconstruction) {
6877 if (nsAccessibilityService* accService = GetAccService()) {
6878 accService->ContentRemoved(mPresShell, aChild);
6879 }
6880 }
6881#endif
6882
6883 // Examine the containing-block for the removed content and see if
6884 // :first-letter style applies.
6885 nsIFrame* inflowChild = childFrame;
6886 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6887 inflowChild = childFrame->GetPlaceholderFrame();
6888 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"
, 6888); MOZ_PretendNoReturn(); } } while (0)
;
6889 }
6890 nsContainerFrame* containingBlock =
6891 GetFloatContainingBlock(inflowChild->GetParent());
6892 bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
6893 if (haveFLS) {
6894 // Trap out to special routine that handles adjusting a blocks
6895 // frame tree when first-letter style is present.
6896#ifdef NOISY_FIRST_LETTER
6897 printf("ContentWillBeRemoved: containingBlock=");
6898 containingBlock->ListTag(stdoutstdout);
6899 printf(" parentFrame=");
6900 parentFrame->ListTag(stdoutstdout);
6901 printf(" childFrame=");
6902 childFrame->ListTag(stdoutstdout);
6903 printf("\n");
6904#endif
6905
6906 // First update the containing blocks structure by removing the
6907 // existing letter frames. This makes the subsequent logic
6908 // simpler.
6909 RemoveLetterFrames(mPresShell, containingBlock);
6910
6911 // Recover childFrame and parentFrame
6912 childFrame = aChild->GetPrimaryFrame();
6913 if (!childFrame || childFrame->GetContent() != aChild) {
6914 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
6915 // Remove it once that's fixed.
6916 return false;
6917 }
6918 parentFrame = childFrame->GetParent();
6919 parentType = parentFrame->Type();
Value stored to 'parentType' is never read
6920
6921#ifdef NOISY_FIRST_LETTER
6922 printf(" ==> revised parentFrame=");
6923 parentFrame->ListTag(stdoutstdout);
6924 printf(" childFrame=");
6925 childFrame->ListTag(stdoutstdout);
6926 printf("\n");
6927#endif
6928 }
6929
6930#ifdef DEBUG1
6931 if (gReallyNoisyContentUpdates) {
6932 printf("nsCSSFrameConstructor::ContentWillBeRemoved: childFrame=");
6933 childFrame->ListTag(stdoutstdout);
6934 putchar('\n');
6935 parentFrame->List(stdoutstdout);
6936 }
6937#endif
6938
6939 // Notify the parent frame that it should delete the frame
6940 if (childFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
6941 childFrame = childFrame->GetPlaceholderFrame();
6942 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"
, 6942); MOZ_PretendNoReturn(); } } while (0)
;
6943 parentFrame = childFrame->GetParent();
6944 }
6945
6946 // Take care of wrapper anonymous boxes that we might need to remove while
6947 // at it. Note that MaybeRecreateContainerForFrameRemoval takes care of
6948 // harder cases (merging sibling anonymous boxes etc).
6949 while (IsWrapperPseudo(parentFrame) &&
6950 CanRemoveWrapperPseudoForChildRemoval(childFrame, parentFrame)) {
6951 childFrame = parentFrame;
6952 parentFrame = childFrame->GetParent();
6953 }
6954
6955 const bool canSkipWhitespaceFixup = [&] {
6956 if (aKind == RemovalKind::ForReconstruction) {
6957 // If we're just reconstructing frames for the element, then the
6958 // following ContentInserted notification on the element will
6959 // take care of fixing up any adjacent white-space text nodes.
6960 return true;
6961 }
6962 switch (parentFrame->Type()) {
6963 case LayoutFrameType::Table:
6964 case LayoutFrameType::TableRow:
6965 case LayoutFrameType::TableRowGroup:
6966 case LayoutFrameType::TableCol:
6967 case LayoutFrameType::TableColGroup:
6968 case LayoutFrameType::TableWrapper: {
6969 // Tables ignore all whitespace within their wrappers, so we can avoid
6970 // reconstructing adjacent whitespace if the table is not anonymous.
6971 if (!IsInAnonymousTable(parentFrame)) {
6972 return true;
6973 }
6974 // If the table is anonymous and the child is at the edges, we might
6975 // need to create whitespace at the edges of the table that wasn't
6976 // there before, so we can only skip the check if childFrame has frames
6977 // around. Captions are extra-special here, because they're siblings
6978 // with the main table frame, so we can't count that as a relevant
6979 // sibling for our purposes.
6980 auto* prevSibling = childFrame->GetPrevSibling();
6981 return prevSibling && !prevSibling->IsTableFrame() &&
6982 childFrame->GetNextSibling();
6983 }
6984 case LayoutFrameType::GridContainer:
6985 case LayoutFrameType::FlexContainer:
6986 // Flex and grid containers similarly skip whitespace and wrap
6987 // non-whitespace in anonymous flex items, so any change to
6988 // white-space that could matter would have triggered the
6989 // reconstruction of the container itself due to merging anonymous
6990 // grid / flex items.
6991 return true;
6992 default:
6993 break;
6994 }
6995 return false;
6996 }();
6997 DestroyContext context(mPresShell);
6998 RemoveFrame(context, nsLayoutUtils::GetChildListNameFor(childFrame),
6999 childFrame);
7000
7001 // NOTE(emilio): aChild could be dead here already if it is a ::before or
7002 // ::after pseudo-element (since in that case it was owned by childFrame,
7003 // which we just destroyed).
7004
7005 if (isRoot) {
7006 mRootElementFrame = nullptr;
7007 mRootElementStyleFrame = nullptr;
7008 mDocElementContainingBlock = nullptr;
7009 mCanvasFrame = nullptr;
7010 mPageSequenceFrame = nullptr;
7011 }
7012
7013 if (haveFLS && mRootElementFrame) {
7014 RecoverLetterFrames(containingBlock);
7015 }
7016
7017 if (!canSkipWhitespaceFixup) {
7018 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"
, 7019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7019); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7019 "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"
, 7019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->GetParentNode()"
") (" "How did we have a sibling without a parent?" ")"); do
{ MOZ_CrashSequence(__null, 7019); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7020 // Adjacent whitespace-only text nodes might have been suppressed if
7021 // this node does not have inline ends. Create frames for them now
7022 // if necessary.
7023 // Reframe any text node just before the node being removed, if there is
7024 // one, and if it's not the last child or the first child. If a whitespace
7025 // textframe was being suppressed and it's now the last child or first
7026 // child then it can stay suppressed since the parent must be a block
7027 // and hence it's adjacent to a block end.
7028 // If aOldNextSibling is null, then the text node before the node being
7029 // removed is the last node, and we don't need to worry about it.
7030 nsIContent* prevSibling = aChild->GetPreviousSibling();
7031 if (prevSibling && prevSibling->GetPreviousSibling()) {
7032 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7033 ReframeTextIfNeeded(prevSibling);
7034 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7035 }
7036 // Reframe any text node just after the node being removed, if there is
7037 // one, and if it's not the last child or the first child.
7038 nsIContent* nextSibling = aChild->GetNextSibling();
7039 if (nextSibling && prevSibling && nextSibling->GetNextSibling()) {
7040 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7041 ReframeTextIfNeeded(nextSibling);
7042 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7043 }
7044 }
7045
7046#ifdef DEBUG1
7047 if (gReallyNoisyContentUpdates && parentFrame) {
7048 printf(
7049 "nsCSSFrameConstructor::ContentWillBeRemoved: resulting frame "
7050 "model:\n");
7051 parentFrame->List(stdoutstdout);
7052 }
7053#endif
7054
7055 return false;
7056}
7057
7058/**
7059 * This method invalidates the canvas when frames are removed or added for a
7060 * node that might have its background propagated to the canvas, i.e., a
7061 * document root node or an HTML BODY which is a child of the root node.
7062 *
7063 * @param aFrame a frame for a content node about to be removed or a frame that
7064 * was just created for a content node that was inserted.
7065 */
7066static void InvalidateCanvasIfNeeded(PresShell* aPresShell, nsIContent* aNode) {
7067 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", 7067); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aPresShell->GetRootFrame()" ") (" "What happened here?"
")"); do { MOZ_CrashSequence(__null, 7067); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7068 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"
, 7068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell->GetPresContext()"
") (" "Say what?" ")"); do { MOZ_CrashSequence(__null, 7068)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
7069
7070 // Note that both in ContentWillBeRemoved and ContentInserted the content
7071 // node will still have the right parent pointer, so looking at that is ok.
7072
7073 nsIContent* parent = aNode->GetParent();
7074 if (parent) {
7075 // Has a parent; might not be what we want
7076 nsIContent* grandParent = parent->GetParent();
7077 if (grandParent) {
7078 // Has a grandparent, so not what we want
7079 return;
7080 }
7081
7082 // Check whether it's an HTML body
7083 if (!aNode->IsHTMLElement(nsGkAtoms::body)) {
7084 return;
7085 }
7086 }
7087
7088 // At this point the node has no parent or it's an HTML <body> child of the
7089 // root. We might not need to invalidate in this case (eg we might be in
7090 // XHTML or something), but chances are we want to. Play it safe.
7091 // Invalidate the viewport.
7092
7093 nsIFrame* rootFrame = aPresShell->GetRootFrame();
7094 rootFrame->InvalidateFrameSubtree();
7095}
7096
7097bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
7098 CharacterData* aContent) {
7099 if (!aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
7100 return false;
7101 }
7102
7103 if (mAlwaysCreateFramesForIgnorableWhitespace) {
7104 return false;
7105 }
7106
7107 // Text frame may have been suppressed. Disable suppression and signal that a
7108 // flush should be performed. We do this on a document-wide basis so that
7109 // pages that repeatedly query metrics for collapsed-whitespace text nodes
7110 // don't trigger pathological behavior.
7111 mAlwaysCreateFramesForIgnorableWhitespace = true;
7112 Element* root = mDocument->GetRootElement();
7113 if (!root) {
7114 return false;
7115 }
7116
7117 RestyleManager()->PostRestyleEvent(root, RestyleHint{0},
7118 nsChangeHint_ReconstructFrame);
7119 return true;
7120}
7121
7122void nsCSSFrameConstructor::CharacterDataChanged(
7123 nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
7124 AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::CharacterDataChanged",mozilla::AutoProfilerLabelHot raiiObject7125( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
7125 LAYOUT_FrameConstruction)mozilla::AutoProfilerLabelHot raiiObject7125( "nsCSSFrameConstructor::CharacterDataChanged"
, nullptr, JS::ProfilingCategoryPair::LAYOUT_FrameConstruction
)
;
7126 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC)nsAutoLayoutPhase autoLayoutPhase((mPresShell->GetPresContext
()), (nsLayoutPhase::FrameC))
;
7127
7128 if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
7129 !aContent->TextIsOnlyWhitespace()) ||
7130 (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
7131 aContent->TextIsOnlyWhitespace())) {
7132#ifdef DEBUG1
7133 nsIFrame* frame = aContent->GetPrimaryFrame();
7134 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"
, 7135); MOZ_PretendNoReturn(); } } while (0)
7135 "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"
, 7135); MOZ_PretendNoReturn(); } } while (0)
;
7136#endif
7137 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7138 RecreateFramesForContent(aContent, InsertionKind::Async);
7139 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7140 return;
7141 }
7142
7143 // It's possible the frame whose content changed isn't inserted into the
7144 // frame hierarchy yet, or that there is no frame that maps the content
7145 if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
7146#if 0
7147 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)
7148 ("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)
7149 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)
7150 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)
;
7151#endif
7152
7153 if (frame->HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI)) {
7154 LAYOUT_PHASE_TEMP_EXIT()do { autoLayoutPhase.Exit(); } while (0);
7155 RecreateFramesForContent(aContent, InsertionKind::Async);
7156 LAYOUT_PHASE_TEMP_REENTER()do { autoLayoutPhase.Enter(); } while (0);
7157 return;
7158 }
7159
7160 // Special check for text content that is a child of a letter frame. If
7161 // this happens, we should remove the letter frame, do whatever we're
7162 // planning to do with this notification, then put the letter frame back.
7163 // Note that this is basically what RecreateFramesForContent ends up doing;
7164 // the reason we dont' want to call that here is that our text content
7165 // could be native anonymous, in which case RecreateFramesForContent would
7166 // completely barf on it. And recreating the non-anonymous ancestor would
7167 // just lead us to come back into this notification (e.g. if quotes or
7168 // counters are involved), leading to a loop.
7169 nsContainerFrame* block = GetFloatContainingBlock(frame);
7170 bool haveFirstLetterStyle = false;
7171 if (block) {
7172 // See if the block has first-letter style applied to it.
7173 haveFirstLetterStyle = HasFirstLetterStyle(block);
7174 if (haveFirstLetterStyle) {
7175 RemoveLetterFrames(mPresShell, block);
7176 // Reget |frame|, since we might have killed it.
7177 // Do we really need to call CharacterDataChanged in this case, though?
7178 frame = aContent->GetPrimaryFrame();
7179 NS_ASSERTION(frame, "Should have frame here!")do { if (!(frame)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have frame here!"
, "frame", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7179); MOZ_PretendNoReturn(); } } while (0)
;
7180 }
7181 }
7182
7183 // Notify the first frame that maps the content. It will generate a reflow
7184 // command
7185 frame->CharacterDataChanged(aInfo);
7186
7187 if (haveFirstLetterStyle) {
7188 RecoverLetterFrames(block);
7189 }
7190 }
7191}
7192
7193void nsCSSFrameConstructor::RecalcQuotesAndCounters() {
7194 nsAutoScriptBlocker scriptBlocker;
7195
7196 if (mQuotesDirty) {
7197 mQuotesDirty = false;
7198 mContainStyleScopeManager.RecalcAllQuotes();
7199 }
7200
7201 if (mCountersDirty) {
7202 mCountersDirty = false;
7203 mContainStyleScopeManager.RecalcAllCounters();
7204 }
7205
7206 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"
, 7206); MOZ_PretendNoReturn(); } } while (0)
;
7207 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"
, 7207); MOZ_PretendNoReturn(); } } while (0)
;
7208}
7209
7210void nsCSSFrameConstructor::NotifyCounterStylesAreDirty() {
7211 mContainStyleScopeManager.SetAllCountersDirty();
7212 CountersDirty();
7213}
7214
7215void nsCSSFrameConstructor::WillDestroyFrameTree() {
7216#if defined(DEBUG_dbaron_off)
7217 mContainStyleScopeManager.DumpCounters();
7218#endif
7219
7220 // Prevent frame tree destruction from being O(N^2)
7221 mContainStyleScopeManager.Clear();
7222 nsFrameManager::Destroy();
7223}
7224
7225// STATIC
7226
7227// XXXbz I'd really like this method to go away. Once we have inline-block and
7228// I can just use that for sized broken images, that can happen, maybe.
7229//
7230// NOTE(emilio): This needs to match MozAltContent handling.
7231void nsCSSFrameConstructor::GetAlternateTextFor(const Element& aElement,
7232 nsAString& aAltText) {
7233 // The "alt" attribute specifies alternate text that is rendered
7234 // when the image can not be displayed.
7235 if (aElement.GetAttr(nsGkAtoms::alt, aAltText)) {
7236 return;
7237 }
7238
7239 if (aElement.IsHTMLElement(nsGkAtoms::input)) {
7240 // If there's no "alt" attribute, and aElement is an input element, then use
7241 // the value of the "value" attribute.
7242 if (aElement.GetAttr(nsGkAtoms::value, aAltText)) {
7243 return;
7244 }
7245
7246 // If there's no "value" attribute either, then use the localized string for
7247 // "Submit" as the alternate text.
7248 nsContentUtils::GetMaybeLocalizedString(PropertiesFile::FORMS_PROPERTIES,
7249 "Submit", aElement.OwnerDoc(),
7250 aAltText);
7251 }
7252}
7253
7254nsIFrame* nsCSSFrameConstructor::CreateContinuingOuterTableFrame(
7255 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7256 ComputedStyle* aComputedStyle) {
7257 nsTableWrapperFrame* newFrame =
7258 NS_NewTableWrapperFrame(mPresShell, aComputedStyle);
7259
7260 newFrame->Init(aContent, aParentFrame, aFrame);
7261
7262 // Create a continuing inner table frame. Note we don't replicate the
7263 // captions: a comment used to hint at that, but the code dealing with that
7264 // never worked and was removed in bug 309322.
7265 nsFrameList newChildFrames;
7266
7267 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"
, 7267); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->IsTableWrapperFrame()"
")"); do { MOZ_CrashSequence(__null, 7267); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7268 if (nsTableFrame* childFrame =
7269 static_cast<nsTableWrapperFrame*>(aFrame)->InnerTableFrame()) {
7270 nsIFrame* continuingTableFrame =
7271 CreateContinuingFrame(childFrame, newFrame);
7272 newChildFrames.AppendFrame(nullptr, continuingTableFrame);
7273 }
7274
7275 // Set the table wrapper's initial child list
7276 newFrame->SetInitialChildList(FrameChildListID::Principal,
7277 std::move(newChildFrames));
7278
7279 return newFrame;
7280}
7281
7282nsIFrame* nsCSSFrameConstructor::CreateContinuingTableFrame(
7283 nsIFrame* aFrame, nsContainerFrame* aParentFrame, nsIContent* aContent,
7284 ComputedStyle* aComputedStyle) {
7285 nsTableFrame* newFrame = NS_NewTableFrame(mPresShell, aComputedStyle);
7286
7287 newFrame->Init(aContent, aParentFrame, aFrame);
7288
7289 // Replicate any header/footer frames
7290 nsFrameList childFrames;
7291 for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
7292 // See if it's a header/footer, possibly wrapped in a scroll frame.
7293 nsTableRowGroupFrame* rowGroupFrame =
7294 static_cast<nsTableRowGroupFrame*>(childFrame);
7295 // If the row group was continued, then don't replicate it.
7296 nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
7297 if (rgNextInFlow) {
7298 rowGroupFrame->SetRepeatable(false);
7299 } else if (rowGroupFrame->IsRepeatable()) {
7300 // Replicate the header/footer frame.
7301 nsTableRowGroupFrame* headerFooterFrame;
7302 nsFrameList childList;
7303
7304 nsFrameConstructorState state(
7305 mPresShell, GetAbsoluteContainingBlock(newFrame, FIXED_POS),
7306 GetAbsoluteContainingBlock(newFrame, ABS_POS), nullptr);
7307 state.mCreatingExtraFrames = true;
7308
7309 ComputedStyle* const headerFooterComputedStyle = rowGroupFrame->Style();
7310 headerFooterFrame = static_cast<nsTableRowGroupFrame*>(
7311 NS_NewTableRowGroupFrame(mPresShell, headerFooterComputedStyle));
7312
7313 nsIContent* headerFooter = rowGroupFrame->GetContent();
7314 headerFooterFrame->Init(headerFooter, newFrame, nullptr);
7315
7316 nsFrameConstructorSaveState absoluteSaveState;
7317 MakeTablePartAbsoluteContainingBlock(state, absoluteSaveState,
7318 headerFooterFrame);
7319
7320 nsFrameConstructorSaveState floatSaveState;
7321 state.MaybePushFloatContainingBlock(headerFooterFrame, floatSaveState);
7322
7323 ProcessChildren(state, headerFooter, rowGroupFrame->Style(),
7324 headerFooterFrame, true, childList, false, nullptr);
7325 NS_ASSERTION(state.mFloatedList.IsEmpty(), "unexpected floated element")do { if (!(state.mFloatedList.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "unexpected floated element", "state.mFloatedList.IsEmpty()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7325); MOZ_PretendNoReturn
(); } } while (0)
;
7326 headerFooterFrame->SetInitialChildList(FrameChildListID::Principal,
7327 std::move(childList));
7328 headerFooterFrame->SetRepeatable(true);
7329
7330 // Table specific initialization
7331 headerFooterFrame->InitRepeatedFrame(rowGroupFrame);
7332
7333 // XXX Deal with absolute and fixed frames...
7334 childFrames.AppendFrame(nullptr, headerFooterFrame);
7335 }
7336 }
7337
7338 // Set the table frame's initial child list
7339 newFrame->SetInitialChildList(FrameChildListID::Principal,
7340 std::move(childFrames));
7341
7342 return newFrame;
7343}
7344
7345nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
7346 nsIFrame* aFrame, nsContainerFrame* aParentFrame, bool aIsFluid) {
7347 ComputedStyle* computedStyle = aFrame->Style();
7348 nsIFrame* newFrame = nullptr;
7349 nsIFrame* nextContinuation = aFrame->GetNextContinuation();
7350 nsIFrame* nextInFlow = aFrame->GetNextInFlow();
7351
7352 // Use the frame type to determine what type of frame to create
7353 LayoutFrameType frameType = aFrame->Type();
7354 nsIContent* content = aFrame->GetContent();
7355
7356 if (LayoutFrameType::Text == frameType) {
7357 newFrame = NS_NewContinuingTextFrame(mPresShell, computedStyle);
7358 newFrame->Init(content, aParentFrame, aFrame);
7359 } else if (LayoutFrameType::Inline == frameType) {
7360 newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
7361 newFrame->Init(content, aParentFrame, aFrame);
7362 } else if (LayoutFrameType::Block == frameType) {
7363 MOZ_ASSERT(!aFrame->IsTableCaption(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7364
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7364); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7364 "no support for fragmenting table captions yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7364
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7364); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7365 newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
7366 newFrame->Init(content, aParentFrame, aFrame);
7367 } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
7368 newFrame = NS_NewColumnSetWrapperFrame(mPresShell, computedStyle,
7369 NS_FRAME_STATE_NONE);
7370 newFrame->Init(content, aParentFrame, aFrame);
7371 } else if (LayoutFrameType::ColumnSet == frameType) {
7372 MOZ_ASSERT(!aFrame->IsTableCaption(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7373
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7373); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7373 "no support for fragmenting table captions yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aFrame->IsTableCaption())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aFrame->IsTableCaption()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aFrame->IsTableCaption()" " (" "no support for fragmenting table captions yet"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7373
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aFrame->IsTableCaption()"
") (" "no support for fragmenting table captions yet" ")"); do
{ MOZ_CrashSequence(__null, 7373); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7374 newFrame =
7375 NS_NewColumnSetFrame(mPresShell, computedStyle, NS_FRAME_STATE_NONE);
7376 newFrame->Init(content, aParentFrame, aFrame);
7377 } else if (LayoutFrameType::PrintedSheet == frameType) {
7378 newFrame = ConstructPrintedSheetFrame(mPresShell, aParentFrame, aFrame);
7379 } else if (LayoutFrameType::Page == frameType) {
7380 nsCanvasFrame* canvasFrame; // (unused outparam for ConstructPageFrame)
7381 newFrame =
7382 ConstructPageFrame(mPresShell, aParentFrame, aFrame, canvasFrame);
7383 } else if (LayoutFrameType::TableWrapper == frameType) {
7384 newFrame = CreateContinuingOuterTableFrame(aFrame, aParentFrame, content,
7385 computedStyle);
7386 } else if (LayoutFrameType::Table == frameType) {
7387 newFrame = CreateContinuingTableFrame(aFrame, aParentFrame, content,
7388 computedStyle);
7389 } else if (LayoutFrameType::TableRowGroup == frameType) {
7390 newFrame = NS_NewTableRowGroupFrame(mPresShell, computedStyle);
7391 newFrame->Init(content, aParentFrame, aFrame);
7392 } else if (LayoutFrameType::TableRow == frameType) {
7393 nsTableRowFrame* rowFrame = NS_NewTableRowFrame(mPresShell, computedStyle);
7394
7395 rowFrame->Init(content, aParentFrame, aFrame);
7396
7397 // Create a continuing frame for each table cell frame
7398 nsFrameList newChildList;
7399 nsIFrame* cellFrame = aFrame->PrincipalChildList().FirstChild();
7400 while (cellFrame) {
7401 // See if it's a table cell frame
7402 if (cellFrame->IsTableCellFrame()) {
7403 nsIFrame* continuingCellFrame =
7404 CreateContinuingFrame(cellFrame, rowFrame);
7405 newChildList.AppendFrame(nullptr, continuingCellFrame);
7406 }
7407 cellFrame = cellFrame->GetNextSibling();
7408 }
7409
7410 rowFrame->SetInitialChildList(FrameChildListID::Principal,
7411 std::move(newChildList));
7412 newFrame = rowFrame;
7413
7414 } else if (LayoutFrameType::TableCell == frameType) {
7415 // Warning: If you change this and add a wrapper frame around table cell
7416 // frames, make sure Bug 368554 doesn't regress!
7417 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
7418 nsTableFrame* tableFrame =
7419 static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame();
7420 nsTableCellFrame* cellFrame =
7421 NS_NewTableCellFrame(mPresShell, computedStyle, tableFrame);
7422
7423 cellFrame->Init(content, aParentFrame, aFrame);
7424
7425 // Create a continuing area frame
7426 nsIFrame* blockFrame = aFrame->PrincipalChildList().FirstChild();
7427 nsIFrame* continuingBlockFrame =
7428 CreateContinuingFrame(blockFrame, cellFrame);
7429
7430 SetInitialSingleChild(cellFrame, continuingBlockFrame);
7431 newFrame = cellFrame;
7432 } else if (LayoutFrameType::Line == frameType) {
7433 newFrame = NS_NewFirstLineFrame(mPresShell, computedStyle);
7434 newFrame->Init(content, aParentFrame, aFrame);
7435 } else if (LayoutFrameType::Letter == frameType) {
7436 newFrame = NS_NewFirstLetterFrame(mPresShell, computedStyle);
7437 newFrame->Init(content, aParentFrame, aFrame);
7438 } else if (LayoutFrameType::Image == frameType) {
7439 auto* imageFrame = static_cast<nsImageFrame*>(aFrame);
7440 newFrame = imageFrame->CreateContinuingFrame(mPresShell, computedStyle);
7441 newFrame->Init(content, aParentFrame, aFrame);
7442 } else if (LayoutFrameType::ImageControl == frameType) {
7443 newFrame = NS_NewImageControlFrame(mPresShell, computedStyle);
7444 newFrame->Init(content, aParentFrame, aFrame);
7445 } else if (LayoutFrameType::FieldSet == frameType) {
7446 newFrame = NS_NewFieldSetFrame(mPresShell, computedStyle);
7447 newFrame->Init(content, aParentFrame, aFrame);
7448 } else if (LayoutFrameType::FlexContainer == frameType) {
7449 newFrame = NS_NewFlexContainerFrame(mPresShell, computedStyle);
7450 newFrame->Init(content, aParentFrame, aFrame);
7451 } else if (LayoutFrameType::GridContainer == frameType) {
7452 newFrame = NS_NewGridContainerFrame(mPresShell, computedStyle);
7453 newFrame->Init(content, aParentFrame, aFrame);
7454 } else if (LayoutFrameType::Ruby == frameType) {
7455 newFrame = NS_NewRubyFrame(mPresShell, computedStyle);
7456 newFrame->Init(content, aParentFrame, aFrame);
7457 } else if (LayoutFrameType::RubyBaseContainer == frameType) {
7458 newFrame = NS_NewRubyBaseContainerFrame(mPresShell, computedStyle);
7459 newFrame->Init(content, aParentFrame, aFrame);
7460 } else if (LayoutFrameType::RubyTextContainer == frameType) {
7461 newFrame = NS_NewRubyTextContainerFrame(mPresShell, computedStyle);
7462 newFrame->Init(content, aParentFrame, aFrame);
7463 } else {
7464 MOZ_CRASH("unexpected frame type")do { do { } while (false); MOZ_ReportCrash("" "unexpected frame type"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7464); AnnotateMozCrashReason
("MOZ_CRASH(" "unexpected frame type" ")"); do { MOZ_CrashSequence
(__null, 7464); __attribute__((nomerge)) ::abort(); } while (
false); } while (false)
;
7465 }
7466
7467 // Init() set newFrame to be a fluid continuation of aFrame.
7468 // If we want a non-fluid continuation, we need to call SetPrevContinuation()
7469 // to reset NS_FRAME_IS_FLUID_CONTINUATION.
7470 if (!aIsFluid) {
7471 newFrame->SetPrevContinuation(aFrame);
7472 }
7473
7474 // If a continuing frame needs to carry frame state bits from its previous
7475 // continuation or parent, set them in nsIFrame::Init(), or in any derived
7476 // frame class's Init() if the bits are belong to specific group.
7477
7478 if (nextInFlow) {
7479 nextInFlow->SetPrevInFlow(newFrame);
7480 newFrame->SetNextInFlow(nextInFlow);
7481 } else if (nextContinuation) {
7482 nextContinuation->SetPrevContinuation(newFrame);
7483 newFrame->SetNextContinuation(nextContinuation);
7484 }
7485
7486 // aFrame cannot be a dynamic reflow root because it has a continuation now.
7487 aFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
7488
7489 MOZ_ASSERT(!newFrame->GetNextSibling(), "unexpected sibling")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newFrame->GetNextSibling())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newFrame->GetNextSibling
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newFrame->GetNextSibling()" " (" "unexpected sibling" ")"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7489); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!newFrame->GetNextSibling()" ") (" "unexpected sibling"
")"); do { MOZ_CrashSequence(__null, 7489); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7490 return newFrame;
7491}
7492
7493void nsCSSFrameConstructor::MaybeSetNextPageContentFramePageName(
7494 const nsIFrame* aFrame) {
7495 MOZ_ASSERT(aFrame, "Frame should not be null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame" " (" "Frame should not be null"
")", "./../../../layout/base/nsCSSFrameConstructor.cpp", 7495
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Frame should not be null"
")"); do { MOZ_CrashSequence(__null, 7495); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7496 // No parent means the root frame, which isn't what this funciton is for.
7497 MOZ_ASSERT(aFrame->GetParent(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7498 "Frame should be the first child placed on a new page, not the "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
7499 "root frame.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->GetParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->GetParent()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aFrame->GetParent()"
" (" "Frame should be the first child placed on a new page, not the "
"root frame." ")", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 7499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame should be the first child placed on a new page, not the "
"root frame." ")"); do { MOZ_CrashSequence(__null, 7499); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
7500 if (mNextPageContentFramePageName) {
7501 return;
7502 }
7503 const nsAtom* const autoValue = aFrame->GetParent()->GetAutoPageValue();
7504 mNextPageContentFramePageName = aFrame->ComputePageValue(autoValue);
7505}
7506
7507nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
7508 nsPageContentFrame* aParentFrame) {
7509 // Now deal with fixed-pos things.... They should appear on all pages,
7510 // so we want to move over the placeholders when processing the child
7511 // of the pageContentFrame.
7512
7513 nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
7514 if (!prevPageContentFrame) {
7515 return NS_OK;
7516 }
7517 nsContainerFrame* canvasFrame =
7518 do_QueryFrame(aParentFrame->PrincipalChildList().FirstChild());
7519 nsIFrame* prevCanvasFrame =
7520 prevPageContentFrame->PrincipalChildList().FirstChild();
7521 if (!canvasFrame || !prevCanvasFrame) {
7522 // document's root element frame missing
7523 return NS_ERROR_UNEXPECTED;
7524 }
7525
7526 nsFrameList fixedPlaceholders;
7527 nsIFrame* firstFixed =
7528 prevPageContentFrame->GetChildList(FrameChildListID::Absolute)
7529 .FirstChild();
7530 if (!firstFixed) {
7531 return NS_OK;
7532 }
7533
7534 // Don't allow abs-pos descendants of the fixed content to escape the content.
7535 // This should not normally be possible (because fixed-pos elements should
7536 // be absolute containers) but fixed-pos tables currently aren't abs-pos
7537 // containers.
7538 nsFrameConstructorState state(mPresShell, aParentFrame, nullptr,
7539 mRootElementFrame);
7540 state.mCreatingExtraFrames = true;
7541
7542 // We can't use an ancestor filter here, because we're not going to
7543 // be usefully recurring down the tree. This means that other
7544 // places in frame construction can't assume a filter is
7545 // initialized!
7546
7547 // Iterate across fixed frames and replicate each whose placeholder is a
7548 // descendant of aFrame. (We don't want to explicitly copy placeholders that
7549 // are within fixed frames, because that would cause duplicates on the new
7550 // page - bug 389619)
7551 for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
7552 nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
7553 if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(
7554 prevCanvasFrame, prevPlaceholder)) {
7555 // We want to use the same style as the primary style frame for
7556 // our content
7557 nsIContent* content = fixed->GetContent();
7558 ComputedStyle* computedStyle =
7559 nsLayoutUtils::GetStyleFrame(content)->Style();
7560 AutoFrameConstructionItemList items(this);
7561 AddFrameConstructionItemsInternal(state, content, canvasFrame, true,
7562 computedStyle,
7563 {ItemFlag::AllowPageBreak}, items);
7564 ConstructFramesFromItemList(state, items, canvasFrame,
7565 /* aParentIsWrapperAnonBox = */ false,
7566 fixedPlaceholders);
7567 }
7568 }
7569
7570 // Add the placeholders to our primary child list.
7571 // XXXbz this is a little screwed up, since the fixed frames will have
7572 // broken auto-positioning. Oh, well.
7573 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"
, 7574); MOZ_PretendNoReturn(); } } while (0)
7574 "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"
, 7574); MOZ_PretendNoReturn(); } } while (0)
;
7575 canvasFrame->SetInitialChildList(FrameChildListID::Principal,
7576 std::move(fixedPlaceholders));
7577 return NS_OK;
7578}
7579
7580nsCSSFrameConstructor::InsertionPoint nsCSSFrameConstructor::GetInsertionPoint(
7581 nsIContent* aChild) {
7582 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"
, 7582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ")"
); do { MOZ_CrashSequence(__null, 7582); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7583 nsIContent* insertionElement = aChild->GetFlattenedTreeParent();
7584 if (!insertionElement) {
7585 // The element doesn't belong in the flattened tree, and thus we don't want
7586 // to render it.
7587 return {};
7588 }
7589
7590 return {GetContentInsertionFrameFor(insertionElement), insertionElement};
7591}
7592
7593// Capture state for the frame tree rooted at the frame associated with the
7594// content object, aContent
7595void nsCSSFrameConstructor::CaptureStateForFramesOf(
7596 nsIContent* aContent, nsILayoutHistoryState* aHistoryState) {
7597 if (!aHistoryState) {
7598 return;
7599 }
7600 nsIFrame* frame = aContent->GetPrimaryFrame();
7601 if (frame == mRootElementFrame) {
7602 frame = mRootElementFrame
7603 ? GetAbsoluteContainingBlock(mRootElementFrame, FIXED_POS)
7604 : GetRootFrame();
7605 }
7606 for (; frame;
7607 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
7608 CaptureFrameState(frame, aHistoryState);
7609 }
7610}
7611
7612static bool IsWhitespaceFrame(nsIFrame* aFrame) {
7613 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", 7613
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "invalid argument"
")"); do { MOZ_CrashSequence(__null, 7613); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7614 return aFrame->IsTextFrame() && aFrame->GetContent()->TextIsOnlyWhitespace();
7615}
7616
7617static nsIFrame* FindNextNonWhitespaceSibling(nsIFrame* aFrame) {
7618 nsIFrame* f = aFrame;
7619 do {
7620 f = f->GetNextSibling();
7621 } while (f && IsWhitespaceFrame(f));
7622 return f;
7623}
7624
7625static nsIFrame* FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) {
7626 nsIFrame* f = aFrame;
7627 do {
7628 f = f->GetPrevSibling();
7629 } while (f && IsWhitespaceFrame(f));
7630 return f;
7631}
7632
7633static nsIFrame* CheckRubyContainers(nsIFrame* aFrame, nsIFrame* aParent) {
7634 auto* ancestor = aParent;
7635 auto* ancestorChild = aFrame;
7636 while (ancestor && IsWrapperPseudo(ancestor) &&
7637 CanRemoveWrapperPseudoForChildRemoval(ancestorChild, ancestor)) {
7638 ancestorChild = ancestor;
7639 ancestor = ancestorChild->GetParent();
7640 }
7641 if (!ancestor) {
7642 return nullptr;
7643 }
7644 const auto ancestorType = ancestor->Type();
7645 if (ancestorType != LayoutFrameType::Ruby &&
7646 !RubyUtils::IsRubyContainerBox(ancestorType)) {
7647 return nullptr;
7648 }
7649 return ancestor;
7650}
7651
7652bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
7653 nsIFrame* aFrame) {
7654#define TRACE(reason) \
7655 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)
7656 {}, 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)
7657 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", 7657
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have a frame"
")"); do { MOZ_CrashSequence(__null, 7657); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7658 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"
, 7658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetParent()"
") (" "Frame shouldn't be root" ")"); do { MOZ_CrashSequence
(__null, 7658); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7659 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"
, 7660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7660); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
7660 "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"
, 7660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame == aFrame->FirstContinuation()"
") (" "aFrame not the result of GetPrimaryFrame()?" ")"); do
{ MOZ_CrashSequence(__null, 7660); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
7661
7662 nsIFrame* inFlowFrame = aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
7663 ? aFrame->GetPlaceholderFrame()
7664 : aFrame;
7665 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"
, 7665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 7665); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
7666 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", 7667
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
7667 "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", 7667
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inFlowFrame == inFlowFrame->FirstContinuation()"
") (" "placeholder for primary frame has previous continuations?"
")"); do { MOZ_CrashSequence(__null, 7667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7668 nsIFrame* parent = inFlowFrame->GetParent();
7669
7670 if (inFlowFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
7671 nsIFrame* grandparent = parent->GetParent();
7672 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"
, 7672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "grandparent"
")"); do { MOZ_CrashSequence(__null, 7672); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7673
7674 bool needsReframe =
7675 // 1. Removing a column-span may lead to an empty
7676 // ::-moz-column-span-wrapper.
7677 inFlowFrame->IsColumnSpan() ||
7678 // 2. Removing a frame which has any column-span siblings may also
7679 // lead to an empty ::-moz-column-span-wrapper subtree. The
7680 // column-span siblings were the frame's children, but later become
7681 // the frame's siblings after CreateColumnSpanSiblings().
7682 inFlowFrame->HasColumnSpanSiblings() ||
7683 // 3. Removing the only child of a ::-moz-column-content, whose
7684 // ColumnSet grandparent has a previous column-span sibling, requires
7685 // reframing since we might connect the ColumnSet's next column-span
7686 // sibling (if there's one). Note that this isn't actually needed if
7687 // the ColumnSet is at the end of ColumnSetWrapper since we create
7688 // empty ones at the end anyway, but we're not worried about
7689 // optimizing that case.
7690 (parent->Style()->GetPseudoType() ==
7691 PseudoStyleType::MozColumnContent &&
7692 // The only child in ::-moz-column-content (might be tall enough to
7693 // split across columns)
7694 !inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7695 // That ::-moz-column-content is the first column.
7696 !parent->GetPrevInFlow() &&
7697 // The ColumnSet grandparent has a previous sibling that is a
7698 // column-span.
7699 grandparent->GetPrevSibling());
7700
7701 if (needsReframe) {
7702 nsContainerFrame* containingBlock =
7703 GetMultiColumnContainingBlockFor(inFlowFrame);
7704
7705#ifdef DEBUG1
7706 if (IsFramePartOfIBSplit(inFlowFrame)) {
7707 nsIFrame* ibContainingBlock = GetIBContainingBlockFor(inFlowFrame);
7708 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"
, 7712); 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, 7712); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7709 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"
, 7712); 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, 7712); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7710 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"
, 7712); 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, 7712); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7711 "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"
, 7712); 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, 7712); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
7712 "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"
, 7712); 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, 7712); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
7713 }
7714#endif
7715
7716 TRACE("Multi-column");
7717 RecreateFramesForContent(containingBlock->GetContent(),
7718 InsertionKind::Async);
7719 return true;
7720 }
7721 }
7722
7723 if (IsFramePartOfIBSplit(aFrame)) {
7724 // The removal functions can't handle removal of an {ib} split directly; we
7725 // need to rebuild the containing block.
7726 TRACE("IB split removal");
7727 ReframeContainingBlock(aFrame);
7728 return true;
7729 }
7730
7731 if (inFlowFrame->IsRenderedLegend()) {
7732 TRACE("Fieldset / Legend");
7733 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7734 return true;
7735 }
7736
7737 // Might need to reconstruct things if this frame's nextSibling is a table
7738 // or ruby pseudo, since removal of this frame might mean that this pseudo
7739 // needs to get merged with the frame's prevSibling if that's also a table
7740 // or ruby pseudo.
7741 nsIFrame* nextSibling =
7742 FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation());
7743 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"
, 7744); MOZ_PretendNoReturn(); } } while (0)
7744 "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"
, 7744); MOZ_PretendNoReturn(); } } while (0)
;
7745 // Effectively, for the ruby pseudo sibling case, only pseudo <ruby> frame
7746 // need to be checked here, since all other types of such frames will have
7747 // a ruby container parent, and be catched by "Check ruby containers" below.
7748 if (nextSibling && IsWrapperPseudo(nextSibling)) {
7749 nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame);
7750 if (prevSibling && IsWrapperPseudo(prevSibling)) {
7751 TRACE("Pseudo sibling");
7752 // Good enough to recreate frames for aFrame's parent's content; even if
7753 // aFrame's parent is a pseudo, that'll be the right content node.
7754 // FIXME(emilio): Consider doing a more subtle check here like, only if
7755 // prevSibling and nextSibling share frame type. Or even consider just
7756 // moving the frames around and destroying nextSibling?
7757 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7758 return true;
7759 }
7760 }
7761
7762 // Check ruby containers
7763 if (const auto* ancestor = CheckRubyContainers(inFlowFrame, parent)) {
7764 // In ruby containers, pseudo frames may be created from
7765 // whitespaces or even nothing. There are two cases we actually
7766 // need to handle here, but hard to check exactly:
7767 // 1. Status of spaces beside the frame may vary, and related
7768 // frames may be constructed or destroyed accordingly.
7769 // 2. The type of the first child of a ruby frame determines
7770 // whether a pseudo ruby base container should exist.
7771 TRACE("Ruby container");
7772 RecreateFramesForContent(ancestor->GetContent(), InsertionKind::Async);
7773 return true;
7774 }
7775
7776 // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
7777 // a non-fluid continuation, i.e. it was split by bidi resolution
7778 if (!inFlowFrame->GetPrevSibling() && !inFlowFrame->GetNextSibling() &&
7779 ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
7780 (parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
7781 TRACE("Removing last child of non-fluid split parent");
7782 RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
7783 return true;
7784 }
7785
7786 // We might still need to reconstruct things if the parent of inFlowFrame is
7787 // ib-split, since in that case the removal of aFrame might affect the
7788 // splitting of its parent.
7789 if (!IsFramePartOfIBSplit(parent)) {
7790 return false;
7791 }
7792
7793 // If inFlowFrame is not the only in-flow child of |parent|, then removing
7794 // it will change nothing about the {ib} split.
7795 if (inFlowFrame != parent->PrincipalChildList().FirstChild() ||
7796 inFlowFrame->LastContinuation()->GetNextSibling()) {
7797 return false;
7798 }
7799
7800 // If the parent is the first or last part of the {ib} split, then
7801 // removing one of its kids will have no effect on the splitting.
7802 // Get the first continuation up front so we don't have to do it twice.
7803 nsIFrame* parentFirstContinuation = parent->FirstContinuation();
7804 if (!GetIBSplitSibling(parentFirstContinuation) ||
7805 !GetIBSplitPrevSibling(parentFirstContinuation)) {
7806 return false;
7807 }
7808
7809 TRACE("IB split parent");
7810 ReframeContainingBlock(parent);
7811 return true;
7812#undef TRACE
7813}
7814
7815void nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent) {
7816 nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
7817
7818 // It's possible that this warning could fire if some other style change
7819 // simultaneously changes the 'display' of the element and makes it no
7820 // longer be a table cell.
7821 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"
, 7821); } } while (false)
;
7822
7823 if (cellFrame) {
7824 cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
7825 }
7826}
7827
7828static nsIContent* GetTopmostMathMLElement(nsIContent* aMathMLContent) {
7829 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"
, 7829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->IsMathMLElement()"
")"); do { MOZ_CrashSequence(__null, 7829); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7830 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"
, 7830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()"
")"); do { MOZ_CrashSequence(__null, 7830); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7831 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"
, 7831); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMathMLContent->GetPrimaryFrame()->IsMathMLFrame()"
")"); do { MOZ_CrashSequence(__null, 7831); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7832 nsIContent* root = aMathMLContent;
7833
7834 for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent(); parent;
7835 parent = parent->GetFlattenedTreeParent()) {
7836 nsIFrame* frame = parent->GetPrimaryFrame();
7837 if (!frame || !frame->IsMathMLFrame()) {
7838 break;
7839 }
7840 root = parent;
7841 }
7842
7843 return root;
7844}
7845
7846// We don't know how to re-insert an anonymous subtree root, so recreate the
7847// closest non-generated ancestor instead, except for a few special cases...
7848static bool ShouldRecreateContainerForNativeAnonymousContentRoot(
7849 nsIContent* aContent) {
7850 if (!aContent->IsRootOfNativeAnonymousSubtree()) {
7851 return false;
7852 }
7853 if (ManualNACPtr::IsManualNAC(aContent)) {
7854 // Editor NAC, would enter an infinite loop, and we sorta get away with it
7855 // because it's all abspos.
7856 return false;
7857 }
7858 if (auto* el = Element::FromNode(aContent)) {
7859 if (el->GetPseudoElementType() ==
7860 PseudoStyleType::MozSnapshotContainingBlock) {
7861 // Much like above, all abspos and on its own top layer so insertion order
7862 // wouldn't really matter anyways.
7863 return false;
7864 }
7865 if (auto* classes = el->GetClasses()) {
7866 if (classes->Contains(nsGkAtoms::mozCustomContentContainer,
7867 eCaseMatters)) {
7868 // Canvas anonymous content (like the custom content container) is also
7869 // fine, because its only sibling is a tooltip which is also abspos, so
7870 // relative insertion order doesn't really matter.
7871 //
7872 // This is important because the inspector uses it, and we don't want
7873 // inspecting the page to change behavior heavily (and reframing
7874 // unfortunately has side-effects sometimes, even though they're bugs).
7875 return false;
7876 }
7877 }
7878 }
7879
7880 return true;
7881}
7882
7883void nsCSSFrameConstructor::RecreateFramesForContent(
7884 nsIContent* aContent, InsertionKind aInsertionKind) {
7885 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"
, 7885); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { MOZ_CrashSequence(__null, 7885); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7886
7887 // If there is no document, we don't want to recreate frames for it. (You
7888 // shouldn't generally be giving this method content without a document
7889 // anyway).
7890 // Rebuilding the frame tree can have bad effects, especially if it's the
7891 // frame tree for chrome (see bug 157322).
7892 if (NS_WARN_IF(!aContent->GetComposedDoc())NS_warn_if_impl(!aContent->GetComposedDoc(), "!aContent->GetComposedDoc()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 7892)
) {
7893 return;
7894 }
7895
7896 // TODO(emilio): We technically can find the right insertion point nowadays
7897 // using StyleChildrenIterator rather than FlattenedChildIterator. But we'd
7898 // need to tweak the setup to insert into replaced elements to filter which
7899 // anonymous roots can be allowed, and which can't.
7900 //
7901 // TODO(emilio, 2022): Is this true? If we have a replaced element we wouldn't
7902 // have generated e.g., a ::before/::after pseudo-element to begin with (which
7903 // is what this code is about, so maybe we can just remove this piece of code
7904 // altogether).
7905 if (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent)) {
7906 do {
7907 aContent = aContent->GetParent();
7908 } while (ShouldRecreateContainerForNativeAnonymousContentRoot(aContent));
7909 return RecreateFramesForContent(aContent, InsertionKind::Async);
7910 }
7911
7912 nsIFrame* frame = aContent->GetPrimaryFrame();
7913 if (frame && frame->IsMathMLFrame()) {
7914 // Reframe the topmost MathML element to prevent exponential blowup
7915 // (see bug 397518).
7916 aContent = GetTopmostMathMLElement(aContent);
7917 frame = aContent->GetPrimaryFrame();
7918 }
7919
7920 if (frame) {
7921 nsIFrame* parent = frame->GetParent();
7922 nsIContent* parentContent = parent ? parent->GetContent() : nullptr;
7923 // If the parent frame is a leaf then the subsequent insert will fail to
7924 // create a frame, so we need to recreate the parent content. This happens
7925 // with native anonymous content from the editor.
7926 if (parent && parent->IsLeaf() && parentContent &&
7927 parentContent != aContent) {
7928 return RecreateFramesForContent(parentContent, InsertionKind::Async);
7929 }
7930 }
7931
7932 if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
7933 return;
7934 }
7935
7936 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"
, 7936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 7936); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7937 const auto removalKind = [&] {
7938 if (aInsertionKind == InsertionKind::Sync && aContent->IsElement() &&
7939 Servo_Element_IsDisplayNone(aContent->AsElement())) {
7940 // If we know we're not going to have frames after reconstructing, it's
7941 // more efficient to do some of that work (a11y notifications, fixing-up
7942 // text nodes) earlier.
7943 return RemovalKind::ForDisplayNoneChange;
7944 }
7945 return RemovalKind::ForReconstruction;
7946 }();
7947 const bool didReconstruct = ContentWillBeRemoved(aContent, removalKind);
7948 if (didReconstruct || removalKind == RemovalKind::ForDisplayNoneChange) {
7949 // If ContentWillBeRemoved triggered reconstruction, then we don't need to
7950 // do anything else because the frames will already have been built.
7951 return;
7952 }
7953 if (aInsertionKind == InsertionKind::Async && aContent->IsElement()) {
7954 // FIXME(emilio, bug 1397239): There's nothing removing the frame state
7955 // for elements that go away before we come back to the frame constructor.
7956 //
7957 // Also, it'd be nice to just use the `ContentRangeInserted` path for
7958 // both elements and non-elements, but we need to make lazy frame
7959 // construction to apply to all elements first.
7960 //
7961 // TODO(emilio): I think lazy frame construction works everywhere now, so
7962 // maybe we can remove this altogether?
7963 RestyleManager()->PostRestyleEvent(aContent->AsElement(), RestyleHint{0},
7964 nsChangeHint_ReconstructFrame);
7965 return;
7966 }
7967 // Now, recreate the frames associated with this content object.
7968 ContentRangeInserted(aContent, aContent->GetNextSibling(), aInsertionKind);
7969}
7970
7971bool nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent) {
7972 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", 7972); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContent && aContent->GetParentNode()"
")"); do { MOZ_CrashSequence(__null, 7972); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7973 return ContentWillBeRemoved(aContent, RemovalKind::ForReconstruction);
7974}
7975
7976//////////////////////////////////////////////////////////////////////
7977
7978// Block frame construction code
7979
7980already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLetterStyle(
7981 nsIContent* aContent, ComputedStyle* aComputedStyle) {
7982 if (aContent) {
7983 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
7984 *aContent->AsElement(), PseudoStyleType::FirstLetter, nullptr,
7985 aComputedStyle);
7986 }
7987 return nullptr;
7988}
7989
7990already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLineStyle(
7991 nsIContent* aContent, ComputedStyle* aComputedStyle) {
7992 if (aContent) {
7993 return mPresShell->StyleSet()->ResolvePseudoElementStyle(
7994 *aContent->AsElement(), PseudoStyleType::FirstLine, nullptr,
7995 aComputedStyle);
7996 }
7997 return nullptr;
7998}
7999
8000// Predicate to see if a given content (block element) has
8001// first-letter style applied to it.
8002bool nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(
8003 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8004 return nsLayoutUtils::HasPseudoStyle(aContent, aComputedStyle,
8005 PseudoStyleType::FirstLetter,
8006 mPresShell->GetPresContext());
8007}
8008
8009bool nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) {
8010 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"
, 8010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBlockFrame"
") (" "Need a frame" ")"); do { MOZ_CrashSequence(__null, 8010
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8011 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", 8011); MOZ_PretendNoReturn
(); } } while (0)
;
8012 return aBlockFrame->HasAnyStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
8013}
8014
8015bool nsCSSFrameConstructor::ShouldHaveFirstLineStyle(
8016 nsIContent* aContent, ComputedStyle* aComputedStyle) {
8017 bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(
8018 aContent, aComputedStyle, PseudoStyleType::FirstLine,
8019 mPresShell->GetPresContext());
8020 return hasFirstLine &&
8021 !aContent->IsAnyOfHTMLElements(nsGkAtoms::fieldset, nsGkAtoms::input,
8022 nsGkAtoms::textarea);
8023}
8024
8025void nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(
8026 nsIContent* aContent, ComputedStyle* aComputedStyle,
8027 bool* aHaveFirstLetterStyle, bool* aHaveFirstLineStyle) {
8028 *aHaveFirstLetterStyle = ShouldHaveFirstLetterStyle(aContent, aComputedStyle);
8029 *aHaveFirstLineStyle = ShouldHaveFirstLineStyle(aContent, aComputedStyle);
8030}
8031
8032/* static */
8033const nsCSSFrameConstructor::PseudoParentData
8034 nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
8035 // Cell
8036 {{&nsCSSFrameConstructor::ConstructTableCell,
8037 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8038 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8039 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow)(((uint32_t)(eTypeRow)) << 28)},
8040 PseudoStyleType::MozTableCell},
8041 // Row
8042 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8043 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8044 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8045 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup)(((uint32_t)(eTypeRowGroup)) << 28)},
8046 PseudoStyleType::MozTableRow},
8047 // Row group
8048 {{&nsCSSFrameConstructor::ConstructTableRowOrRowGroup,
8049 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8050 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8051 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8052 PseudoStyleType::MozTableRowGroup},
8053 // Column group
8054 {{ToCreationFunc(NS_NewTableColGroupFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewTableColGroupFrame(aPs, aStyle); }
,
8055 FCDATA_IS_TABLE_PART0x800 | FCDATA_SKIP_FRAMESET0x1 |
8056 FCDATA_DISALLOW_OUT_OF_FLOW0x8 | FCDATA_USE_CHILD_ITEMS0x10000 |
8057 FCDATA_SKIP_ABSPOS_PUSH0x200 |
8058 // Not FCDATA_IS_WRAPPER_ANON_BOX, because we don't need to
8059 // restyle these: they have non-inheriting styles.
8060 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable)(((uint32_t)(eTypeTable)) << 28)},
8061 PseudoStyleType::MozTableColumnGroup},
8062 // Table
8063 {{&nsCSSFrameConstructor::ConstructTable,
8064 FCDATA_SKIP_FRAMESET0x1 | FCDATA_USE_CHILD_ITEMS0x10000 |
8065 FCDATA_IS_WRAPPER_ANON_BOX0x400000},
8066 PseudoStyleType::MozTable},
8067 // Ruby
8068 {{ToCreationFunc(NS_NewRubyFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyFrame(aPs, aStyle); }
,
8069 FCDATA_IS_LINE_PARTICIPANT0x2000 | FCDATA_USE_CHILD_ITEMS0x10000 |
8070 FCDATA_IS_WRAPPER_ANON_BOX0x400000 | FCDATA_SKIP_FRAMESET0x1},
8071 PseudoStyleType::MozRuby},
8072 // Ruby Base
8073 {{ToCreationFunc(NS_NewRubyBaseFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseFrame(aPs, aStyle); }
,
8074 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8075 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8076 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer)(((uint32_t)(eTypeRubyBaseContainer)) << 28) |
8077 FCDATA_SKIP_FRAMESET0x1},
8078 PseudoStyleType::MozRubyBase},
8079 // Ruby Base Container
8080 {{ToCreationFunc(NS_NewRubyBaseContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyBaseContainerFrame(aPs, aStyle); }
,
8081 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8082 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8083 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8084 FCDATA_SKIP_FRAMESET0x1},
8085 PseudoStyleType::MozRubyBaseContainer},
8086 // Ruby Text
8087 {{ToCreationFunc(NS_NewRubyTextFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextFrame(aPs, aStyle); }
,
8088 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_LINE_PARTICIPANT0x2000 |
8089 FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8090 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer)(((uint32_t)(eTypeRubyTextContainer)) << 28) |
8091 FCDATA_SKIP_FRAMESET0x1},
8092 PseudoStyleType::MozRubyText},
8093 // Ruby Text Container
8094 {{ToCreationFunc(NS_NewRubyTextContainerFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewRubyTextContainerFrame(aPs, aStyle); }
,
8095 FCDATA_USE_CHILD_ITEMS0x10000 | FCDATA_IS_WRAPPER_ANON_BOX0x400000 |
8096 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby)(((uint32_t)(eTypeRuby)) << 28) |
8097 FCDATA_SKIP_FRAMESET0x1},
8098 PseudoStyleType::MozRubyTextContainer}};
8099
8100void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
8101 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8102 nsIFrame* aParentFrame) {
8103 if (aItems.IsEmpty()) {
8104 return;
8105 }
8106
8107 if (!aParentFrame->IsFlexOrGridContainer()) {
8108 return;
8109 }
8110
8111 const bool isLegacyWebKitBox =
8112 IsFlexContainerForLegacyWebKitBox(aParentFrame);
8113 FCItemIterator iter(aItems);
8114 do {
8115 // Advance iter past children that don't want to be wrapped
8116 if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState,
8117 isLegacyWebKitBox)) {
8118 // Hit the end of the items without finding any remaining children that
8119 // need to be wrapped. We're finished!
8120 return;
8121 }
8122
8123 // If our next potentially-wrappable child is whitespace, then see if
8124 // there's anything wrappable immediately after it. If not, we just drop
8125 // the whitespace and move on. (We're not supposed to create any anonymous
8126 // flex/grid items that _only_ contain whitespace).
8127 // (BUT if this is generated content, then we don't give whitespace nodes
8128 // any special treatment, because they're probably not really whitespace --
8129 // they're just temporarily empty, waiting for their generated text.)
8130 // XXXdholbert If this node's generated text will *actually end up being
8131 // entirely whitespace*, then we technically should still skip over it, per
8132 // the CSS grid & flexbox specs. I'm not bothering with that at this point,
8133 // since it's a pretty extreme edge case.
8134 if (!aParentFrame->IsGeneratedContentFrame() &&
8135 iter.item().IsWhitespace(aState)) {
8136 FCItemIterator afterWhitespaceIter(iter);
8137 bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
8138 bool nextChildNeedsAnonItem =
8139 !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(
8140 aState, isLegacyWebKitBox);
8141
8142 if (!nextChildNeedsAnonItem) {
8143 // There's nothing after the whitespace that we need to wrap, so we
8144 // just drop this run of whitespace.
8145 iter.DeleteItemsTo(this, afterWhitespaceIter);
8146 if (hitEnd) {
8147 // Nothing left to do -- we're finished!
8148 return;
8149 }
8150 // else, we have a next child and it does not want to be wrapped. So,
8151 // we jump back to the beginning of the loop to skip over that child
8152 // (and anything else non-wrappable after it)
8153 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"
, 8155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8155); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8154 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"
, 8155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8155); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8155 "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"
, 8155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter.IsDone() && !iter.item().NeedsAnonFlexOrGridItem( aState, isLegacyWebKitBox)"
") (" "hitEnd and/or nextChildNeedsAnonItem lied" ")"); do {
MOZ_CrashSequence(__null, 8155); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8156 continue;
8157 }
8158 }
8159
8160 // Now |iter| points to the first child that needs to be wrapped in an
8161 // anonymous flex/grid item. Now we see how many children after it also want
8162 // to be wrapped in an anonymous flex/grid item.
8163 FCItemIterator endIter(iter); // iterator to find the end of the group
8164 endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox);
8165
8166 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", 8167); MOZ_PretendNoReturn
(); } } while (0)
8167 "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", 8167); MOZ_PretendNoReturn
(); } } while (0)
;
8168
8169 // Now, we create the anonymous flex or grid item to contain the children
8170 // between |iter| and |endIter|.
8171 nsIContent* parentContent = aParentFrame->GetContent();
8172 RefPtr<ComputedStyle> wrapperStyle =
8173 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8174 PseudoStyleType::MozAnonymousItem, aParentFrame->Style());
8175
8176 static constexpr FrameConstructionData sBlockFCData(
8177 ToCreationFunc(NS_NewBlockFrame)[](PresShell* aPs, ComputedStyle* aStyle) -> nsIFrame* { return
NS_NewBlockFrame(aPs, aStyle); }
, FCDATA_SKIP_FRAMESET0x1 |
8178 FCDATA_USE_CHILD_ITEMS0x10000 |
8179 FCDATA_IS_WRAPPER_ANON_BOX0x400000);
8180
8181 // Use the content of our parent frame
8182 auto* newItem = new (this) FrameConstructionItem(
8183 &sBlockFCData, parentContent, wrapperStyle.forget(), true);
8184
8185 newItem->mIsAllInline =
8186 newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
8187 newItem->mIsBlock = !newItem->mIsAllInline;
8188
8189 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"
, 8192); 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, 8192); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8190 "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"
, 8192); 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, 8192); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8191 "(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"
, 8192); 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, 8192); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8192 "'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"
, 8192); 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, 8192); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8193
8194 // Anonymous flex and grid items induce line boundaries around their
8195 // contents.
8196 newItem->mChildItems.SetLineBoundaryAtStart(true);
8197 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8198 // The parent of the items in aItems is also the parent of the items
8199 // in mChildItems
8200 newItem->mChildItems.SetParentHasNoShadowDOM(aItems.ParentHasNoShadowDOM());
8201
8202 // Eat up all items between |iter| and |endIter| and put them in our
8203 // wrapper. This advances |iter| to point to |endIter|.
8204 iter.AppendItemsToList(this, endIter, newItem->mChildItems);
8205
8206 iter.InsertItem(newItem);
8207 } while (!iter.IsDone());
8208}
8209
8210/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8211nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
8212 StyleDisplay aNextDisplay) {
8213 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"
, 8213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevDisplay.IsRuby() && aNextDisplay.IsRuby()"
")"); do { MOZ_CrashSequence(__null, 8213); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8214 if (aPrevDisplay == aNextDisplay &&
8215 (aPrevDisplay == StyleDisplay::RubyBase ||
8216 aPrevDisplay == StyleDisplay::RubyText)) {
8217 return eRubyInterLeafWhitespace;
8218 }
8219 if (aNextDisplay == StyleDisplay::RubyText ||
8220 aNextDisplay == StyleDisplay::RubyTextContainer) {
8221 return eRubyInterLevelWhitespace;
8222 }
8223 return eRubyInterSegmentWhitespace;
8224}
8225
8226/**
8227 * This function checks the content from |aStartIter| to |aEndIter|,
8228 * determines whether it contains only whitespace, and if yes,
8229 * interprets the type of whitespace. This method does not change
8230 * any of the iters.
8231 */
8232/* static */ nsCSSFrameConstructor::RubyWhitespaceType
8233nsCSSFrameConstructor::InterpretRubyWhitespace(nsFrameConstructorState& aState,
8234 const FCItemIterator& aStartIter,
8235 const FCItemIterator& aEndIter) {
8236 if (!aStartIter.item().IsWhitespace(aState)) {
8237 return eRubyNotWhitespace;
8238 }
8239
8240 FCItemIterator spaceEndIter(aStartIter);
8241 spaceEndIter.SkipWhitespace(aState);
8242 if (spaceEndIter != aEndIter) {
8243 return eRubyNotWhitespace;
8244 }
8245
8246 // Any leading or trailing whitespace in non-pseudo ruby box
8247 // should have been trimmed, hence there should not be any
8248 // whitespace at the start or the end.
8249 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", 8249); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!aStartIter.AtStart() && !aEndIter.IsDone()"
")"); do { MOZ_CrashSequence(__null, 8249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8250 FCItemIterator prevIter(aStartIter);
8251 prevIter.Prev();
8252 return ComputeRubyWhitespaceType(
8253 prevIter.item().mComputedStyle->StyleDisplay()->mDisplay,
8254 aEndIter.item().mComputedStyle->StyleDisplay()->mDisplay);
8255}
8256
8257/**
8258 * This function eats up consecutive items which do not want the current
8259 * parent into either a ruby base box or a ruby text box. When it
8260 * returns, |aIter| points to the first item it doesn't wrap.
8261 */
8262void nsCSSFrameConstructor::WrapItemsInPseudoRubyLeafBox(
8263 FCItemIterator& aIter, ComputedStyle* aParentStyle,
8264 nsIContent* aParentContent) {
8265 StyleDisplay parentDisplay = aParentStyle->StyleDisplay()->mDisplay;
8266 ParentType parentType, wrapperType;
8267 if (parentDisplay == StyleDisplay::RubyTextContainer) {
8268 parentType = eTypeRubyTextContainer;
8269 wrapperType = eTypeRubyText;
8270 } else {
8271 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", 8271); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "parentDisplay == StyleDisplay::RubyBaseContainer"
")"); do { MOZ_CrashSequence(__null, 8271); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8272 parentType = eTypeRubyBaseContainer;
8273 wrapperType = eTypeRubyBase;
8274 }
8275
8276 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"
, 8277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8277); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8277 "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"
, 8277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != parentType"
") (" "Should point to something needs to be wrapped." ")");
do { MOZ_CrashSequence(__null, 8277); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8278
8279 FCItemIterator endIter(aIter);
8280 endIter.SkipItemsNotWantingParentType(parentType);
8281
8282 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8283 endIter);
8284}
8285
8286/**
8287 * This function eats up consecutive items into a ruby level container.
8288 * It may create zero or one level container. When it returns, |aIter|
8289 * points to the first item it doesn't wrap.
8290 */
8291void nsCSSFrameConstructor::WrapItemsInPseudoRubyLevelContainer(
8292 nsFrameConstructorState& aState, FCItemIterator& aIter,
8293 ComputedStyle* aParentStyle, nsIContent* aParentContent) {
8294 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"
, 8295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8295); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8295 "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"
, 8295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIter.item().DesiredParentType() != eTypeRuby"
") (" "Pointing to a level container?" ")"); do { MOZ_CrashSequence
(__null, 8295); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8296
8297 FrameConstructionItem& firstItem = aIter.item();
8298 ParentType wrapperType = firstItem.DesiredParentType();
8299 if (wrapperType != eTypeRubyTextContainer) {
8300 // If the first item is not ruby text,
8301 // it should be in a base container.
8302 wrapperType = eTypeRubyBaseContainer;
8303 }
8304
8305 FCItemIterator endIter(aIter);
8306 do {
8307 if (endIter.SkipItemsWantingParentType(wrapperType) ||
8308 // If the skipping above stops at some item which wants a
8309 // different ruby parent, then we have finished.
8310 IsRubyParentType(endIter.item().DesiredParentType())) {
8311 // No more items need to be wrapped in this level container.
8312 break;
8313 }
8314
8315 FCItemIterator contentEndIter(endIter);
8316 contentEndIter.SkipItemsNotWantingRubyParent();
8317 // endIter must be on something doesn't want a ruby parent.
8318 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", 8318); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "contentEndIter != endIter" ")"); do { MOZ_CrashSequence
(__null, 8318); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8319
8320 // InterpretRubyWhitespace depends on the fact that any leading or
8321 // trailing whitespace described in the spec have been trimmed at
8322 // this point. With this precondition, it is safe not to check
8323 // whether contentEndIter has been done.
8324 RubyWhitespaceType whitespaceType =
8325 InterpretRubyWhitespace(aState, endIter, contentEndIter);
8326 if (whitespaceType == eRubyInterLevelWhitespace) {
8327 // Remove inter-level whitespace.
8328 bool atStart = (aIter == endIter);
8329 endIter.DeleteItemsTo(this, contentEndIter);
8330 if (atStart) {
8331 aIter = endIter;
8332 }
8333 } else if (whitespaceType == eRubyInterSegmentWhitespace) {
8334 // If this level container starts with inter-segment whitespaces,
8335 // wrap them. Break at contentEndIter. Otherwise, leave it here.
8336 // Break at endIter. They will be wrapped when we are here again.
8337 if (aIter == endIter) {
8338 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", 8339); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8339); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8339 "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", 8339); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "wrapperType == eTypeRubyBaseContainer" ") ("
"Inter-segment whitespace should be wrapped in rbc" ")"); do
{ MOZ_CrashSequence(__null, 8339); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8340 endIter = contentEndIter;
8341 }
8342 break;
8343 } else if (wrapperType == eTypeRubyTextContainer &&
8344 whitespaceType != eRubyInterLeafWhitespace) {
8345 // Misparented inline content that's not inter-annotation
8346 // whitespace doesn't belong in a pseudo ruby text container.
8347 // Break at endIter.
8348 break;
8349 } else {
8350 endIter = contentEndIter;
8351 }
8352 } while (!endIter.IsDone());
8353
8354 // It is possible that everything our parent wants us to wrap is
8355 // simply an inter-level whitespace, which has been trimmed, or
8356 // an inter-segment whitespace, which will be wrapped later.
8357 // In those cases, don't create anything.
8358 if (aIter != endIter) {
8359 WrapItemsInPseudoParent(aParentContent, aParentStyle, wrapperType, aIter,
8360 endIter);
8361 }
8362}
8363
8364/**
8365 * This function trims leading and trailing whitespaces
8366 * in the given item list.
8367 */
8368void nsCSSFrameConstructor::TrimLeadingAndTrailingWhitespaces(
8369 nsFrameConstructorState& aState, FrameConstructionItemList& aItems) {
8370 FCItemIterator iter(aItems);
8371 if (!iter.IsDone() && iter.item().IsWhitespace(aState)) {
8372 FCItemIterator spaceEndIter(iter);
8373 spaceEndIter.SkipWhitespace(aState);
8374 iter.DeleteItemsTo(this, spaceEndIter);
8375 }
8376
8377 iter.SetToEnd();
8378 if (!iter.AtStart()) {
8379 FCItemIterator spaceEndIter(iter);
8380 do {
8381 iter.Prev();
8382 if (iter.AtStart()) {
8383 // It's fine to not check the first item, because we
8384 // should have trimmed leading whitespaces above.
8385 break;
8386 }
8387 } while (iter.item().IsWhitespace(aState));
8388 iter.Next();
8389 if (iter != spaceEndIter) {
8390 iter.DeleteItemsTo(this, spaceEndIter);
8391 }
8392 }
8393}
8394
8395/**
8396 * This function walks through the child list (aItems) and creates
8397 * needed pseudo ruby boxes to wrap misparented children.
8398 */
8399void nsCSSFrameConstructor::CreateNeededPseudoInternalRubyBoxes(
8400 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8401 nsIFrame* aParentFrame) {
8402 const ParentType ourParentType = GetParentType(aParentFrame);
8403 if (!IsRubyParentType(ourParentType) ||
8404 aItems.AllWantParentType(ourParentType)) {
8405 return;
8406 }
8407
8408 if (!IsRubyPseudo(aParentFrame) ||
8409 ourParentType == eTypeRuby /* for 'display:block ruby' */) {
8410 // Normally, ruby pseudo frames start from and end at some elements,
8411 // which means they don't have leading and trailing whitespaces at
8412 // all. But there are two cases where they do actually have leading
8413 // or trailing whitespaces:
8414 // 1. It is an inter-segment whitespace which in an individual ruby
8415 // base container.
8416 // 2. The pseudo frame starts from or ends at consecutive inline
8417 // content, which is not pure whitespace, but includes some.
8418 // In either case, the whitespaces are not the leading or trailing
8419 // whitespaces defined in the spec, and thus should not be trimmed.
8420 TrimLeadingAndTrailingWhitespaces(aState, aItems);
8421 }
8422
8423 FCItemIterator iter(aItems);
8424 nsIContent* parentContent = aParentFrame->GetContent();
8425 ComputedStyle* parentStyle = aParentFrame->Style();
8426 while (!iter.IsDone()) {
8427 if (!iter.SkipItemsWantingParentType(ourParentType)) {
8428 if (ourParentType == eTypeRuby) {
8429 WrapItemsInPseudoRubyLevelContainer(aState, iter, parentStyle,
8430 parentContent);
8431 } else {
8432 WrapItemsInPseudoRubyLeafBox(iter, parentStyle, parentContent);
8433 }
8434 }
8435 }
8436}
8437
8438/*
8439 * This function works as follows: we walk through the child list (aItems) and
8440 * find items that cannot have aParentFrame as their parent. We wrap
8441 * continuous runs of such items into a FrameConstructionItem for a frame that
8442 * gets them closer to their desired parents. For example, a run of non-row
8443 * children of a row-group will get wrapped in a row. When we later construct
8444 * the frame for this wrapper (in this case for the row), it'll be the correct
8445 * parent for the cells in the set of items we wrapped or we'll wrap cells
8446 * around everything else. At the end of this method, aItems is guaranteed to
8447 * contain only items for frames that can be direct kids of aParentFrame.
8448 */
8449void nsCSSFrameConstructor::CreateNeededPseudoContainers(
8450 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8451 nsIFrame* aParentFrame) {
8452 ParentType ourParentType = GetParentType(aParentFrame);
8453 if (IsRubyParentType(ourParentType) ||
8454 aItems.AllWantParentType(ourParentType)) {
8455 // Nothing to do here
8456 return;
8457 }
8458
8459 FCItemIterator iter(aItems);
8460 do {
8461 if (iter.SkipItemsWantingParentType(ourParentType)) {
8462 // Nothing else to do here; we're finished
8463 return;
8464 }
8465
8466 // Now we're pointing to the first child that wants a different parent
8467 // type.
8468
8469 // Now try to figure out what kids we can group together. We can generally
8470 // group everything that has a different desired parent type from us. Two
8471 // exceptions to this:
8472 // 1) If our parent type is table, we can't group columns with anything
8473 // else other than whitespace.
8474 // 2) Whitespace that lies between two things we can group which both want
8475 // a non-block parent should be dropped, even if we can't group them
8476 // with each other and even if the whitespace wants a parent of
8477 // ourParentType. Ends of the list count as things that don't want a
8478 // block parent (so that for example we'll drop a whitespace-only list).
8479
8480 FCItemIterator endIter(iter); /* iterator to find the end of the group */
8481 ParentType groupingParentType = endIter.item().DesiredParentType();
8482 if (aItems.AllWantParentType(groupingParentType) &&
8483 groupingParentType != eTypeBlock) {
8484 // Just group them all and be done with it. We need the check for
8485 // eTypeBlock here to catch the "all the items are whitespace" case
8486 // described above.
8487 endIter.SetToEnd();
8488 } else {
8489 // Locate the end of the group.
8490
8491 // Keep track of the type the previous item wanted, in case we have to
8492 // deal with whitespace. Start it off with ourParentType, since that's
8493 // the last thing |iter| would have skipped over.
8494 ParentType prevParentType = ourParentType;
8495 do {
8496 // Walk an iterator past any whitespace that we might be able to drop
8497 // from the list
8498 FCItemIterator spaceEndIter(endIter);
8499 if (prevParentType != eTypeBlock &&
8500 !aParentFrame->IsGeneratedContentFrame() &&
8501 spaceEndIter.item().IsWhitespace(aState)) {
8502 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
8503
8504 // We drop the whitespace in the following cases:
8505 // 1) If these are not trailing spaces and the next item wants a table
8506 // or table-part parent
8507 // 2) If these are trailing spaces and aParentFrame is a
8508 // tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
8509 // (Being a tabular container pretty much means ourParentType is
8510 // not eTypeBlock besides the eTypeColGroup case, which won't
8511 // reach here.)
8512 if ((!trailingSpaces &&
8513 IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
8514 (trailingSpaces && ourParentType != eTypeBlock)) {
8515 bool updateStart = (iter == endIter);
8516 endIter.DeleteItemsTo(this, spaceEndIter);
8517 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", 8518); MOZ_PretendNoReturn
(); } } while (0)
8518 "These should match")do { if (!(trailingSpaces == endIter.IsDone())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "These should match", "trailingSpaces == endIter.IsDone()"
, "./../../../layout/base/nsCSSFrameConstructor.cpp", 8518); MOZ_PretendNoReturn
(); } } while (0)
;
8519
8520 if (updateStart) {
8521 iter = endIter;
8522 }
8523
8524 if (trailingSpaces) {
8525 break; /* Found group end */
8526 }
8527
8528 if (updateStart) {
8529 // Update groupingParentType, since it might have been eTypeBlock
8530 // just because of the whitespace.
8531 groupingParentType = iter.item().DesiredParentType();
8532 }
8533 }
8534 }
8535
8536 // Now endIter points to a non-whitespace item or a non-droppable
8537 // whitespace item. In the latter case, if this is the end of the group
8538 // we'll traverse this whitespace again. But it'll all just be quick
8539 // DesiredParentType() checks which will match ourParentType (that's
8540 // what it means that this is the group end), so it's OK.
8541 // However, when we are grouping a ruby parent, and endIter points to
8542 // a non-droppable whitespace, if the next non-whitespace item also
8543 // wants a ruby parent, the whitespace should also be included into
8544 // the current ruby container.
8545 prevParentType = endIter.item().DesiredParentType();
8546 if (prevParentType == ourParentType &&
8547 (endIter == spaceEndIter || spaceEndIter.IsDone() ||
8548 !IsRubyParentType(groupingParentType) ||
8549 !IsRubyParentType(spaceEndIter.item().DesiredParentType()))) {
8550 // End the group at endIter.
8551 break;
8552 }
8553
8554 if (ourParentType == eTypeTable &&
8555 (prevParentType == eTypeColGroup) !=
8556 (groupingParentType == eTypeColGroup)) {
8557 // Either we started with columns and now found something else, or
8558 // vice versa. In any case, end the grouping.
8559 break;
8560 }
8561
8562 // If we have some whitespace that we were not able to drop and there is
8563 // an item after the whitespace that is already properly parented, then
8564 // make sure to include the spaces in our group but stop the group after
8565 // that.
8566 if (spaceEndIter != endIter && !spaceEndIter.IsDone() &&
8567 ourParentType == spaceEndIter.item().DesiredParentType()) {
8568 endIter = spaceEndIter;
8569 break;
8570 }
8571
8572 // Include the whitespace we didn't drop (if any) in the group.
8573 endIter = spaceEndIter;
8574 prevParentType = endIter.item().DesiredParentType();
8575
8576 endIter.Next();
8577 } while (!endIter.IsDone());
8578 }
8579
8580 if (iter == endIter) {
8581 // Nothing to wrap here; just skipped some whitespace
8582 continue;
8583 }
8584
8585 if (ourParentType == eTypeColGroup) {
8586 // Suppress non-col items of colgroups.
8587 iter.DeleteItemsTo(this, endIter);
8588 continue;
8589 }
8590
8591 // Now group together all the items between iter and endIter. The right
8592 // parent type to use depends on ourParentType.
8593 ParentType wrapperType;
8594 switch (ourParentType) {
8595 case eTypeRow:
8596 // The parent type for a cell is eTypeBlock, since that's what a cell
8597 // looks like to its kids.
8598 wrapperType = eTypeBlock;
8599 break;
8600 case eTypeRowGroup:
8601 wrapperType = eTypeRow;
8602 break;
8603 case eTypeTable:
8604 // Either colgroup or rowgroup, depending on what we're grouping.
8605 wrapperType =
8606 groupingParentType == eTypeColGroup ? eTypeColGroup : eTypeRowGroup;
8607 break;
8608 case eTypeColGroup:
8609 MOZ_FALLTHROUGH_ASSERT("handled above")do { do { } while (false); MOZ_ReportCrash("" "MOZ_FALLTHROUGH_ASSERT: "
"handled above", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 8609); AnnotateMozCrashReason("MOZ_CRASH(" "MOZ_FALLTHROUGH_ASSERT: "
"handled above" ")"); do { MOZ_CrashSequence(__null, 8609); __attribute__
((nomerge)) ::abort(); } while (false); } while (false)
;
8610 default:
8611 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"
, 8611); MOZ_PretendNoReturn(); } } while (0)
;
8612 if (IsRubyParentType(groupingParentType)) {
8613 wrapperType = eTypeRuby;
8614 } else {
8615 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"
, 8616); MOZ_PretendNoReturn(); } } while (0)
8616 "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"
, 8616); MOZ_PretendNoReturn(); } } while (0)
;
8617 wrapperType = eTypeTable;
8618 }
8619 }
8620
8621 ComputedStyle* parentStyle = aParentFrame->Style();
8622 WrapItemsInPseudoParent(aParentFrame->GetContent(), parentStyle,
8623 wrapperType, iter, endIter);
8624
8625 // Now |iter| points to the item that was the first one we didn't wrap;
8626 // loop and see whether we need to skip it or wrap it in something
8627 // different.
8628 } while (!iter.IsDone());
8629}
8630
8631/**
8632 * This method wraps frame construction item from |aIter| to
8633 * |aEndIter|. After it returns, aIter points to the first item
8634 * after the wrapper.
8635 */
8636void nsCSSFrameConstructor::WrapItemsInPseudoParent(
8637 nsIContent* aParentContent, ComputedStyle* aParentStyle,
8638 ParentType aWrapperType, FCItemIterator& aIter,
8639 const FCItemIterator& aEndIter) {
8640 const PseudoParentData& pseudoData = sPseudoParentData[aWrapperType];
8641 PseudoStyleType pseudoType = pseudoData.mPseudoType;
8642 auto& parentDisplay = *aParentStyle->StyleDisplay();
8643 auto parentDisplayInside = parentDisplay.DisplayInside();
8644
8645 // XXXmats should we use IsInlineInsideStyle() here instead? seems odd to
8646 // exclude RubyBaseContainer/RubyTextContainer...
8647 if (pseudoType == PseudoStyleType::MozTable &&
8648 (parentDisplay.IsInlineFlow() ||
8649 parentDisplayInside == StyleDisplayInside::RubyBase ||
8650 parentDisplayInside == StyleDisplayInside::RubyText)) {
8651 pseudoType = PseudoStyleType::MozInlineTable;
8652 }
8653
8654 RefPtr<ComputedStyle> wrapperStyle;
8655 if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX0x400000) {
8656 wrapperStyle = mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8657 pseudoType, aParentStyle);
8658 } else {
8659 wrapperStyle =
8660 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
8661 pseudoType);
8662 }
8663
8664 // Use the content of our parent frame
8665 auto* newItem = new (this) FrameConstructionItem(
8666 &pseudoData.mFCData, aParentContent, wrapperStyle.forget(), true);
8667
8668 const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
8669 // Here we're cheating a tad... technically, table-internal items should be
8670 // inline if aParentFrame is inline, but they'll get wrapped in an
8671 // inline-table in the end, so it'll all work out. In any case, arguably
8672 // we don't need to maintain this state at this point... but it's better
8673 // to, I guess.
8674 newItem->mIsAllInline = disp->IsInlineOutsideStyle();
8675
8676 bool isRuby = disp->IsRubyDisplayType();
8677 if (!isRuby) {
8678 // Table pseudo frames always induce line boundaries around their
8679 // contents.
8680 newItem->mChildItems.SetLineBoundaryAtStart(true);
8681 newItem->mChildItems.SetLineBoundaryAtEnd(true);
8682 }
8683 // The parent of the items in aItems is also the parent of the items
8684 // in mChildItems
8685 newItem->mChildItems.SetParentHasNoShadowDOM(
8686 aIter.List()->ParentHasNoShadowDOM());
8687
8688 // Eat up all items between |aIter| and |aEndIter| and put them in our
8689 // wrapper Advances |aIter| to point to |aEndIter|.
8690 aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
8691
8692 aIter.InsertItem(newItem);
8693}
8694
8695void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
8696 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8697 nsIFrame* aParentFrame) {
8698 if (aItems.IsEmpty() || GetParentType(aParentFrame) != eTypeRuby) {
8699 return;
8700 }
8701
8702 FCItemIterator iter(aItems);
8703 StyleDisplay firstDisplay =
8704 iter.item().mComputedStyle->StyleDisplay()->mDisplay;
8705 if (firstDisplay == StyleDisplay::RubyBaseContainer) {
8706 return;
8707 }
8708 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"
, 8709); MOZ_PretendNoReturn(); } } while (0)
8709 "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"
, 8709); MOZ_PretendNoReturn(); } } while (0)
;
8710
8711 const PseudoParentData& pseudoData =
8712 sPseudoParentData[eTypeRubyBaseContainer];
8713 RefPtr<ComputedStyle> pseudoStyle =
8714 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
8715 pseudoData.mPseudoType, aParentFrame->Style());
8716 FrameConstructionItem* newItem = new (this) FrameConstructionItem(
8717 &pseudoData.mFCData,
8718 // Use the content of the parent frame
8719 aParentFrame->GetContent(), pseudoStyle.forget(), true);
8720 newItem->mIsAllInline = true;
8721 newItem->mChildItems.SetParentHasNoShadowDOM(true);
8722 iter.InsertItem(newItem);
8723}
8724
8725#ifdef DEBUG1
8726/**
8727 * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
8728 * rather than being a direct child of aContainerFrame.
8729 *
8730 * NOTE: aContainerFrame must be a flex or grid container - this function is
8731 * purely for sanity-checking the children of these container types.
8732 * NOTE: See also NeedsAnonFlexOrGridItem(), for the non-debug version of this
8733 * logic (which operates a bit earlier, on FCData instead of frames).
8734 */
8735static bool FrameWantsToBeInAnonymousItem(const nsIFrame* aContainerFrame,
8736 const nsIFrame* aFrame) {
8737 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", 8737); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aContainerFrame->IsFlexOrGridContainer()"
")"); do { MOZ_CrashSequence(__null, 8737); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8738
8739 // Any line-participant frames (e.g. text) definitely want to be wrapped in
8740 // an anonymous flex/grid item.
8741 if (aFrame->IsLineParticipant()) {
8742 return true;
8743 }
8744
8745 // If the container is a -webkit-{inline-}box container, then placeholders
8746 // also need to be wrapped, for compatibility.
8747 if (IsFlexContainerForLegacyWebKitBox(aContainerFrame) &&
8748 aFrame->IsPlaceholderFrame()) {
8749 return true;
8750 }
8751
8752 return false;
8753}
8754#endif
8755
8756static void VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
8757 const nsFrameList& aChildren) {
8758#ifdef DEBUG1
8759 if (!aParentFrame->IsFlexOrGridContainer()) {
8760 return;
8761 }
8762
8763 bool prevChildWasAnonItem = false;
8764 for (const nsIFrame* child : aChildren) {
8765 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", 8766
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8766); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8766 "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", 8766
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FrameWantsToBeInAnonymousItem(aParentFrame, child)"
") (" "frame wants to be inside an anonymous item, but it isn't"
")"); do { MOZ_CrashSequence(__null, 8766); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8767 if (IsAnonymousItem(child)) {
8768 AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
8769 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"
, 8769); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!prevChildWasAnonItem"
") (" "two anon items in a row" ")"); do { MOZ_CrashSequence
(__null, 8769); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8770 nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
8771 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"
, 8771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "firstWrappedChild"
") (" "anonymous item shouldn't be empty" ")"); do { MOZ_CrashSequence
(__null, 8771); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8772 prevChildWasAnonItem = true;
8773 } else {
8774 prevChildWasAnonItem = false;
8775 }
8776 }
8777#endif
8778}
8779
8780static bool FrameHasOnlyPlaceholderPrevSiblings(const nsIFrame* aFrame) {
8781 // Check for prev siblings, ignoring placeholder frames.
8782 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", 8782
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8782); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8783 const nsIFrame* prevSibling = aFrame;
8784 do {
8785 prevSibling = prevSibling->GetPrevSibling();
8786 } while (prevSibling && prevSibling->IsPlaceholderFrame());
8787 return !prevSibling;
8788}
8789
8790static bool FrameHasOnlyPlaceholderNextSiblings(const nsIFrame* aFrame) {
8791 // Check for next siblings, ignoring placeholder frames.
8792 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", 8792
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "frame must not be null"
")"); do { MOZ_CrashSequence(__null, 8792); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8793 const nsIFrame* nextSibling = aFrame;
8794 do {
8795 nextSibling = nextSibling->GetNextSibling();
8796 } while (nextSibling && nextSibling->IsPlaceholderFrame());
8797 return !nextSibling;
8798}
8799
8800static void SetPageValues(nsIFrame* const aFrame,
8801 const nsAtom* const aAutoValue,
8802 const nsAtom* const aStartValue,
8803 const nsAtom* const aEndValue) {
8804 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", 8804
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAutoValue" ") ("
"Auto page value should never be null" ")"); do { MOZ_CrashSequence
(__null, 8804); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8805 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"
, 8805); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartValue || aEndValue"
") (" "Should not have called with no values" ")"); do { MOZ_CrashSequence
(__null, 8805); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8806 nsIFrame::PageValues* pageValues =
8807 aFrame->GetProperty(nsIFrame::PageValuesProperty());
8808
8809 if (aStartValue) {
8810 if (aStartValue == aAutoValue) {
8811 // If the page value struct already exists, set the start value to null
8812 // to indicate the auto value.
8813 if (pageValues) {
8814 pageValues->mStartPageValue = nullptr;
8815 }
8816 } else {
8817 // The start value is not auto, so we need to store it, creating the
8818 // page values struct if it does not already exist.
8819 if (!pageValues) {
8820 pageValues = new nsIFrame::PageValues();
8821 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8822 }
8823 pageValues->mStartPageValue = aStartValue;
8824 }
8825 }
8826 if (aEndValue) {
8827 if (aEndValue == aAutoValue) {
8828 // If the page value struct already exists, set the end value to null
8829 // to indicate the auto value.
8830 if (pageValues) {
8831 pageValues->mEndPageValue = nullptr;
8832 }
8833 } else {
8834 // The end value is not auto, so we need to store it, creating the
8835 // page values struct if it does not already exist.
8836 if (!pageValues) {
8837 pageValues = new nsIFrame::PageValues();
8838 aFrame->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8839 }
8840 pageValues->mEndPageValue = aEndValue;
8841 }
8842 }
8843}
8844
8845inline void nsCSSFrameConstructor::ConstructFramesFromItemList(
8846 nsFrameConstructorState& aState, FrameConstructionItemList& aItems,
8847 nsContainerFrame* aParentFrame, bool aParentIsWrapperAnonBox,
8848 nsFrameList& aFrameList) {
8849#ifdef DEBUG1
8850 // The assertion condition should match the logic in
8851 // MaybePushFloatContainingBlock().
8852 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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8853 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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8854 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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8855 "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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8856 "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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
8857 "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"
, 8857); 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, 8857
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
8858 aState.mFloatCBCandidate = nullptr;
8859#endif
8860
8861 // Ensure aParentIsWrapperAnonBox is correct. We _could_ compute it directly,
8862 // but it would be a bit slow, which is why we pass it from callers, who have
8863 // that information offhand in many cases.
8864 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", 8864); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox"
")"); do { MOZ_CrashSequence(__null, 8864); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8865
8866 // Note: we explicitly exclude TableColGroupFrame because it doesn't
8867 // have the FCDATA_IS_WRAPPER_ANON_BOX on pseudos so aParentIsWrapperAnonBox
8868 // is false for such pseudos (see sPseudoParentData below).
8869 if (!aParentIsWrapperAnonBox && aState.mHasRenderedLegend &&
8870 aParentFrame->GetContent()->IsHTMLElement(nsGkAtoms::fieldset) &&
8871 !aParentFrame->IsTableColGroupFrame()) {
8872 DebugOnly<bool> found = false;
8873 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8874 if (iter.item().mIsRenderedLegend) {
8875 // This makes the rendered legend the first frame in the fieldset child
8876 // list which makes keyboard traversal follow the visual order.
8877 nsFieldSetFrame* fieldSetFrame = GetFieldSetFrameFor(aParentFrame);
8878 nsFrameList renderedLegend;
8879 ConstructFramesFromItem(aState, iter, fieldSetFrame, renderedLegend);
8880 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"
, 8881); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8881); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8881 "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"
, 8881); AnnotateMozCrashReason("MOZ_ASSERT" "(" "renderedLegend.OnlyChild()"
") (" "a rendered legend should have exactly one frame" ")")
; do { MOZ_CrashSequence(__null, 8881); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8882 fieldSetFrame->InsertFrames(FrameChildListID::Principal, nullptr,
8883 nullptr, std::move(renderedLegend));
8884 FCItemIterator next = iter;
8885 next.Next();
8886 iter.DeleteItemsTo(this, next);
8887 found = true;
8888 break;
8889 }
8890 }
8891 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", 8891
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "found" ") (" "should have found our rendered legend"
")"); do { MOZ_CrashSequence(__null, 8891); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8892 }
8893
8894 CreateNeededPseudoContainers(aState, aItems, aParentFrame);
8895 CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
8896 CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
8897 CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
8898
8899 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
8900 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"
, 8902); 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, 8902); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8901 "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"
, 8902); 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, 8902); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
8902 "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"
, 8902); 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, 8902); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8903 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", 8904); MOZ_PretendNoReturn
(); } } while (0)
8904 "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", 8904); MOZ_PretendNoReturn
(); } } while (0)
;
8905 ConstructFramesFromItem(aState, iter, aParentFrame, aFrameList);
8906 }
8907
8908 VerifyGridFlexContainerChildren(aParentFrame, aFrameList);
8909
8910 // Calculate and propagate page-name values for each frame in the frame list.
8911 // We do not want to compute and propagate page-name values from frames that
8912 // are children of any subclasses of block frames, but not actually a block
8913 // frame. The page-name property does not apply to frames which cannot create
8914 // class A breakpoints (currently no subclass of BlockFrame can). Because the
8915 // property does not apply, those children also cannot propagate page-name
8916 // values.
8917 // This assumption helps avoid unnecessarily handling page-names for frames
8918 // such as form controls, which also avoids bug 1819468.
8919 if (aState.mPresContext->IsPaginated() && aParentFrame->IsBlockFrame()) {
8920 // Set the start/end page values while iterating the frame list, to walk
8921 // up the frame tree only once after iterating the frame list.
8922 // This also avoids extra property lookups on these frames.
8923 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"
, 8925); 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, 8925); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8924 "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"
, 8925); 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, 8925); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8925 "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"
, 8925); 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, 8925); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8926 // Even though we store null for page values that equal the "auto" resolved
8927 // value on frames, we always want startPageValue/endPageValue to be the
8928 // actual atoms reflecting the start/end values. This is because when we
8929 // propagate the values up the frame tree, we will need to compare them to
8930 // the auto value for each ancestor. This value might be different than the
8931 // auto value for this frame.
8932 const nsAtom* startPageValue = nullptr;
8933 const nsAtom* endPageValue = nullptr;
8934 for (nsIFrame* f : aFrameList) {
8935 if (f->IsPlaceholderFrame()) {
8936 continue;
8937 }
8938 // Resolve auto against the parent frame's used page name, which has been
8939 // determined and set on aState.mAutoPageNameValue. If this item is not
8940 // block-level then we use the value that auto resolves to.
8941 //
8942 // This is to achieve the propagation behavior described in the spec:
8943 //
8944 // "A start page value and end page value is determined for each box as
8945 // the value (if any) propagated from its first or last child box
8946 // (respectively), else the used value on the box itself."
8947 //
8948 // "A child propagates its own start or end page value if and only if the
8949 // page property applies to it."
8950 //
8951 // The page property only applies to "boxes that create class A break
8952 // points". When taken together, this means that non block-level children
8953 // do not propagate start/end page values, and instead we use "the used
8954 // value on the box itself", the "box itself" being aParentFrame. This
8955 // value has been determined and saved as aState.mAutoPageNameValue
8956 //
8957 // https://www.w3.org/TR/css-page-3/#using-named-pages
8958 // https://www.w3.org/TR/css-break-3/#btw-blocks
8959 const StylePageName& pageName = f->StylePage()->mPage;
8960 const nsAtom* const pageNameAtom =
8961 (pageName.IsPageName() && f->IsBlockOutside())
8962 ? pageName.AsPageName().AsAtom()
8963 : aState.mAutoPageNameValue;
8964 nsIFrame::PageValues* pageValues =
8965 f->GetProperty(nsIFrame::PageValuesProperty());
8966 // If this frame has any children, it will already have had its page
8967 // values set at this point. However, if no page values have been set,
8968 // we must ensure that the appropriate PageValuesProperty value has been
8969 // set.
8970 // If the page name is equal to the auto value, then PageValuesProperty
8971 // should remain null to indicate that the start/end values are both
8972 // equal to the auto value.
8973 if (pageNameAtom != aState.mAutoPageNameValue && !pageValues) {
8974 pageValues = new nsIFrame::PageValues{pageNameAtom, pageNameAtom};
8975 f->SetProperty(nsIFrame::PageValuesProperty(), pageValues);
8976 }
8977 // We don't want to use GetStartPageValue() or GetEndPageValue(), as each
8978 // requires a property lookup which we can avoid here.
8979 if (!startPageValue) {
8980 startPageValue = (pageValues && pageValues->mStartPageValue)
8981 ? pageValues->mStartPageValue.get()
8982 : aState.mAutoPageNameValue;
8983 }
8984 endPageValue = (pageValues && pageValues->mEndPageValue)
8985 ? pageValues->mEndPageValue.get()
8986 : aState.mAutoPageNameValue;
8987 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"
, 8988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 8988); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
8988 "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"
, 8988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "startPageValue && endPageValue"
") (" "Should have found start/end page value" ")"); do { MOZ_CrashSequence
(__null, 8988); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8989 }
8990 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", 8991
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 8991); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
8991 "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", 8991
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!startPageValue == !endPageValue"
") (" "Should have set both or neither page values" ")"); do
{ MOZ_CrashSequence(__null, 8991); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
8992 if (startPageValue) {
8993 // Walk up the frame tree from our parent frame, propagating start and
8994 // end page values.
8995 // As we go, if we find that, for a frame, we are not contributing one of
8996 // the start/end page values, then our subtree will not contribute this
8997 // value from that frame onward. startPageValue/endPageValue are set to
8998 // null to indicate this.
8999 // Stop iterating when we are not contributing either start or end
9000 // values, when we hit the root frame (no parent), or when we find a
9001 // frame that is not a block frame.
9002 for (nsContainerFrame* ancestorFrame = aParentFrame;
9003 (startPageValue || endPageValue) && ancestorFrame &&
9004 ancestorFrame->IsBlockFrame();
9005 ancestorFrame = ancestorFrame->GetParent()) {
9006 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", 9007
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9007); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9007 "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", 9007
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ancestorFrame->GetPrevInFlow()"
") (" "Should not have fragmentation yet" ")"); do { MOZ_CrashSequence
(__null, 9007); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9008 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", 9010
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9010); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9009 "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", 9010
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9010); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9010 "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", 9010
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorFrame->mWasVisitedByAutoFrameConstructionPageName"
") (" "Frame should have been visited by " "AutoFrameConstructionPageName"
")"); do { MOZ_CrashSequence(__null, 9010); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9011 {
9012 // Get what the auto value is, based on this frame's parent.
9013 // For the root frame, `auto` resolves to the empty atom.
9014 const nsContainerFrame* const parent = ancestorFrame->GetParent();
9015 const nsAtom* const parentAuto = MOZ_LIKELY(parent)(__builtin_expect(!!(parent), 1))
9016 ? parent->GetAutoPageValue()
9017 : nsGkAtoms::_empty;
9018 SetPageValues(ancestorFrame, parentAuto, startPageValue,
9019 endPageValue);
9020 }
9021 // Once we stop contributing start/end values, we know there is a
9022 // sibling subtree that contributed that value to our shared parent
9023 // instead of our starting frame's subtree. This means once
9024 // startPageValue/endPageValue becomes null, indicating that we are no
9025 // longer contributing that page value, it should stay null and we no
9026 // longer need to check for siblings in that direction.
9027 if (startPageValue &&
9028 !FrameHasOnlyPlaceholderPrevSiblings(ancestorFrame)) {
9029 startPageValue = nullptr;
9030 }
9031 if (endPageValue &&
9032 !FrameHasOnlyPlaceholderNextSiblings(ancestorFrame)) {
9033 endPageValue = nullptr;
9034 }
9035 }
9036 }
9037 }
9038
9039 if (aParentIsWrapperAnonBox) {
9040 for (nsIFrame* f : aFrameList) {
9041 f->SetParentIsWrapperAnonBox();
9042 }
9043 }
9044}
9045
9046void nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
9047 nsFrameConstructorState& aState, nsContainerFrame* aFrame,
9048 const nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems,
9049 FrameConstructionItemList& aItemsToConstruct,
9050 const AutoFrameConstructionPageName&) {
9051 for (const auto& info : aAnonymousItems) {
9052 nsIContent* content = info.mContent;
9053 // Gecko-styled nodes should have no pending restyle flags.
9054 // Assert some things about this content
9055 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"
, 9057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9057); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9056 (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"
, 9057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9057); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9057 "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"
, 9057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(content->GetFlags() & (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME))"
") (" "Should not be marked as needing frames" ")"); do { MOZ_CrashSequence
(__null, 9057); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9058 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", 9058
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!content->GetPrimaryFrame()"
") (" "Should have no existing frame" ")"); do { MOZ_CrashSequence
(__null, 9058); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9059 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", 9060); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9060); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9060 "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", 9060); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsComment() && !content->IsProcessingInstruction()"
") (" "Why is someone creating garbage anonymous content" ")"
); do { MOZ_CrashSequence(__null, 9060); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9061
9062 // Make sure we eagerly performed the servo cascade when the anonymous
9063 // nodes were created.
9064 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", 9064); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!content->IsElement() || content->AsElement()->HasServoData()"
")"); do { MOZ_CrashSequence(__null, 9064); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9065
9066 RefPtr<ComputedStyle> computedStyle = ResolveComputedStyle(content);
9067
9068 AddFrameConstructionItemsInternal(aState, content, aFrame, true,
9069 computedStyle, {ItemFlag::AllowPageBreak},
9070 aItemsToConstruct);
9071 }
9072}
9073
9074void nsCSSFrameConstructor::ProcessChildren(
9075 nsFrameConstructorState& aState, nsIContent* aContent,
9076 ComputedStyle* aComputedStyle, nsContainerFrame* aFrame,
9077 const bool aCanHaveGeneratedContent, nsFrameList& aFrameList,
9078 const bool aAllowBlockStyles, nsIFrame* aPossiblyLeafFrame) {
9079 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", 9079
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame" ") (" "Must have parent frame here"
")"); do { MOZ_CrashSequence(__null, 9079); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9080 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", 9082
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9081 "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", 9082
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9082 "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", 9082
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->GetContentInsertionFrame() == aFrame"
") (" "Parent frame in ProcessChildren should be its own " "content insertion frame"
")"); do { MOZ_CrashSequence(__null, 9082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9083
9084 const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH1026;
9085 static_assert(kMaxDepth <= UINT16_MAX(65535), "mCurrentDepth type is too narrow");
9086 AutoRestore<uint16_t> savedDepth(mCurrentDepth);
9087 if (mCurrentDepth != UINT16_MAX(65535)) {
9088 ++mCurrentDepth;
9089 }
9090
9091 if (!aPossiblyLeafFrame) {
9092 aPossiblyLeafFrame = aFrame;
9093 }
9094
9095 // XXXbz ideally, this would do all the pushing of various
9096 // containing blocks as needed, so callers don't have to do it...
9097
9098 // Check that our parent frame is a block before allowing ::first-letter/line.
9099 // E.g. <button style="display:grid"> should not allow it.
9100 const bool allowFirstPseudos =
9101 aAllowBlockStyles && aFrame->IsBlockFrameOrSubclass();
9102 bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
9103 if (allowFirstPseudos) {
9104 ShouldHaveSpecialBlockStyle(aContent, aComputedStyle, &haveFirstLetterStyle,
9105 &haveFirstLineStyle);
9106 }
9107
9108 AutoFrameConstructionItemList itemsToConstruct(this);
9109 AutoFrameConstructionPageName pageNameTracker(aState, aFrame);
9110
9111 // If we have first-letter or first-line style then frames can get
9112 // moved around so don't set these flags.
9113 if (allowFirstPseudos && !haveFirstLetterStyle && !haveFirstLineStyle) {
9114 itemsToConstruct.SetLineBoundaryAtStart(true);
9115 itemsToConstruct.SetLineBoundaryAtEnd(true);
9116 }
9117
9118 // Create any anonymous frames we need here.
9119 AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
9120 GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
9121#ifdef DEBUG1
9122 for (auto& item : anonymousItems) {
9123 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"
, 9124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9124); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
9124 "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"
, 9124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item.mContent->IsRootOfNativeAnonymousSubtree()"
") (" "Content should know it's an anonymous subtree" ")"); do
{ MOZ_CrashSequence(__null, 9124); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
9125 }
9126#endif
9127 AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems,
9128 itemsToConstruct, pageNameTracker);
9129
9130 // Generated content should have the same style parent as normal kids.
9131 //
9132 // Note that we don't use this style for looking up things like special
9133 // block styles because in some cases involving table pseudo-frames it has
9134 // nothing to do with the parent frame's desired behavior.
9135 auto* styleParentFrame =
9136 nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo);
9137 ComputedStyle* parentStyle = styleParentFrame->Style();
9138 if (parentStyle->StyleDisplay()->mTopLayer == StyleTopLayer::Auto &&
9139 !aContent->IsInNativeAnonymousSubtree()) {
9140 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9141 *parentStyle, PseudoStyleType::Backdrop,
9142 itemsToConstruct);
9143 }
9144
9145 nsBlockFrame* listItem = nullptr;
9146 bool isOutsideMarker = false;
9147 if (!aPossiblyLeafFrame->IsLeaf()) {
9148 if (aCanHaveGeneratedContent) {
9149 if (parentStyle->StyleDisplay()->IsListItem() &&
9150 (listItem = do_QueryFrame(aFrame)) &&
9151 !styleParentFrame->IsFieldSetFrame()) {
9152 isOutsideMarker = parentStyle->StyleList()->mListStylePosition ==
9153 StyleListStylePosition::Outside;
9154 ItemFlags extraFlags;
9155 if (isOutsideMarker) {
9156 extraFlags += ItemFlag::IsForOutsideMarker;
9157 }
9158 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9159 *parentStyle, PseudoStyleType::Marker,
9160 itemsToConstruct, extraFlags);
9161 }
9162 if (aContent->IsHTMLElement(nsGkAtoms::option)) {
9163 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9164 *parentStyle, PseudoStyleType::Checkmark,
9165 itemsToConstruct);
9166 }
9167 // Probe for generated content before
9168 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9169 *parentStyle, PseudoStyleType::Before,
9170 itemsToConstruct);
9171 }
9172
9173 const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth)(__builtin_expect(!!(mCurrentDepth < kMaxDepth), 1));
9174 if (!addChildItems) {
9175 NS_WARNING("ProcessChildren max depth exceeded")NS_DebugBreak(NS_DEBUG_WARNING, "ProcessChildren max depth exceeded"
, nullptr, "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 9175)
;
9176 }
9177
9178 FlattenedChildIterator iter(aContent);
9179 const InsertionPoint insertion(aFrame, aContent);
9180 for (nsIContent* child = iter.GetNextChild(); child;
9181 child = iter.GetNextChild()) {
9182 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"
, 9183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9183); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
9183 "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"
, 9183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertion.mContainer == GetInsertionPoint(child).mContainer"
") (" "GetInsertionPoint should agree with us" ")"); do { MOZ_CrashSequence
(__null, 9183); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9184 if (addChildItems) {
9185 AddFrameConstructionItems(aState, child, iter.ShadowDOMInvolved(),
9186 *parentStyle, insertion, itemsToConstruct);
9187 } else {
9188 ClearLazyBits(child, child->GetNextSibling());
9189 }
9190 }
9191 itemsToConstruct.SetParentHasNoShadowDOM(!iter.ShadowDOMInvolved());
9192
9193 if (aCanHaveGeneratedContent) {
9194 // Probe for generated content after
9195 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9196 *parentStyle, PseudoStyleType::After,
9197 itemsToConstruct);
9198 if (aContent->IsHTMLElement(nsGkAtoms::select)) {
9199 CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(),
9200 *parentStyle, PseudoStyleType::PickerIcon,
9201 itemsToConstruct);
9202 }
9203 }
9204 } else {
9205 ClearLazyBits(aContent->GetFirstChild(), nullptr);
9206 }
9207
9208 ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
9209 /* aParentIsWrapperAnonBox = */ false,
9210 aFrameList);
9211
9212 if (listItem) {
9213 if (auto* markerFrame = nsLayoutUtils::GetMarkerFrame(aContent)) {
9214 for (auto* childFrame : aFrameList) {
9215 if (markerFrame == childFrame) {
9216 if (isOutsideMarker) {
9217 // SetMarkerFrameForListItem will add childFrame to the marker list.
9218 aFrameList.RemoveFrame(childFrame);
9219 auto* grandParent = listItem->GetParent()->GetParent();
9220 if (listItem->Style()->GetPseudoType() ==
9221 PseudoStyleType::MozColumnContent &&
9222 grandParent && grandParent->IsColumnSetWrapperFrame()) {
9223 listItem = do_QueryFrame(grandParent);
9224 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"
, 9226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9226); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9225 "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"
, 9226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9226); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9226 "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"
, 9226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "listItem" ") ("
"ColumnSetWrapperFrame is expected to be " "a nsBlockFrame subclass"
")"); do { MOZ_CrashSequence(__null, 9226); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9227 childFrame->SetParent(listItem);
9228 }
9229 }
9230 listItem->SetMarkerFrameForListItem(childFrame);
9231 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", 9231); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "listItem->HasOutsideMarker() == isOutsideMarker"
")"); do { MOZ_CrashSequence(__null, 9231); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9232#ifdef ACCESSIBILITY1
9233 if (nsAccessibilityService* accService = GetAccService()) {
9234 auto* marker = markerFrame->GetContent();
9235 accService->ContentRangeInserted(mPresShell, marker, nullptr);
9236 }
9237#endif
9238 break;
9239 }
9240 }
9241 }
9242 }
9243
9244 if (haveFirstLetterStyle) {
9245 WrapFramesInFirstLetterFrame(aFrame, aFrameList);
9246 }
9247 if (haveFirstLineStyle) {
9248 WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, aFrameList);
9249 }
9250}
9251
9252//----------------------------------------------------------------------
9253
9254// Support for :first-line style
9255
9256// Special routine to handle placing a list of frames into a block
9257// frame that has first-line style. The routine ensures that the first
9258// collection of inline frames end up in a first-line frame.
9259// NOTE: aState may have containing block information related to a
9260// different part of the frame tree than where the first line occurs.
9261// In particular aState may be set up for where ContentInserted or
9262// ContentAppended is inserting content, which may be some
9263// non-first-in-flow continuation of the block to which the first-line
9264// belongs. So this function needs to be careful about how it uses
9265// aState.
9266void nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9267 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9268 nsContainerFrame* aBlockFrame, nsFirstLineFrame* aLineFrame,
9269 nsFrameList& aFrameList) {
9270 // Extract any initial inline frames from aFrameList so we can put them
9271 // in the first-line.
9272 nsFrameList firstLineChildren =
9273 aFrameList.Split([](nsIFrame* f) { return !f->IsInlineOutside(); });
9274
9275 if (firstLineChildren.IsEmpty()) {
9276 // Nothing is supposed to go into the first-line; nothing to do
9277 return;
9278 }
9279
9280 if (!aLineFrame) {
9281 // Create line frame
9282 ComputedStyle* parentStyle = nsIFrame::CorrectStyleParentFrame(
9283 aBlockFrame, PseudoStyleType::FirstLine)
9284 ->Style();
9285 RefPtr<ComputedStyle> firstLineStyle =
9286 GetFirstLineStyle(aBlockContent, parentStyle);
9287
9288 aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
9289
9290 // Initialize the line frame
9291 InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame);
9292
9293 // The lineFrame will be the block's first child; the rest of the
9294 // frame list (after lastInlineFrame) will be the second and
9295 // subsequent children; insert lineFrame into aFrameList.
9296 aFrameList.InsertFrame(nullptr, nullptr, aLineFrame);
9297
9298 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", 9299); MOZ_PretendNoReturn
(); } } while (0)
9299 "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", 9299); MOZ_PretendNoReturn
(); } } while (0)
;
9300 }
9301
9302 // Give the inline frames to the lineFrame <b>after</b> reparenting them
9303 ReparentFrames(this, aLineFrame, firstLineChildren, true);
9304 if (aLineFrame->PrincipalChildList().IsEmpty() &&
9305 aLineFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
9306 aLineFrame->SetInitialChildList(FrameChildListID::Principal,
9307 std::move(firstLineChildren));
9308 } else {
9309 AppendFrames(aLineFrame, FrameChildListID::Principal,
9310 std::move(firstLineChildren));
9311 }
9312}
9313
9314// Special routine to handle appending a new frame to a block frame's
9315// child list. Takes care of placing the new frame into the right
9316// place when first-line style is present.
9317void nsCSSFrameConstructor::AppendFirstLineFrames(
9318 nsFrameConstructorState& aState, nsIContent* aBlockContent,
9319 nsContainerFrame* aBlockFrame, nsFrameList& aFrameList) {
9320 // It's possible that aBlockFrame needs to have a first-line frame
9321 // created because it doesn't currently have any children.
9322 const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
9323 if (blockKids.IsEmpty()) {
9324 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, nullptr,
9325 aFrameList);
9326 return;
9327 }
9328
9329 // Examine the last block child - if it's a first-line frame then
9330 // appended frames need special treatment.
9331 nsIFrame* lastBlockKid = blockKids.LastChild();
9332 if (!lastBlockKid->IsLineFrame()) {
9333 // No first-line frame at the end of the list, therefore there is
9334 // an intervening block between any first-line frame the frames
9335 // we are appending. Therefore, we don't need any special
9336 // treatment of the appended frames.
9337 return;
9338 }
9339
9340 nsFirstLineFrame* lineFrame = static_cast<nsFirstLineFrame*>(lastBlockKid);
9341 WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, lineFrame,
9342 aFrameList);
9343}
9344
9345void nsCSSFrameConstructor::CheckForFirstLineInsertion(
9346 nsIFrame* aParentFrame, nsFrameList& aFrameList) {
9347 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"
, 9348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9348); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
9348 "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"
, 9348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame->Style()->IsInFirstLineSubtree()"
") (" "Why were we called?" ")"); do { MOZ_CrashSequence(__null
, 9348); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
9349
9350 if (aFrameList.IsEmpty()) {
9351 // Happens often enough, with the caption stuff. No need to do the ancestor
9352 // walk here.
9353 return;
9354 }
9355
9356 class RestyleManager* restyleManager = RestyleManager();
9357
9358 // Check whether there's a ::first-line on the path up from aParentFrame.
9359 // Note that we can't stop until we've run out of ancestors with
9360 // pseudo-element data, because the first-letter might be somewhere way up the
9361 // tree; in particular it might be past our containing block.
9362 nsIFrame* ancestor = aParentFrame;
9363 while (ancestor) {
9364 if (!ancestor->Style()->IsInFirstLineSubtree()) {
9365 // We know we won't find a ::first-line now.
9366 return;
9367 }
9368
9369 if (!ancestor->IsLineFrame()) {
9370 ancestor = ancestor->GetParent();
9371 continue;
9372 }
9373
9374 if (!ancestor->Style()->IsPseudoElement()) {
9375 // This is a continuation lineframe, not the first line; no need to do
9376 // anything to the styles.
9377 return;
9378 }
9379
9380 // Fix up the styles of aFrameList for ::first-line.
9381 for (nsIFrame* f : aFrameList) {
9382 restyleManager->ReparentComputedStyleForFirstLine(f);
9383 }
9384 return;
9385 }
9386}
9387
9388//----------------------------------------------------------------------
9389
9390// First-letter support
9391
9392// Determine how many characters in the text fragment apply to the
9393// first letter
9394static int32_t FirstLetterCount(
9395 const CharacterDataBuffer* aCharacterDataBuffer) {
9396 int32_t count = 0;
9397 int32_t firstLetterLength = 0;
9398
9399 const uint32_t n = aCharacterDataBuffer->GetLength();
9400 for (uint32_t i = 0; i < n; i++) {
9401 const char16_t ch = aCharacterDataBuffer->CharAt(i);
9402 // FIXME: take content language into account when deciding whitespace.
9403 if (dom::IsSpaceCharacter(ch)) {
9404 if (firstLetterLength) {
9405 break;
9406 }
9407 count++;
9408 continue;
9409 }
9410 // XXX I18n
9411 if ((ch == '\'') || (ch == '\"')) {
9412 if (firstLetterLength) {
9413 break;
9414 }
9415 // keep looping
9416 firstLetterLength = 1;
9417 } else {
9418 count++;
9419 break;
9420 }
9421 }
9422
9423 return count;
9424}
9425
9426static bool NeedFirstLetterContinuation(Text* aText) {
9427 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", 9427); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aText" ") (" "null ptr" ")"); do { MOZ_CrashSequence
(__null, 9427); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9428 int32_t flc = FirstLetterCount(&aText->DataBuffer());
9429 int32_t tl = aText->TextDataLength();
9430 return flc < tl;
9431}
9432
9433static bool IsFirstLetterContent(Text* aText) {
9434 return aText->TextDataLength() && !aText->TextIsOnlyWhitespace();
9435}
9436
9437/**
9438 * Create a letter frame, only make it a floating frame.
9439 */
9440nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
9441 nsFrameConstructorState& aState, Text* aTextContent, nsIFrame* aTextFrame,
9442 nsContainerFrame* aParentFrame, ComputedStyle* aParentStyle,
9443 ComputedStyle* aComputedStyle, nsFrameList& aResult) {
9444 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"
, 9444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentStyle"
")"); do { MOZ_CrashSequence(__null, 9444); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9445
9446 nsFirstLetterFrame* letterFrame =
9447 NS_NewFloatingFirstLetterFrame(mPresShell, aComputedStyle);
9448 // We don't want to use a text content for a non-text frame (because we want
9449 // its primary frame to be a text frame).
9450 nsIContent* letterContent = aParentFrame->GetContent();
9451 nsContainerFrame* containingBlock =
9452 aState.GetGeometricParent(*aComputedStyle->StyleDisplay(), aParentFrame);
9453 InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame);
9454
9455 // Init the text frame to refer to the letter frame.
9456 //
9457 // Make sure we get a proper style for it (the one passed in is for the letter
9458 // frame and will have the float property set on it; the text frame shouldn't
9459 // have that set).
9460 ServoStyleSet* styleSet = mPresShell->StyleSet();
9461 RefPtr<ComputedStyle> textSC =
9462 styleSet->ResolveStyleForText(aTextContent, aComputedStyle);
9463 aTextFrame->SetComputedStyleWithoutNotification(textSC);
9464 InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame);
9465
9466 // And then give the text frame to the letter frame
9467 SetInitialSingleChild(letterFrame, aTextFrame);
9468
9469 // See if we will need to continue the text frame (does it contain
9470 // more than just the first-letter text or not?) If it does, then we
9471 // create (in advance) a continuation frame for it.
9472 nsIFrame* nextTextFrame = nullptr;
9473 if (NeedFirstLetterContinuation(aTextContent)) {
9474 // Create continuation
9475 nextTextFrame = CreateContinuingFrame(aTextFrame, aParentFrame);
9476 RefPtr<ComputedStyle> newSC =
9477 styleSet->ResolveStyleForText(aTextContent, aParentStyle);
9478 nextTextFrame->SetComputedStyle(newSC);
9479 }
9480
9481 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", 9481); MOZ_PretendNoReturn
(); } } while (0)
;
9482 // Put the new float before any of the floats in the block we're doing
9483 // first-letter for, that is, before any floats whose parent is
9484 // containingBlock.
9485 nsIFrame* prevSibling = nullptr;
9486 for (nsIFrame* f : aState.mFloatedList) {
9487 if (f->GetParent() == containingBlock) {
9488 break;
9489 }
9490 prevSibling = f;
9491 }
9492
9493 aState.AddChild(letterFrame, aResult, letterContent, aParentFrame, false,
9494 true, true, prevSibling);
9495
9496 if (nextTextFrame) {
9497 aResult.AppendFrame(nullptr, nextTextFrame);
9498 }
9499
9500 return letterFrame;
9501}
9502
9503/**
9504 * Create a new letter frame for aTextFrame. The letter frame will be
9505 * a child of aParentFrame.
9506 */
9507void nsCSSFrameConstructor::CreateLetterFrame(
9508 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9509 Text* aTextContent, nsContainerFrame* aParentFrame, nsFrameList& aResult) {
9510 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", 9510); MOZ_PretendNoReturn
(); } } while (0)
;
9511
9512 // Get a ComputedStyle for the first-letter-frame.
9513 //
9514 // Keep this in sync with nsBlockFrame::UpdatePseudoElementStyles.
9515 nsIFrame* parentFrame = nsIFrame::CorrectStyleParentFrame(
9516 aParentFrame, PseudoStyleType::FirstLetter);
9517
9518 ComputedStyle* parentComputedStyle = parentFrame->Style();
9519 ComputedStyle* parentComputedStyleIgnoringFirstLine = parentComputedStyle;
9520 if (parentFrame->IsLineFrame()) {
9521 parentComputedStyleIgnoringFirstLine =
9522 nsIFrame::CorrectStyleParentFrame(aBlockFrame,
9523 PseudoStyleType::FirstLetter)
9524 ->Style();
9525 }
9526
9527 // Use content from containing block so that we can actually
9528 // find a matching style rule.
9529 nsIContent* blockContent = aBlockFrame->GetContent();
9530
9531 // Create first-letter style rule, ignoring first line. If we already have a
9532 // first-line we'll reparent the style below.
9533 RefPtr<ComputedStyle> sc =
9534 GetFirstLetterStyle(blockContent, parentComputedStyleIgnoringFirstLine);
9535
9536 if (sc) {
9537 if (parentComputedStyleIgnoringFirstLine != parentComputedStyle) {
9538 sc = mPresShell->StyleSet()->ReparentComputedStyle(
9539 sc, parentComputedStyle, parentComputedStyle,
9540 blockContent->AsElement());
9541 }
9542
9543 RefPtr<ComputedStyle> textSC =
9544 mPresShell->StyleSet()->ResolveStyleForText(aTextContent, sc);
9545
9546 // Create a new text frame (the original one will be discarded)
9547 // pass a temporary stylecontext, the correct one will be set
9548 // later. Start off by unsetting the primary frame for
9549 // aTextContent, so it's no longer pointing to the to-be-destroyed
9550 // frame.
9551 // XXXbz it would be really nice to destroy the old frame _first_,
9552 // then create the new one, so we could avoid this hack.
9553 aTextContent->SetPrimaryFrame(nullptr);
9554 nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
9555
9556 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", 9557); MOZ_PretendNoReturn
(); } } while (0)
9557 "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", 9557); MOZ_PretendNoReturn
(); } } while (0)
;
9558 nsFrameConstructorState state(
9559 mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
9560 GetAbsoluteContainingBlock(aParentFrame, ABS_POS), aBlockContinuation);
9561
9562 // Create the right type of first-letter frame
9563 const nsStyleDisplay* display = sc->StyleDisplay();
9564 nsFirstLetterFrame* letterFrame;
9565 if (display->IsFloatingStyle() && !aParentFrame->IsInSVGTextSubtree()) {
9566 // Make a floating first-letter frame
9567 letterFrame = CreateFloatingLetterFrame(state, aTextContent, textFrame,
9568 aParentFrame, parentComputedStyle,
9569 sc, aResult);
9570 } else {
9571 // Make an inflow first-letter frame
9572 letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
9573
9574 // Initialize the first-letter-frame. We don't want to use a text
9575 // content for a non-text frame (because we want its primary frame to
9576 // be a text frame).
9577 nsIContent* letterContent = aParentFrame->GetContent();
9578 letterFrame->Init(letterContent, aParentFrame, nullptr);
9579
9580 InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame);
9581
9582 SetInitialSingleChild(letterFrame, textFrame);
9583 aResult.Clear();
9584 aResult.AppendFrame(nullptr, letterFrame);
9585 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"
, 9586); MOZ_PretendNoReturn(); } } while (0)
9586 "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"
, 9586); MOZ_PretendNoReturn(); } } while (0)
;
9587 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9588 }
9589 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", 9591
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9591); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9590 !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", 9591
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9591); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
9591 "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", 9591
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBlockFrame->GetPrevContinuation()"
") (" "Setting up a first-letter frame on a non-first block continuation?"
")"); do { MOZ_CrashSequence(__null, 9591); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9592 auto parent =
9593 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9594 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9595 parent = static_cast<nsContainerFrame*>(
9596 parent->GetParent()->FirstContinuation());
9597 }
9598 parent->SetHasFirstLetterChild();
9599 aBlockFrame->SetProperty(nsContainerFrame::FirstLetterProperty(),
9600 letterFrame);
9601 aTextContent->SetPrimaryFrame(textFrame);
9602 }
9603}
9604
9605void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9606 nsContainerFrame* aBlockFrame, nsFrameList& aBlockFrames) {
9607 aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9608
9609 nsContainerFrame* parentFrame = nullptr;
9610 nsIFrame* textFrame = nullptr;
9611 nsIFrame* prevFrame = nullptr;
9612 nsFrameList letterFrames;
9613 bool stopLooking = false;
9614 WrapFramesInFirstLetterFrame(
9615 aBlockFrame, aBlockFrame, aBlockFrame, aBlockFrames.FirstChild(),
9616 &parentFrame, &textFrame, &prevFrame, letterFrames, &stopLooking);
9617 if (!parentFrame) {
9618 return;
9619 }
9620 DestroyContext context(mPresShell);
9621 if (parentFrame == aBlockFrame) {
9622 // Take textFrame out of the block's frame list and substitute the
9623 // letter frame(s) instead.
9624 aBlockFrames.DestroyFrame(context, textFrame);
9625 aBlockFrames.InsertFrames(nullptr, prevFrame, std::move(letterFrames));
9626 } else {
9627 // Take the old textFrame out of the inline parent's child list
9628 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9629
9630 // Insert in the letter frame(s)
9631 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9632 std::move(letterFrames));
9633 }
9634}
9635
9636void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
9637 nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
9638 nsContainerFrame* aParentFrame, nsIFrame* aParentFrameList,
9639 nsContainerFrame** aModifiedParent, nsIFrame** aTextFrame,
9640 nsIFrame** aPrevFrame, nsFrameList& aLetterFrames, bool* aStopLooking) {
9641 nsIFrame* prevFrame = nullptr;
9642 nsIFrame* frame = aParentFrameList;
9643
9644 // This loop attempts to implement "Finding the First Letter":
9645 // https://drafts.csswg.org/css-pseudo-4/#application-in-css
9646 // FIXME: we don't handle nested blocks correctly yet though (bug 214004)
9647 while (frame) {
9648 nsIFrame* nextFrame = frame->GetNextSibling();
9649
9650 // Skip all ::markers and placeholders.
9651 if (frame->Style()->GetPseudoType() == PseudoStyleType::Marker ||
9652 frame->IsPlaceholderFrame()) {
9653 prevFrame = frame;
9654 frame = nextFrame;
9655 continue;
9656 }
9657 LayoutFrameType frameType = frame->Type();
9658 if (LayoutFrameType::Text == frameType) {
9659 // Wrap up first-letter content in a letter frame
9660 Text* textContent = frame->GetContent()->AsText();
9661 if (IsFirstLetterContent(textContent)) {
9662 // Create letter frame to wrap up the text
9663 CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
9664 aParentFrame, aLetterFrames);
9665
9666 // Provide adjustment information for parent
9667 *aModifiedParent = aParentFrame;
9668 *aTextFrame = frame;
9669 *aPrevFrame = prevFrame;
9670 *aStopLooking = true;
9671 return;
9672 }
9673 } else if (IsInlineFrame(frame) && frameType != LayoutFrameType::Br) {
9674 nsIFrame* kids = frame->PrincipalChildList().FirstChild();
9675 WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation,
9676 static_cast<nsContainerFrame*>(frame), kids,
9677 aModifiedParent, aTextFrame, aPrevFrame,
9678 aLetterFrames, aStopLooking);
9679 if (*aStopLooking) {
9680 return;
9681 }
9682 } else {
9683 // This will stop us looking to create more letter frames. For
9684 // example, maybe the frame-type is "letterFrame" or
9685 // "placeholderFrame". This keeps us from creating extra letter
9686 // frames, and also prevents us from creating letter frames when
9687 // the first real content child of a block is not text (e.g. an
9688 // image, hr, etc.)
9689 *aStopLooking = true;
9690 break;
9691 }
9692
9693 prevFrame = frame;
9694 frame = nextFrame;
9695 }
9696}
9697
9698static nsIFrame* FindFirstLetterFrame(nsIFrame* aFrame,
9699 FrameChildListID aListID) {
9700 for (nsIFrame* f : aFrame->GetChildList(aListID)) {
9701 if (f->IsLetterFrame()) {
9702 return f;
9703 }
9704 }
9705 return nullptr;
9706}
9707
9708static void ClearHasFirstLetterChildFrom(nsContainerFrame* aParentFrame) {
9709 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"
, 9709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParentFrame"
")"); do { MOZ_CrashSequence(__null, 9709); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9710 auto* parent =
9711 static_cast<nsContainerFrame*>(aParentFrame->FirstContinuation());
9712 if (MOZ_UNLIKELY(parent->IsLineFrame())(__builtin_expect(!!(parent->IsLineFrame()), 0))) {
9713 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"
, 9713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9713); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9714 parent = static_cast<nsContainerFrame*>(
9715 parent->GetParent()->FirstContinuation());
9716 }
9717 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"
, 9717); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parent->HasFirstLetterChild()"
")"); do { MOZ_CrashSequence(__null, 9717); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9718 parent->ClearHasFirstLetterChild();
9719}
9720
9721void nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
9722 PresShell* aPresShell, nsIFrame* aBlockFrame) {
9723 // Look for the first letter frame on the FrameChildListID::Float, then
9724 // FrameChildListID::PushedFloats.
9725 nsIFrame* floatFrame =
9726 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::Float);
9727 if (!floatFrame) {
9728 floatFrame =
9729 ::FindFirstLetterFrame(aBlockFrame, FrameChildListID::PushedFloats);
9730 if (!floatFrame) {
9731 return;
9732 }
9733 }
9734
9735 // Take the text frame away from the letter frame (so it isn't
9736 // destroyed when we destroy the letter frame).
9737 nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
9738 if (!textFrame) {
9739 return;
9740 }
9741
9742 // Discover the placeholder frame for the letter frame
9743 nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
9744 if (!placeholderFrame) {
9745 // Somethings really wrong
9746 return;
9747 }
9748 nsContainerFrame* parentFrame = placeholderFrame->GetParent();
9749 if (!parentFrame) {
9750 // Somethings really wrong
9751 return;
9752 }
9753
9754 ClearHasFirstLetterChildFrom(parentFrame);
9755
9756 // Create a new text frame with the right style that maps all of the content
9757 // that was previously part of the letter frame (and probably continued
9758 // elsewhere).
9759 ComputedStyle* parentSC = parentFrame->Style();
9760 nsIContent* textContent = textFrame->GetContent();
9761 if (!textContent) {
9762 return;
9763 }
9764 RefPtr<ComputedStyle> newSC =
9765 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9766 nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
9767 newTextFrame->Init(textContent, parentFrame, nullptr);
9768
9769 // Destroy the old text frame's continuations (the old text frame
9770 // will be destroyed when its letter frame is destroyed).
9771 nsIFrame* frameToDelete = textFrame->LastContinuation();
9772 DestroyContext context(mPresShell);
9773 while (frameToDelete != textFrame) {
9774 nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
9775 RemoveFrame(context, FrameChildListID::Principal, frameToDelete);
9776 frameToDelete = nextFrameToDelete;
9777 }
9778
9779 nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
9780
9781 // Now that everything is set...
9782#ifdef NOISY_FIRST_LETTER
9783 printf(
9784 "RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p "
9785 "newTextFrame=%p\n",
9786 textContent.get(), textFrame, newTextFrame);
9787#endif
9788
9789 // Remove placeholder frame and the float
9790 RemoveFrame(context, FrameChildListID::Principal, placeholderFrame);
9791
9792 // Now that the old frames are gone, we can start pointing to our
9793 // new primary frame.
9794 textContent->SetPrimaryFrame(newTextFrame);
9795
9796 // Wallpaper bug 822910.
9797 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9798 if (offsetsNeedFixing) {
9799 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9800 }
9801
9802 // Insert text frame in its place
9803 InsertFrames(parentFrame, FrameChildListID::Principal, prevSibling,
9804 nsFrameList(newTextFrame, newTextFrame));
9805
9806 if (offsetsNeedFixing) {
9807 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9808 }
9809}
9810
9811void nsCSSFrameConstructor::RemoveFirstLetterFrames(
9812 PresShell* aPresShell, nsContainerFrame* aFrame,
9813 nsContainerFrame* aBlockFrame, bool* aStopLooking) {
9814 nsIFrame* prevSibling = nullptr;
9815 nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
9816
9817 while (kid) {
9818 if (kid->IsLetterFrame()) {
9819 ClearHasFirstLetterChildFrom(aFrame);
9820 nsIFrame* textFrame = kid->PrincipalChildList().FirstChild();
9821 if (!textFrame) {
9822 break;
9823 }
9824
9825 // Create a new textframe
9826 ComputedStyle* parentSC = aFrame->Style();
9827 if (!parentSC) {
9828 break;
9829 }
9830 nsIContent* textContent = textFrame->GetContent();
9831 if (!textContent) {
9832 break;
9833 }
9834 RefPtr<ComputedStyle> newSC =
9835 aPresShell->StyleSet()->ResolveStyleForText(textContent, parentSC);
9836 textFrame = NS_NewTextFrame(aPresShell, newSC);
9837 textFrame->Init(textContent, aFrame, nullptr);
9838
9839 DestroyContext context(mPresShell);
9840
9841 // Next rip out the kid and replace it with the text frame
9842 RemoveFrame(context, FrameChildListID::Principal, kid);
9843
9844 // Now that the old frames are gone, we can start pointing to our
9845 // new primary frame.
9846 textContent->SetPrimaryFrame(textFrame);
9847
9848 // Wallpaper bug 822910.
9849 bool offsetsNeedFixing = prevSibling && prevSibling->IsTextFrame();
9850 if (offsetsNeedFixing) {
9851 prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING);
9852 }
9853
9854 // Insert text frame in its place
9855 InsertFrames(aFrame, FrameChildListID::Principal, prevSibling,
9856 nsFrameList(textFrame, textFrame));
9857
9858 if (offsetsNeedFixing) {
9859 prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
9860 }
9861
9862 *aStopLooking = true;
9863 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"
, 9864); MOZ_PretendNoReturn(); } } while (0)
9864 "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"
, 9864); MOZ_PretendNoReturn(); } } while (0)
;
9865 aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
9866 break;
9867 }
9868 if (IsInlineFrame(kid)) {
9869 nsContainerFrame* kidAsContainerFrame = do_QueryFrame(kid);
9870 if (kidAsContainerFrame) {
9871 // Look inside child inline frame for the letter frame.
9872 RemoveFirstLetterFrames(aPresShell, kidAsContainerFrame, aBlockFrame,
9873 aStopLooking);
9874 if (*aStopLooking) {
9875 break;
9876 }
9877 }
9878 }
9879 prevSibling = kid;
9880 kid = kid->GetNextSibling();
9881 }
9882}
9883
9884void nsCSSFrameConstructor::RemoveLetterFrames(PresShell* aPresShell,
9885 nsContainerFrame* aBlockFrame) {
9886 aBlockFrame =
9887 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9888 aBlockFrame->RemoveProperty(nsContainerFrame::FirstLetterProperty());
9889 nsContainerFrame* continuation = aBlockFrame;
9890
9891 bool stopLooking = false;
9892 do {
9893 RemoveFloatingFirstLetterFrames(aPresShell, continuation);
9894 RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
9895 &stopLooking);
9896 if (stopLooking) {
9897 break;
9898 }
9899 continuation =
9900 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9901 } while (continuation);
9902}
9903
9904// Fixup the letter frame situation for the given block
9905void nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame) {
9906 aBlockFrame =
9907 static_cast<nsContainerFrame*>(aBlockFrame->FirstContinuation());
9908 nsContainerFrame* continuation = aBlockFrame;
9909
9910 nsContainerFrame* parentFrame = nullptr;
9911 nsIFrame* textFrame = nullptr;
9912 nsIFrame* prevFrame = nullptr;
9913 nsFrameList letterFrames;
9914 bool stopLooking = false;
9915 do {
9916 // XXX shouldn't this bit be set already (bug 408493), assert instead?
9917 continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
9918 WrapFramesInFirstLetterFrame(
9919 aBlockFrame, continuation, continuation,
9920 continuation->PrincipalChildList().FirstChild(), &parentFrame,
9921 &textFrame, &prevFrame, letterFrames, &stopLooking);
9922 if (stopLooking) {
9923 break;
9924 }
9925 continuation =
9926 static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
9927 } while (continuation);
9928
9929 if (!parentFrame) {
9930 return;
9931 }
9932 // Take the old textFrame out of the parent's child list
9933 DestroyContext context(mPresShell);
9934 RemoveFrame(context, FrameChildListID::Principal, textFrame);
9935
9936 // Insert in the letter frame(s)
9937 parentFrame->InsertFrames(FrameChildListID::Principal, prevFrame, nullptr,
9938 std::move(letterFrames));
9939}
9940
9941//----------------------------------------------------------------------
9942
9943void nsCSSFrameConstructor::ConstructBlock(
9944 nsFrameConstructorState& aState, nsIContent* aContent,
9945 nsContainerFrame* aParentFrame, nsContainerFrame* aContentParentFrame,
9946 ComputedStyle* aComputedStyle, nsContainerFrame** aNewFrame,
9947 nsFrameList& aFrameList, nsIFrame* aPositionedFrameForAbsPosContainer) {
9948 // clang-format off
9949 //
9950 // If a block frame is in a multi-column subtree, its children may need to
9951 // be chopped into runs of blocks containing column-spans and runs of
9952 // blocks containing no column-spans. Each run containing column-spans
9953 // will be wrapped by an anonymous block. See CreateColumnSpanSiblings() for
9954 // the implementation.
9955 //
9956 // If a block frame is a multi-column container, its children will need to
9957 // be processed as above. Moreover, it creates a ColumnSetWrapperFrame as
9958 // its outermost frame, and its children which have no
9959 // -moz-column-span-wrapper pseudo will be wrapped in ColumnSetFrames. See
9960 // FinishBuildingColumns() for the implementation.
9961 //
9962 // The multi-column subtree maintains the following invariants:
9963 //
9964 // 1) All the frames have the frame state bit
9965 // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR set, except for top-level
9966 // ColumnSetWrapperFrame and those children in the column-span subtrees.
9967 //
9968 // 2) The first and last frame under ColumnSetWrapperFrame are always
9969 // ColumnSetFrame.
9970 //
9971 // 3) ColumnSetFrames are linked together as continuations.
9972 //
9973 // 4) Those column-span wrappers are *not* linked together with themselves nor
9974 // with the original block frame. The continuation chain consists of the
9975 // original block frame and the original block's continuations wrapping
9976 // non-column-spans.
9977 //
9978 // For example, this HTML
9979 // <div id="x" style="column-count: 2;">
9980 // <div style="column-span: all">a</div>
9981 // <div id="y">
9982 // b
9983 // <div style="column-span: all">c</div>
9984 // <div style="column-span: all">d</div>
9985 // e
9986 // </div>
9987 // </div>
9988 // <div style="column-span: all">f</div>
9989 //
9990 // yields the following frame tree.
9991 //
9992 // A) ColumnSetWrapper (original style)
9993 // B) ColumnSet (-moz-column-set) <-- always created by BeginBuildingColumns
9994 // C) Block (-moz-column-content)
9995 // D) Block (-moz-column-span-wrapper, created by x)
9996 // E) Block (div)
9997 // F) Text ("a")
9998 // G) ColumnSet (-moz-column-set)
9999 // H) Block (-moz-column-content, created by x)
10000 // I) Block (div, y)
10001 // J) Text ("b")
10002 // K) Block (-moz-column-span-wrapper, created by x)
10003 // L) Block (-moz-column-span-wrapper, created by y)
10004 // M) Block (div, new BFC)
10005 // N) Text ("c")
10006 // O) Block (div, new BFC)
10007 // P) Text ("d")
10008 // Q) ColumnSet (-moz-column-set)
10009 // R) Block (-moz-column-content, created by x)
10010 // S) Block (div, y)
10011 // T) Text ("e")
10012 // U) Block (div, new BFC) <-- not in multi-column hierarchy
10013 // V) Text ("f")
10014 //
10015 // ColumnSet linkage described in 3): B -> G -> Q
10016 //
10017 // Block linkage described in 4): C -> H -> R and I -> S
10018 //
10019 // clang-format on
10020
10021 nsBlockFrame* blockFrame = do_QueryFrame(*aNewFrame);
10022 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"
, 10022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "blockFrame && blockFrame->IsBlockFrame()"
") (" "not a block frame?" ")"); do { MOZ_CrashSequence(__null
, 10022); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
10023
10024 // Create column hierarchy if necessary.
10025 const bool needsColumn =
10026 aComputedStyle->StyleColumn()->IsColumnContainerStyle() &&
10027 !aParentFrame->IsTextInputFrame();
10028 if (needsColumn) {
10029 *aNewFrame = BeginBuildingColumns(aState, aContent, aParentFrame,
10030 blockFrame, aComputedStyle);
10031
10032 if (aPositionedFrameForAbsPosContainer == blockFrame) {
10033 aPositionedFrameForAbsPosContainer = *aNewFrame;
10034 }
10035 } else {
10036 // No need to create column hierarchy. Initialize block frame.
10037 blockFrame->SetComputedStyleWithoutNotification(aComputedStyle);
10038 InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame);
10039 }
10040
10041 aState.AddChild(*aNewFrame, aFrameList, aContent,
10042 aContentParentFrame ? aContentParentFrame : aParentFrame);
10043 if (!mRootElementFrame) {
10044 mRootElementFrame = *aNewFrame;
10045 }
10046
10047 // We should make the outer frame be the absolute containing block,
10048 // if one is required. We have to do this because absolute
10049 // positioning must be computed with respect to the CSS dimensions
10050 // of the element, which are the dimensions of the outer block. But
10051 // we can't really do that because only blocks can have absolute
10052 // children. So use the block and try to compensate with hacks
10053 // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10054 nsFrameConstructorSaveState absoluteSaveState;
10055 (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10056 if (aPositionedFrameForAbsPosContainer) {
10057 aState.PushAbsoluteContainingBlock(
10058 *aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
10059 }
10060
10061 nsFrameConstructorSaveState floatSaveState;
10062 aState.MaybePushFloatContainingBlock(blockFrame, floatSaveState);
10063
10064 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10065 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10066 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10067 }
10068
10069 // Process the child content
10070 nsFrameList childList;
10071 ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true, childList,
10072 true);
10073
10074 if (!MayNeedToCreateColumnSpanSiblings(blockFrame, childList)) {
10075 // No need to create column-span siblings.
10076 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10077 std::move(childList));
10078 return;
10079 }
10080
10081 // Extract any initial non-column-span kids, and put them in block frame's
10082 // child list.
10083 nsFrameList initialNonColumnSpanKids =
10084 childList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10085 blockFrame->SetInitialChildList(FrameChildListID::Principal,
10086 std::move(initialNonColumnSpanKids));
10087
10088 if (childList.IsEmpty()) {
10089 // No more kids to process (there weren't any column-span kids).
10090 return;
10091 }
10092
10093 nsFrameList columnSpanSiblings = CreateColumnSpanSiblings(
10094 aState, blockFrame, childList,
10095 // If we're constructing a column container, pass nullptr as
10096 // aPositionedFrame to forbid reparenting absolute/fixed positioned frames
10097 // to column contents or column-span wrappers.
10098 needsColumn ? nullptr : aPositionedFrameForAbsPosContainer);
10099
10100 if (needsColumn) {
10101 // We're constructing a column container; need to finish building it.
10102 FinishBuildingColumns(aState, *aNewFrame, blockFrame, columnSpanSiblings);
10103 } else {
10104 // We're constructing a normal block which has column-span children in a
10105 // column hierarchy such as "x" in the following example.
10106 //
10107 // <div style="column-count: 2">
10108 // <div id="x">
10109 // <div>normal child</div>
10110 // <div style="column-span">spanner</div>
10111 // </div>
10112 // </div>
10113 aFrameList.AppendFrames(nullptr, std::move(columnSpanSiblings));
10114 }
10115
10116 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", 10117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10117); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10117 "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", 10117
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "columnSpanSiblings.IsEmpty()"
") (" "The column-span siblings should be moved to the proper place!"
")"); do { MOZ_CrashSequence(__null, 10117); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10118}
10119
10120nsBlockFrame* nsCSSFrameConstructor::BeginBuildingColumns(
10121 nsFrameConstructorState& aState, nsIContent* aContent,
10122 nsContainerFrame* aParentFrame, nsContainerFrame* aColumnContent,
10123 ComputedStyle* aComputedStyle) {
10124 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", 10125
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10125); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10125 "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", 10125
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aColumnContent->IsBlockFrame()"
") (" "aColumnContent should be a block frame." ")"); do { MOZ_CrashSequence
(__null, 10125); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10126 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"
, 10127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10127); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10127 "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"
, 10127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aComputedStyle->StyleColumn()->IsColumnContainerStyle()"
") (" "No need to build a column hierarchy!" ")"); do { MOZ_CrashSequence
(__null, 10127); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10128
10129 // The initial column hierarchy looks like this:
10130 //
10131 // ColumnSetWrapper (original style)
10132 // ColumnSet (-moz-column-set)
10133 // Block (-moz-column-content)
10134 //
10135 nsBlockFrame* columnSetWrapper = NS_NewColumnSetWrapperFrame(
10136 mPresShell, aComputedStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10137 InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);
10138 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10139 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10140 columnSetWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10141 }
10142
10143 AutoFrameConstructionPageName pageNameTracker(aState, columnSetWrapper);
10144 RefPtr<ComputedStyle> columnSetStyle =
10145 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10146 PseudoStyleType::MozColumnSet, aComputedStyle);
10147 nsContainerFrame* columnSet = NS_NewColumnSetFrame(
10148 mPresShell, columnSetStyle, nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
10149 InitAndRestoreFrame(aState, aContent, columnSetWrapper, columnSet);
10150 columnSet->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10151
10152 RefPtr<ComputedStyle> blockStyle =
10153 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10154 PseudoStyleType::MozColumnContent, columnSetStyle);
10155 aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
10156 InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
10157 aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10158
10159 // Set up the parent-child chain.
10160 SetInitialSingleChild(columnSetWrapper, columnSet);
10161 SetInitialSingleChild(columnSet, aColumnContent);
10162
10163 return columnSetWrapper;
10164}
10165
10166void nsCSSFrameConstructor::FinishBuildingColumns(
10167 nsFrameConstructorState& aState, nsContainerFrame* aColumnSetWrapper,
10168 nsContainerFrame* aColumnContent, nsFrameList& aColumnContentSiblings) {
10169 nsContainerFrame* prevColumnSet = aColumnContent->GetParent();
10170
10171 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"
, 10173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10173); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10172 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"
, 10173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10173); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
10173 "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"
, 10173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prevColumnSet->IsColumnSetFrame() && prevColumnSet->GetParent() == aColumnSetWrapper"
") (" "Should have established column hierarchy!" ")"); do {
MOZ_CrashSequence(__null, 10173); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
10174
10175 // Tag the first ColumnSet to have column-span siblings so that the bit can
10176 // propagate to all the continuations. We don't want the last ColumnSet to
10177 // have this bit, so we will unset the bit for it at the end of this function.
10178 prevColumnSet->SetHasColumnSpanSiblings(true);
10179
10180 nsFrameList finalList;
10181 while (aColumnContentSiblings.NotEmpty()) {
10182 nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
10183 if (f->IsColumnSpan()) {
10184 // Do nothing for column-span wrappers. Just move it to the final
10185 // items.
10186 finalList.AppendFrame(aColumnSetWrapper, f);
10187 } else {
10188 auto* continuingColumnSet = static_cast<nsContainerFrame*>(
10189 CreateContinuingFrame(prevColumnSet, aColumnSetWrapper, false));
10190 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", 10191);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10191); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10191 "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", 10191);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "continuingColumnSet->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10191); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10192
10193 f->SetParent(continuingColumnSet);
10194 SetInitialSingleChild(continuingColumnSet, f);
10195 finalList.AppendFrame(aColumnSetWrapper, continuingColumnSet);
10196 prevColumnSet = continuingColumnSet;
10197 }
10198 }
10199
10200 // Unset the bit because the last ColumnSet has no column-span siblings.
10201 prevColumnSet->SetHasColumnSpanSiblings(false);
10202
10203 aColumnSetWrapper->AppendFrames(FrameChildListID::Principal,
10204 std::move(finalList));
10205}
10206
10207bool nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
10208 nsContainerFrame* aBlockFrame, const nsFrameList& aChildList) {
10209 if (!aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10210 // The block frame isn't in a multi-column block formatting context.
10211 return false;
10212 }
10213
10214 if (ShouldSuppressColumnSpanDescendants(aBlockFrame)) {
10215 // No need to create column-span siblings for a frame that suppresses them.
10216 return false;
10217 }
10218
10219 if (aChildList.IsEmpty()) {
10220 // No child needs to be processed.
10221 return false;
10222 }
10223
10224 // Need to actually look into the child list.
10225 return true;
10226}
10227
10228nsFrameList nsCSSFrameConstructor::CreateColumnSpanSiblings(
10229 nsFrameConstructorState& aState, nsContainerFrame* aInitialBlock,
10230 nsFrameList& aChildList, nsIFrame* aPositionedFrame) {
10231 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", 10231);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitialBlock->IsBlockFrameOrSubclass()"
")"); do { MOZ_CrashSequence(__null, 10231); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10232 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", 10232);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPositionedFrame || aPositionedFrame->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10232); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10233
10234 nsIContent* const content = aInitialBlock->GetContent();
10235 nsContainerFrame* const parentFrame = aInitialBlock->GetParent();
10236 const bool isInitialBlockFloatCB = aInitialBlock->IsFloatContainingBlock();
10237
10238 nsFrameList siblings;
10239 nsContainerFrame* lastNonColumnSpanWrapper = aInitialBlock;
10240
10241 // Tag the first non-column-span wrapper to have column-span siblings so that
10242 // the bit can propagate to all the continuations. We don't want the last
10243 // wrapper to have this bit, so we will unset the bit for it at the end of
10244 // this function.
10245 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(true);
10246 do {
10247 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"
, 10247); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Why call this if child list is empty?" ")"); do { MOZ_CrashSequence
(__null, 10247); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10248 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"
, 10249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10249 "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"
, 10249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsColumnSpan()"
") (" "Must have the child starting with column-span!" ")");
do { MOZ_CrashSequence(__null, 10249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10250
10251 // Grab the consecutive column-span kids, and reparent them into a
10252 // block frame.
10253 RefPtr<ComputedStyle> columnSpanWrapperStyle =
10254 mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
10255 PseudoStyleType::MozColumnSpanWrapper);
10256 nsBlockFrame* columnSpanWrapper =
10257 NS_NewBlockFrame(mPresShell, columnSpanWrapperStyle);
10258 InitAndRestoreFrame(aState, content, parentFrame, columnSpanWrapper,
10259 AllowCounters::No);
10260 columnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10261 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10262
10263 nsFrameList columnSpanKids =
10264 aChildList.Split([](nsIFrame* f) { return !f->IsColumnSpan(); });
10265 columnSpanKids.ApplySetParent(columnSpanWrapper);
10266 columnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10267 std::move(columnSpanKids));
10268 if (aPositionedFrame) {
10269 aState.ReparentAbsoluteItems(columnSpanWrapper);
10270 }
10271
10272 siblings.AppendFrame(nullptr, columnSpanWrapper);
10273
10274 // Grab the consecutive non-column-span kids, and reparent them into a new
10275 // continuation of the last non-column-span wrapper frame.
10276 auto* nonColumnSpanWrapper = static_cast<nsContainerFrame*>(
10277 CreateContinuingFrame(lastNonColumnSpanWrapper, parentFrame, false));
10278 nonColumnSpanWrapper->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
10279 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10280 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", 10281);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10281); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
10281 "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", 10281);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonColumnSpanWrapper->HasColumnSpanSiblings()"
") (" "The bit should propagate to the next continuation!" ")"
); do { MOZ_CrashSequence(__null, 10281); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
10282
10283 if (aChildList.NotEmpty()) {
10284 nsFrameList nonColumnSpanKids =
10285 aChildList.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10286
10287 nonColumnSpanKids.ApplySetParent(nonColumnSpanWrapper);
10288 nonColumnSpanWrapper->SetInitialChildList(FrameChildListID::Principal,
10289 std::move(nonColumnSpanKids));
10290 if (aPositionedFrame) {
10291 aState.ReparentAbsoluteItems(nonColumnSpanWrapper);
10292 }
10293 if (isInitialBlockFloatCB) {
10294 aState.ReparentFloats(nonColumnSpanWrapper);
10295 }
10296 }
10297
10298 siblings.AppendFrame(nullptr, nonColumnSpanWrapper);
10299
10300 lastNonColumnSpanWrapper = nonColumnSpanWrapper;
10301 } while (aChildList.NotEmpty());
10302
10303 // Unset the bit because the last non-column-span wrapper has no column-span
10304 // siblings.
10305 lastNonColumnSpanWrapper->SetHasColumnSpanSiblings(false);
10306
10307 return siblings;
10308}
10309
10310bool nsCSSFrameConstructor::MaybeRecreateForColumnSpan(
10311 nsFrameConstructorState& aState, nsContainerFrame* aParentFrame,
10312 nsFrameList& aFrameList, nsIFrame* aPrevSibling) {
10313 if (!aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10314 return false;
10315 }
10316
10317 if (aFrameList.IsEmpty()) {
10318 return false;
10319 }
10320
10321 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"
, 10323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10323); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10322 "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"
, 10323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10323); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
10323 "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"
, 10323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFramePartOfIBSplit(aParentFrame)"
") (" "We should have wiped aParentFrame in " "WipeContainingBlock if it's part of IB split!"
")"); do { MOZ_CrashSequence(__null, 10323); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10324
10325 nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
10326 if (!nextSibling && IsLastContinuationForColumnContent(aParentFrame)) {
10327 // We are appending a list of frames to the last continuation of a
10328 // ::-moz-column-content. This is the case where we can fix the frame tree
10329 // instead of reframing the containing block. Return false and let
10330 // AppendFramesToParent() deal with this.
10331 return false;
10332 }
10333
10334 auto HasColumnSpan = [](const nsFrameList& aList) {
10335 for (nsIFrame* f : aList) {
10336 if (f->IsColumnSpan()) {
10337 return true;
10338 }
10339 }
10340 return false;
10341 };
10342
10343 if (HasColumnSpan(aFrameList)) {
10344 // If any frame in the frame list has "column-span:all" style, i.e. a
10345 // -moz-column-span-wrapper frame, we need to reframe the multi-column
10346 // containing block.
10347 //
10348 // We can only be here if none of the new inserted nsIContent* nodes (via
10349 // ContentAppended or ContentRangeInserted) have column-span:all style, yet
10350 // some of them have column-span:all descendants. Sadly, there's no way to
10351 // detect this by checking FrameConstructionItems in WipeContainingBlock().
10352 // Otherwise, we would have already wiped the multi-column containing block.
10353 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)
10354 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)
;
10355
10356 // aFrameList can contain placeholder frames. In order to destroy their
10357 // associated out-of-flow frames properly, we need to manually flush all the
10358 // out-of-flow frames in aState to their container frames.
10359 aState.ProcessFrameInsertionsForAllLists();
10360 DestroyContext context(mPresShell);
10361 aFrameList.DestroyFrames(context);
10362 RecreateFramesForContent(
10363 GetMultiColumnContainingBlockFor(aParentFrame)->GetContent(),
10364 InsertionKind::Async);
10365 return true;
10366 }
10367
10368 return false;
10369}
10370
10371nsIFrame* nsCSSFrameConstructor::ConstructInline(
10372 nsFrameConstructorState& aState, FrameConstructionItem& aItem,
10373 nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
10374 nsFrameList& aFrameList) {
10375 // If an inline frame has non-inline kids, then we chop up the child list
10376 // into runs of blocks and runs of inlines, create anonymous block frames to
10377 // contain the runs of blocks, inline frames with our style for the runs of
10378 // inlines, and put all these frames, in order, into aFrameList.
10379 //
10380 // When there are column-span blocks in a run of blocks, instead of creating
10381 // an anonymous block to wrap them, we create multiple anonymous blocks,
10382 // wrapping runs of non-column-spans and runs of column-spans.
10383 //
10384 // We return the the first one. The whole setup is called an {ib}
10385 // split; in what follows "frames in the split" refers to the anonymous blocks
10386 // and inlines that contain our children.
10387 //
10388 // {ib} splits maintain the following invariants:
10389 // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit
10390 // set.
10391 //
10392 // 2) Each frame in the split has the nsIFrame::IBSplitSibling
10393 // property pointing to the next frame in the split, except for the last
10394 // one, which does not have it set.
10395 //
10396 // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling
10397 // property pointing to the previous frame in the split, except for the
10398 // first one, which does not have it set.
10399 //
10400 // 4) The first and last frame in the split are always inlines.
10401 //
10402 // 5) The frames wrapping runs of non-column-spans are linked together as
10403 // continuations. The frames wrapping runs of column-spans are *not*
10404 // linked with each other nor with other non-column-span wrappers.
10405 //
10406 // 6) The first and last frame in the chains of blocks are always wrapping
10407 // non-column-spans. Both of them are created even if they're empty.
10408 //
10409 // An invariant that is NOT maintained is that the wrappers are actually
10410 // linked via GetNextSibling linkage. A simple example is an inline
10411 // containing an inline that contains a block. The three parts of the inner
10412 // inline end up with three different parents.
10413 //
10414 // For example, this HTML:
10415 // <span>
10416 // <div>a</div>
10417 // <span>
10418 // b
10419 // <div>c</div>
10420 // </span>
10421 // d
10422 // <div>e</div>
10423 // f
10424 // </span>
10425 // Gives the following frame tree:
10426 //
10427 // Inline (outer span)
10428 // Block (anonymous, outer span)
10429 // Block (div)
10430 // Text("a")
10431 // Inline (outer span)
10432 // Inline (inner span)
10433 // Text("b")
10434 // Block (anonymous, outer span)
10435 // Block (anonymous, inner span)
10436 // Block (div)
10437 // Text("c")
10438 // Inline (outer span)
10439 // Inline (inner span)
10440 // Text("d")
10441 // Block (anonymous, outer span)
10442 // Block (div)
10443 // Text("e")
10444 // Inline (outer span)
10445 // Text("f")
10446
10447 nsIContent* const content = aItem.mContent;
10448 ComputedStyle* const computedStyle = aItem.mComputedStyle;
10449
10450 nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10451
10452 // Initialize the frame
10453 InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
10454
10455 // definition cannot be inside next block because the object's destructor is
10456 // significant. this is part of the fix for bug 42372
10457 nsFrameConstructorSaveState absoluteSaveState;
10458
10459 bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
10460 newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10461 if (isAbsPosCB) {
10462 // Relatively positioned frames becomes a container for child
10463 // frames that are positioned
10464 aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
10465 }
10466
10467 if (aParentFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) &&
10468 !ShouldSuppressColumnSpanDescendants(aParentFrame)) {
10469 newFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10470 }
10471
10472 // Process the child content
10473 nsFrameList childList;
10474 ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
10475 /* aParentIsWrapperAnonBox = */ false, childList);
10476
10477 nsIFrame* firstBlock = nullptr;
10478 if (!aItem.mIsAllInline) {
10479 for (nsIFrame* f : childList) {
10480 if (f->IsBlockOutside()) {
10481 firstBlock = f;
10482 break;
10483 }
10484 }
10485 }
10486
10487 if (aItem.mIsAllInline || !firstBlock) {
10488 // This part is easy. We either already know we have no non-inline kids,
10489 // or haven't found any when constructing actual frames (the latter can
10490 // happen only if out-of-flows that we thought had no containing block
10491 // acquired one when ancestor inline frames and {ib} splits got
10492 // constructed). Just put all the kids into the single inline frame and
10493 // bail.
10494 newFrame->SetInitialChildList(FrameChildListID::Principal,
10495 std::move(childList));
10496 aState.AddChild(newFrame, aFrameList, content, aParentFrame);
10497 return newFrame;
10498 }
10499
10500 // This inline frame contains several types of children. Therefore this frame
10501 // has to be chopped into several pieces, as described above.
10502
10503 // Grab the first inline's kids
10504 nsFrameList firstInlineKids = childList.TakeFramesBefore(firstBlock);
10505 newFrame->SetInitialChildList(FrameChildListID::Principal,
10506 std::move(firstInlineKids));
10507
10508 aFrameList.AppendFrame(nullptr, newFrame);
10509
10510 newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
10511 CreateIBSiblings(aState, newFrame, isAbsPosCB, childList, aFrameList);
10512
10513 return newFrame;
10514}
10515
10516void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
10517 nsContainerFrame* aInitialInline,
10518 bool aIsAbsPosCB,
10519 nsFrameList& aChildList,
10520 nsFrameList& aSiblings) {
10521 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", 10521);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock()"
")"); do { MOZ_CrashSequence(__null, 10521); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
10522
10523 nsIContent* content = aInitialInline->GetContent();
10524 ComputedStyle* computedStyle = aInitialInline->Style();
10525 nsContainerFrame* parentFrame = aInitialInline->GetParent();
10526
10527 // Resolve the right style for our anonymous blocks.
10528 //
10529 // The distinction in styles is needed because of CSS 2.1, section
10530 // 9.2.1.1, which says:
10531 //
10532 // When such an inline box is affected by relative positioning, any
10533 // resulting translation also affects the block-level box contained
10534 // in the inline box.
10535 RefPtr<ComputedStyle> blockSC =
10536 mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
10537 PseudoStyleType::MozBlockInsideInlineWrapper, computedStyle);
10538
10539 nsContainerFrame* lastNewInline =
10540 static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
10541 do {
10542 // On entry to this loop aChildList is not empty and the first frame in it
10543 // is block-level.
10544 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"
, 10544); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.NotEmpty()"
") (" "Should have child items" ")"); do { MOZ_CrashSequence
(__null, 10544); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10545 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"
, 10546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10546); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
10546 "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"
, 10546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChildList.FirstChild()->IsBlockOutside()"
") (" "Must have list starting with block" ")"); do { MOZ_CrashSequence
(__null, 10546); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10547
10548 // The initial run of blocks belongs to an anonymous block that we create
10549 // right now. The anonymous block will be the parent of these block
10550 // children of the inline.
10551 nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10552 InitAndRestoreFrame(aState, content, parentFrame, blockFrame,
10553 AllowCounters::No);
10554 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10555 blockFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10556 }
10557
10558 // Find the first non-block child which defines the end of our block kids
10559 // and the start of our next inline's kids
10560 nsFrameList blockKids =
10561 aChildList.Split([](nsIFrame* f) { return !f->IsBlockOutside(); });
10562
10563 if (!aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10564 MoveChildrenTo(aInitialInline, blockFrame, blockKids);
10565
10566 SetFrameIsIBSplit(lastNewInline, blockFrame);
10567 aSiblings.AppendFrame(nullptr, blockFrame);
10568 } else {
10569 // Extract any initial non-column-span frames, and put them in
10570 // blockFrame's child list.
10571 nsFrameList initialNonColumnSpanKids =
10572 blockKids.Split([](nsIFrame* f) { return f->IsColumnSpan(); });
10573 MoveChildrenTo(aInitialInline, blockFrame, initialNonColumnSpanKids);
10574
10575 SetFrameIsIBSplit(lastNewInline, blockFrame);
10576 aSiblings.AppendFrame(nullptr, blockFrame);
10577
10578 if (blockKids.NotEmpty()) {
10579 // Although SetFrameIsIBSplit() will add NS_FRAME_PART_OF_IBSPLIT for
10580 // blockFrame later, we manually add the bit earlier here to make all
10581 // the continuations of blockFrame created in
10582 // CreateColumnSpanSiblings(), i.e. non-column-span wrappers, have the
10583 // bit via nsIFrame::Init().
10584 blockFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT);
10585
10586 nsFrameList columnSpanSiblings =
10587 CreateColumnSpanSiblings(aState, blockFrame, blockKids,
10588 aIsAbsPosCB ? aInitialInline : nullptr);
10589 aSiblings.AppendFrames(nullptr, std::move(columnSpanSiblings));
10590 }
10591 }
10592
10593 // Now grab the initial inlines in aChildList and put them into an inline
10594 // frame.
10595 nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
10596 InitAndRestoreFrame(aState, content, parentFrame, inlineFrame,
10597 AllowCounters::No);
10598 inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
10599 if (aInitialInline->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
10600 inlineFrame->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR);
10601 }
10602
10603 if (aIsAbsPosCB) {
10604 inlineFrame->MarkAsAbsoluteContainingBlock();
10605 }
10606
10607 if (aChildList.NotEmpty()) {
10608 nsFrameList inlineKids =
10609 aChildList.Split([](nsIFrame* f) { return f->IsBlockOutside(); });
10610 MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
10611 }
10612
10613 SetFrameIsIBSplit(blockFrame, inlineFrame);
10614 aSiblings.AppendFrame(nullptr, inlineFrame);
10615 lastNewInline = inlineFrame;
10616 } while (aChildList.NotEmpty());
10617
10618 SetFrameIsIBSplit(lastNewInline, nullptr);
10619}
10620
10621void nsCSSFrameConstructor::BuildInlineChildItems(
10622 nsFrameConstructorState& aState, FrameConstructionItem& aParentItem,
10623 bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) {
10624 ComputedStyle* const parentStyle = aParentItem.mComputedStyle;
10625 nsIContent* const parentContent = aParentItem.mContent;
10626
10627 if (!aItemIsWithinSVGText) {
10628 if (parentStyle->StyleDisplay()->IsListItem()) {
10629 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10630 *parentStyle, PseudoStyleType::Marker,
10631 aParentItem.mChildItems);
10632 }
10633 // Probe for generated content before
10634 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10635 *parentStyle, PseudoStyleType::Before,
10636 aParentItem.mChildItems);
10637 }
10638
10639 ItemFlags flags;
10640 if (aItemIsWithinSVGText) {
10641 flags += ItemFlag::IsWithinSVGText;
10642 }
10643 if (aItemAllowsTextPathChild &&
10644 aParentItem.mContent->IsSVGElement(nsGkAtoms::a)) {
10645 flags += ItemFlag::AllowTextPathChild;
10646 }
10647
10648 FlattenedChildIterator iter(parentContent);
10649 for (nsIContent* content = iter.GetNextChild(); content;
10650 content = iter.GetNextChild()) {
10651 AddFrameConstructionItems(aState, content, iter.ShadowDOMInvolved(),
10652 *parentStyle, InsertionPoint(),
10653 aParentItem.mChildItems, flags);
10654 }
10655
10656 if (!aItemIsWithinSVGText) {
10657 // Probe for generated content after
10658 CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(),
10659 *parentStyle, PseudoStyleType::After,
10660 aParentItem.mChildItems);
10661 }
10662
10663 aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
10664}
10665
10666// return whether it's ok to append (in the AppendFrames sense) to
10667// aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10668// be an ib-split inline.
10669static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
10670 nsIFrame* aNextSibling) {
10671 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"
, 10671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsInlineFrame(aParentFrame)"
") (" "Must have an inline parent here" ")"); do { MOZ_CrashSequence
(__null, 10671); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
10672
10673 do {
10674 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", 10675);
MOZ_PretendNoReturn(); } } while (0)
10675 "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", 10675);
MOZ_PretendNoReturn(); } } while (0)
;
10676 if (aNextSibling || aParentFrame->GetNextContinuation() ||
10677 GetIBSplitSibling(aParentFrame)) {
10678 return false;
10679 }
10680
10681 aNextSibling = aParentFrame->GetNextSibling();
10682 aParentFrame = aParentFrame->GetParent();
10683 } while (IsInlineFrame(aParentFrame));
10684
10685 return true;
10686}
10687
10688bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame) {
10689#define TRACE(reason) \
10690 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)
10691 "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)
;
10692
10693 const LayoutFrameType frameType = aFrame->Type();
10694
10695 // FIXME(emilio): This looks terribly inefficient if you insert elements deep
10696 // in a MathML subtree.
10697 if (aFrame->IsMathMLFrame()) {
10698 TRACE("MathML");
10699 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10700 return true;
10701 }
10702
10703 // A ruby-related frame that's getting new children.
10704 // The situation for ruby is complex, especially when interacting with
10705 // spaces. It contains these two special cases apart from tables:
10706 // 1) There are effectively three types of white spaces in ruby frames
10707 // we handle differently: leading/tailing/inter-level space,
10708 // inter-base/inter-annotation space, and inter-segment space.
10709 // These three types of spaces can be converted to each other when
10710 // their sibling changes.
10711 // 2) The first effective child of a ruby frame must always be a ruby
10712 // base container. It should be created or destroyed accordingly.
10713 if (IsRubyPseudo(aFrame) || frameType == LayoutFrameType::Ruby ||
10714 RubyUtils::IsRubyContainerBox(frameType)) {
10715 // We want to optimize it better, and avoid reframing as much as
10716 // possible. But given the cases above, and the fact that a ruby
10717 // usually won't be very large, it should be fine to reframe it.
10718 TRACE("Ruby");
10719 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10720 return true;
10721 }
10722
10723 // Reframe the multi-column container whenever elements insert/append
10724 // into it because we need to reconstruct column-span split.
10725 if (aFrame->IsColumnSetWrapperFrame()) {
10726 TRACE("Multi-column");
10727 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10728 return true;
10729 }
10730
10731 return false;
10732
10733#undef TRACE
10734}
10735
10736bool nsCSSFrameConstructor::WipeContainingBlock(
10737 nsFrameConstructorState& aState, nsIFrame* aContainingBlock,
10738 nsIFrame* aFrame, FrameConstructionItemList& aItems, bool aIsAppend,
10739 nsIFrame* aPrevSibling) {
10740#define TRACE(reason) \
10741 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)
10742 "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)
;
10743
10744 if (aItems.IsEmpty()) {
10745 return false;
10746 }
10747
10748 // Before we go and append the frames, we must check for several
10749 // special situations.
10750
10751 if (aFrame->GetContent() == mDocument->GetRootElement()) {
10752 // Situation #1 is when we insert content that becomes the canonical body
10753 // element, and its used WritingMode is different from the root element's
10754 // used WritingMode.
10755 // We need to reframe the root element so that the root element's frames has
10756 // the correct writing-mode propagated from body element. (See
10757 // nsCSSFrameConstructor::ConstructDocElementFrame.)
10758 //
10759 // Bug 1594297: When inserting a new <body>, we may need to reframe the old
10760 // <body> which has a "overflow" value other than simple "visible". But it's
10761 // tricky, see bug 1593752.
10762 nsIContent* bodyElement = mDocument->GetBodyElement();
10763 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
10764 const WritingMode bodyWM(iter.item().mComputedStyle);
10765 if (iter.item().mContent == bodyElement &&
10766 bodyWM != aFrame->GetWritingMode()) {
10767 TRACE("Root");
10768 RecreateFramesForContent(mDocument->GetRootElement(),
10769 InsertionKind::Async);
10770 return true;
10771 }
10772 }
10773 }
10774
10775 nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
10776
10777 // Situation #2 is a flex / grid container frame into which we're inserting
10778 // new inline non-replaced children, adjacent to an existing anonymous flex or
10779 // grid item.
10780 if (aFrame->IsFlexOrGridContainer()) {
10781 FCItemIterator iter(aItems);
10782
10783 // Check if we're adding to-be-wrapped content right *after* an existing
10784 // anonymous flex or grid item (which would need to absorb this content).
10785 const bool isLegacyWebKitBox = IsFlexContainerForLegacyWebKitBox(aFrame);
10786 if (aPrevSibling && IsAnonymousItem(aPrevSibling) &&
10787 iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10788 TRACE("Inserting inline after anon flex or grid item");
10789 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10790 return true;
10791 }
10792
10793 // Check if we're adding to-be-wrapped content right *before* an existing
10794 // anonymous flex or grid item (which would need to absorb this content).
10795 if (nextSibling && IsAnonymousItem(nextSibling)) {
10796 // Jump to the last entry in the list
10797 iter.SetToEnd();
10798 iter.Prev();
10799 if (iter.item().NeedsAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10800 TRACE("Inserting inline before anon flex or grid item");
10801 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
10802 return true;
10803 }
10804 }
10805 }
10806
10807 // Situation #3 is an anonymous flex or grid item that's getting new children
10808 // who don't want to be wrapped.
10809 if (IsAnonymousItem(aFrame)) {
10810 AssertAnonymousFlexOrGridItemParent(aFrame);
10811
10812 // We need to push a null float containing block to be sure that
10813 // "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
10814 // inserted content. (In particular, this is necessary in order for
10815 // its "GetGeometricParent" call to return the correct result.)
10816 // We're not honoring floats on this content because it has the
10817 // _flex/grid container_ as its parent in the content tree.
10818 nsFrameConstructorSaveState floatSaveState;
10819 aState.PushFloatContainingBlock(nullptr, floatSaveState);
10820
10821 FCItemIterator iter(aItems);
10822 // Skip over things that _do_ need an anonymous flex item, because
10823 // they're perfectly happy to go here -- they won't cause a reframe.
10824 nsIFrame* containerFrame = aFrame->GetParent();
10825 const bool isLegacyWebKitBox =
10826 IsFlexContainerForLegacyWebKitBox(containerFrame);
10827 if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isLegacyWebKitBox)) {
10828 // We hit something that _doesn't_ need an anonymous flex item!
10829 // Rebuild the flex container to bust it out.
10830 TRACE("Inserting non-inlines inside anon flex or grid item");
10831 RecreateFramesForContent(containerFrame->GetContent(),
10832 InsertionKind::Async);
10833 return true;
10834 }
10835
10836 // If we get here, then everything in |aItems| needs to be wrapped in
10837 // an anonymous flex or grid item. That's where it's already going - good!
10838 }
10839
10840 // Situation #4 is a case when table pseudo-frames don't work out right
10841 ParentType parentType = GetParentType(aFrame);
10842 // If all the kids want a parent of the type that aFrame is, then we're all
10843 // set to go. Indeed, there won't be any table pseudo-frames created between
10844 // aFrame and the kids, so those won't need to be merged with any table
10845 // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10846 // table pseudo-frame, then all the kids in this list would have wanted a
10847 // frame of that type wrapping them anyway, so putting them inside it is ok.
10848 if (!aItems.AllWantParentType(parentType)) {
10849 // Don't give up yet. If parentType is not eTypeBlock and the parent is
10850 // not a generated content frame, then try filtering whitespace out of the
10851 // list.
10852 if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
10853 // For leading whitespace followed by a kid that wants our parent type,
10854 // there are four cases:
10855 // 1) We have a previous sibling which is not a table pseudo. That means
10856 // that previous sibling wanted a (non-block) parent of the type we're
10857 // looking at. Then the whitespace comes between two table-internal
10858 // elements, so should be collapsed out.
10859 // 2) We have a previous sibling which is a table pseudo. It might have
10860 // kids who want this whitespace, so we need to reframe.
10861 // 3) We have no previous sibling and our parent frame is not a table
10862 // pseudo. That means that we'll be at the beginning of our actual
10863 // non-block-type parent, and the whitespace is OK to collapse out.
10864 // If something is ever inserted before us, it'll find our own parent
10865 // as its parent and if it's something that would care about the
10866 // whitespace it'll want a block parent, so it'll trigger a reframe at
10867 // that point.
10868 // 4) We have no previous sibling and our parent frame is a table pseudo.
10869 // Need to reframe.
10870 // All that is predicated on finding the correct previous sibling. We
10871 // might have to walk backwards along continuations from aFrame to do so.
10872 //
10873 // It's always OK to drop whitespace between any two items that want a
10874 // parent of type parentType.
10875 //
10876 // For trailing whitespace preceded by a kid that wants our parent type,
10877 // there are four cases:
10878 // 1) We have a next sibling which is not a table pseudo. That means
10879 // that next sibling wanted a (non-block) parent of the type we're
10880 // looking at. Then the whitespace comes between two table-internal
10881 // elements, so should be collapsed out.
10882 // 2) We have a next sibling which is a table pseudo. It might have
10883 // kids who want this whitespace, so we need to reframe.
10884 // 3) We have no next sibling and our parent frame is not a table
10885 // pseudo. That means that we'll be at the end of our actual
10886 // non-block-type parent, and the whitespace is OK to collapse out.
10887 // If something is ever inserted after us, it'll find our own parent
10888 // as its parent and if it's something that would care about the
10889 // whitespace it'll want a block parent, so it'll trigger a reframe at
10890 // that point.
10891 // 4) We have no next sibling and our parent frame is a table pseudo.
10892 // Need to reframe.
10893 // All that is predicated on finding the correct next sibling. We might
10894 // have to walk forward along continuations from aFrame to do so. That
10895 // said, in the case when nextSibling is null at this point and aIsAppend
10896 // is true, we know we're in case 3. Furthermore, in that case we don't
10897 // even have to worry about the table pseudo situation; we know our
10898 // parent is not a table pseudo there.
10899 FCItemIterator iter(aItems);
10900 FCItemIterator start(iter);
10901 do {
10902 if (iter.SkipItemsWantingParentType(parentType)) {
10903 break;
10904 }
10905
10906 // iter points to an item that wants a different parent. If it's not
10907 // whitespace, we're done; no more point scanning the list.
10908 if (!iter.item().IsWhitespace(aState)) {
10909 break;
10910 }
10911
10912 if (iter == start) {
10913 // Leading whitespace. How to handle this depends on our
10914 // previous sibling and aFrame. See the long comment above.
10915 nsIFrame* prevSibling = aPrevSibling;
10916 if (!prevSibling) {
10917 // Try to find one after all
10918 nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
10919 while (parentPrevCont) {
10920 prevSibling = parentPrevCont->PrincipalChildList().LastChild();
10921 if (prevSibling) {
10922 break;
10923 }
10924 parentPrevCont = parentPrevCont->GetPrevContinuation();
10925 }
10926 };
10927 if (prevSibling) {
10928 if (IsTablePseudo(prevSibling)) {
10929 // need to reframe
10930 break;
10931 }
10932 } else if (IsTablePseudo(aFrame)) {
10933 // need to reframe
10934 break;
10935 }
10936 }
10937
10938 FCItemIterator spaceEndIter(iter);
10939 // Advance spaceEndIter past any whitespace
10940 bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
10941
10942 bool okToDrop;
10943 if (trailingSpaces) {
10944 // Trailing whitespace. How to handle this depeds on aIsAppend, our
10945 // next sibling and aFrame. See the long comment above.
10946 okToDrop = aIsAppend && !nextSibling;
10947 if (!okToDrop) {
10948 if (!nextSibling) {
10949 // Try to find one after all
10950 nsIFrame* parentNextCont = aFrame->GetNextContinuation();
10951 while (parentNextCont) {
10952 nextSibling = parentNextCont->PrincipalChildList().FirstChild();
10953 if (nextSibling) {
10954 break;
10955 }
10956 parentNextCont = parentNextCont->GetNextContinuation();
10957 }
10958 }
10959
10960 okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
10961 (!nextSibling && !IsTablePseudo(aFrame));
10962 } else {
10963 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"
, 10963); MOZ_PretendNoReturn(); } } while (0)
;
10964 }
10965 } else {
10966 okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
10967 }
10968
10969 if (okToDrop) {
10970 iter.DeleteItemsTo(this, spaceEndIter);
10971 } else {
10972 // We're done: we don't want to drop the whitespace, and it has the
10973 // wrong parent type.
10974 break;
10975 }
10976
10977 // Now loop, since |iter| points to item right after the whitespace we
10978 // removed.
10979 } while (!iter.IsDone());
10980 }
10981
10982 // We might be able to figure out some sort of optimizations here, but they
10983 // would have to depend on having a correct aPrevSibling and a correct next
10984 // sibling. For example, we can probably avoid reframing if none of
10985 // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
10986 // doesn't seem worth it to worry about that for now, especially since we
10987 // in fact do not have a reliable aPrevSibling, nor any next sibling, in
10988 // this method.
10989
10990 // aItems might have changed, so recheck the parent type thing. In fact,
10991 // it might be empty, so recheck that too.
10992 if (aItems.IsEmpty()) {
10993 return false;
10994 }
10995
10996 // If aFrame is empty, the insertion process will be able to take care of
10997 // creating any needed pseudo-parents.
10998 if (!aItems.AllWantParentType(parentType) &&
10999 !SafeToInsertPseudoNeedingChildren(aFrame)) {
11000 // Reframing aFrame->GetContent() is good enough, since the content of
11001 // table pseudo-frames is the ancestor content.
11002 TRACE("Pseudo-frames going wrong");
11003 RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
11004 return true;
11005 }
11006 }
11007
11008 // Situation #5 is a frame in multicol subtree that's getting new children.
11009 if (aFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
11010 bool anyColumnSpanItems = false;
11011 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11012 if (iter.item().mComputedStyle->StyleColumn()->IsColumnSpanStyle()) {
11013 anyColumnSpanItems = true;
11014 break;
11015 }
11016 }
11017
11018 bool needsReframe =
11019 // 1. Insert / append any column-span children.
11020 anyColumnSpanItems ||
11021 // 2. GetInsertionPrevSibling() modifies insertion parent. If the prev
11022 // sibling is a column-span, aFrame ends up being the
11023 // column-span-wrapper.
11024 aFrame->Style()->GetPseudoType() ==
11025 PseudoStyleType::MozColumnSpanWrapper ||
11026 // 3. Append into {ib} split container. There might be room for
11027 // optimization, but let's reframe for correctness...
11028 IsFramePartOfIBSplit(aFrame);
11029
11030 if (needsReframe) {
11031 TRACE("Multi-column");
11032 RecreateFramesForContent(
11033 GetMultiColumnContainingBlockFor(aFrame)->GetContent(),
11034 InsertionKind::Async);
11035 return true;
11036 }
11037
11038 // If we get here, then we need further check for {ib} split to decide
11039 // whether to reframe. For example, appending a block into an empty inline
11040 // that is not part of an {ib} split, but should become an {ib} split.
11041 }
11042
11043 // A <fieldset> may need to pick up a new rendered legend from aItems.
11044 // We currently can't handle this case without recreating frames for
11045 // the fieldset.
11046 // XXXmats we should be able to optimize this when the fieldset doesn't
11047 // currently have a rendered legend. ContentRangeInserted needs to be fixed
11048 // to use the inner frame as the content insertion frame in that case.
11049 if (const auto* fieldset = GetFieldSetFrameFor(aFrame)) {
11050 // Check if any item is eligible to be a rendered legend.
11051 for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
11052 const auto& item = iter.item();
11053 if (!item.mContent->IsHTMLElement(nsGkAtoms::legend)) {
11054 continue;
11055 }
11056 const auto* display = item.mComputedStyle->StyleDisplay();
11057 if (display->IsFloatingStyle() ||
11058 display->IsAbsolutelyPositionedStyle()) {
11059 continue;
11060 }
11061 TRACE("Fieldset with rendered legend");
11062 RecreateFramesForContent(fieldset->GetContent(), InsertionKind::Async);
11063 return true;
11064 }
11065 }
11066
11067 // Now we have several cases involving {ib} splits. Put them all in a
11068 // do/while with breaks to take us to the "go and reconstruct" code.
11069 do {
11070 if (IsInlineFrame(aFrame)) {
11071 if (aItems.AreAllItemsInline()) {
11072 // We can just put the kids in.
11073 return false;
11074 }
11075
11076 if (!IsFramePartOfIBSplit(aFrame)) {
11077 // Need to go ahead and reconstruct.
11078 break;
11079 }
11080
11081 // Now we're adding kids including some blocks to an inline part of an
11082 // {ib} split. If we plan to call AppendFrames, and don't have a next
11083 // sibling for the new frames, and our parent is the last continuation of
11084 // the last part of the {ib} split, and the same is true of all our
11085 // ancestor inlines (they have no following continuations and they're the
11086 // last part of their {ib} splits and we'd be adding to the end for all
11087 // of them), then AppendFrames will handle things for us. Bail out in
11088 // that case.
11089 if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) {
11090 return false;
11091 }
11092
11093 // Need to reconstruct.
11094 break;
11095 }
11096
11097 // Now we know we have a block parent. If it's not part of an
11098 // ib-split, we're all set.
11099 if (!IsFramePartOfIBSplit(aFrame)) {
11100 return false;
11101 }
11102
11103 // We're adding some kids to a block part of an {ib} split. If all the
11104 // kids are blocks, we don't need to reconstruct.
11105 if (aItems.AreAllItemsBlock()) {
11106 return false;
11107 }
11108
11109 // We might have some inline kids for this block. Just fall out of the
11110 // loop and reconstruct.
11111 } while (false);
11112
11113 // If we don't have a containing block, start with aFrame and look for one.
11114 if (!aContainingBlock) {
11115 aContainingBlock = aFrame;
11116 }
11117
11118 // To find the right block to reframe, just walk up the tree until we find a
11119 // frame that is:
11120 // 1) Not part of an IB split
11121 // 2) Not a pseudo-frame
11122 // 3) Not an inline frame
11123 // We're guaranteed to find one, since ComputedStyle::ApplyStyleFixups
11124 // enforces that the root is display:none, display:table, or display:block.
11125 // Note that walking up "too far" is OK in terms of correctness, even if it
11126 // might be a little inefficient. This is why we walk out of all
11127 // pseudo-frames -- telling which ones are or are not OK to walk out of is
11128 // too hard (and I suspect that we do in fact need to walk out of all of
11129 // them).
11130 while (IsFramePartOfIBSplit(aContainingBlock) ||
11131 aContainingBlock->IsInlineOutside() ||
11132 aContainingBlock->Style()->IsPseudoOrAnonBox()) {
11133 aContainingBlock = aContainingBlock->GetParent();
11134 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"
, 11136); MOZ_PretendNoReturn(); } } while (0)
11135 "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"
, 11136); MOZ_PretendNoReturn(); } } while (0)
11136 "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"
, 11136); MOZ_PretendNoReturn(); } } while (0)
;
11137 }
11138
11139 // Tell parent of the containing block to reformulate the
11140 // entire block. This is painful and definitely not optimal
11141 // but it will *always* get the right answer.
11142
11143 nsIContent* blockContent = aContainingBlock->GetContent();
11144 TRACE("IB splits");
11145 RecreateFramesForContent(blockContent, InsertionKind::Async);
11146 return true;
11147#undef TRACE
11148}
11149
11150void nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) {
11151 // XXXbz how exactly would we get here while isReflowing anyway? Should this
11152 // whole test be ifdef DEBUG?
11153 if (mPresShell->IsReflowLocked()) {
11154 // don't ReframeContainingBlock, this will result in a crash
11155 // if we remove a tree that's in reflow - see bug 121368 for testcase
11156 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11158); MOZ_PretendNoReturn(); } while (0)
11157 "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11158); MOZ_PretendNoReturn(); } while (0)
11158 "Reflow!!!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a "
"Reflow!!!", "Error", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11158); MOZ_PretendNoReturn(); } while (0)
;
11159 return;
11160 }
11161
11162 // Get the first "normal" ancestor of the target frame.
11163 nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11164 if (containingBlock) {
11165 // From here we look for the containing block in case the target
11166 // frame is already a block (which can happen when an inline frame
11167 // wraps some of its content in an anonymous block; see
11168 // ConstructInline)
11169
11170 // NOTE: We used to get the FloatContainingBlock here, but it was often
11171 // wrong. GetIBContainingBlock works much better and provides the correct
11172 // container in all cases so GetFloatContainingBlock(aFrame) has been
11173 // removed
11174
11175 // And get the containingBlock's content
11176 if (nsIContent* blockContent = containingBlock->GetContent()) {
11177#ifdef DEBUG1
11178 if (gNoisyContentUpdates) {
11179 printf(" ==> blockContent=%p\n", blockContent);
11180 }
11181#endif
11182 RecreateFramesForContent(blockContent, InsertionKind::Async);
11183 return;
11184 }
11185 }
11186
11187 // If we get here, we're screwed!
11188 RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11189 InsertionKind::Async);
11190}
11191
11192//////////////////////////////////////////////////////////
11193// nsCSSFrameConstructor::FrameConstructionItem methods //
11194//////////////////////////////////////////////////////////
11195bool nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace(
11196 nsFrameConstructorState& aState) const {
11197 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"
, 11198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11198); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
11198 "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"
, 11198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState.mCreatingExtraFrames || !mContent->GetPrimaryFrame()"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11198); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11199 if (!mIsText) {
11200 return false;
11201 }
11202 mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11203 NS_REFRAME_IF_WHITESPACE);
11204 return mContent->TextIsOnlyWhitespace();
11205}
11206
11207//////////////////////////////////////////////////////////////
11208// nsCSSFrameConstructor::FrameConstructionItemList methods //
11209//////////////////////////////////////////////////////////////
11210void nsCSSFrameConstructor::FrameConstructionItemList::AdjustCountsForItem(
11211 FrameConstructionItem* aItem, int32_t aDelta) {
11212 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"
, 11212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDelta == 1 || aDelta == -1"
") (" "Unexpected delta" ")"); do { MOZ_CrashSequence(__null
, 11212); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11213 mItemCount += aDelta;
11214 if (aItem->mIsAllInline) {
11215 mInlineCount += aDelta;
11216 }
11217 if (aItem->mIsBlock) {
11218 mBlockCount += aDelta;
11219 }
11220 mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
11221}
11222
11223////////////////////////////////////////////////////////////////////////
11224// nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11225////////////////////////////////////////////////////////////////////////
11226inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11227 SkipItemsWantingParentType(ParentType aParentType) {
11228 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", 11228
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11228); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11229 while (item().DesiredParentType() == aParentType) {
11230 Next();
11231 if (IsDone()) {
11232 return true;
11233 }
11234 }
11235 return false;
11236}
11237
11238inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11239 SkipItemsNotWantingParentType(ParentType aParentType) {
11240 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", 11240
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11240); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11241 while (item().DesiredParentType() != aParentType) {
11242 Next();
11243 if (IsDone()) {
11244 return true;
11245 }
11246 }
11247 return false;
11248}
11249
11250// Note: we implement -webkit-{inline-}box using nsFlexContainerFrame, but we
11251// use different rules for what gets wrapped in an anonymous flex item.
11252bool nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem(
11253 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11254 if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT0x2000) {
11255 // This will be an inline non-replaced box.
11256 return true;
11257 }
11258
11259 if (aIsLegacyWebKitBox) {
11260 if (mComputedStyle->StyleDisplay()->IsInlineOutsideStyle()) {
11261 // In an emulated legacy box, all inline-level content gets wrapped in an
11262 // anonymous flex item.
11263 return true;
11264 }
11265 if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW0x8) &&
11266 aState.GetGeometricParent(*mComputedStyle->StyleDisplay(), nullptr)) {
11267 // We're abspos or fixedpos (or a XUL popup), which means we'll spawn a
11268 // placeholder which (because our container is an emulated legacy box)
11269 // we'll need to wrap in an anonymous flex item. So, we just treat
11270 // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
11271 // and then when we spawn the placeholder, it'll end up in the right
11272 // spot.
11273 return true;
11274 }
11275 }
11276
11277 return false;
11278}
11279
11280inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11281 SkipItemsThatNeedAnonFlexOrGridItem(const nsFrameConstructorState& aState,
11282 bool aIsLegacyWebKitBox) {
11283 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", 11283
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11283); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11284 while (item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox)) {
11285 Next();
11286 if (IsDone()) {
11287 return true;
11288 }
11289 }
11290 return false;
11291}
11292
11293inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11294 SkipItemsThatDontNeedAnonFlexOrGridItem(
11295 const nsFrameConstructorState& aState, bool aIsLegacyWebKitBox) {
11296 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", 11296
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11296); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11297 while (!(item().NeedsAnonFlexOrGridItem(aState, aIsLegacyWebKitBox))) {
11298 Next();
11299 if (IsDone()) {
11300 return true;
11301 }
11302 }
11303 return false;
11304}
11305
11306inline bool nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11307 SkipItemsNotWantingRubyParent() {
11308 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", 11308
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11308); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11309 while (!IsRubyParentType(item().DesiredParentType())) {
11310 Next();
11311 if (IsDone()) {
11312 return true;
11313 }
11314 }
11315 return false;
11316}
11317
11318inline bool
11319nsCSSFrameConstructor::FrameConstructionItemList::Iterator::SkipWhitespace(
11320 nsFrameConstructorState& aState) {
11321 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", 11321
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "Shouldn't be done yet"
")"); do { MOZ_CrashSequence(__null, 11321); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11322 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"
, 11322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "item().IsWhitespace(aState)"
") (" "Not pointing to whitespace?" ")"); do { MOZ_CrashSequence
(__null, 11322); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11323 do {
11324 Next();
11325 if (IsDone()) {
11326 return true;
11327 }
11328 } while (item().IsWhitespace(aState));
11329
11330 return false;
11331}
11332
11333void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11334 AppendItemToList(FrameConstructionItemList& aTargetList) {
11335 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11335); MOZ_PretendNoReturn(); } } while (0)
;
11336 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", 11336
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsDone()" ") (" "should not be done"
")"); do { MOZ_CrashSequence(__null, 11336); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11337
11338 FrameConstructionItem* item = mCurrent;
11339 Next();
11340 item->remove();
11341 aTargetList.mItems.insertBack(item);
11342
11343 mList.AdjustCountsForItem(item, -1);
11344 aTargetList.AdjustCountsForItem(item, 1);
11345}
11346
11347void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::
11348 AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
11349 FrameConstructionItemList& aTargetList) {
11350 NS_ASSERTION(&aTargetList != &mList, "Unexpected call")do { if (!(&aTargetList != &mList)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected call", "&aTargetList != &mList", "./../../../layout/base/nsCSSFrameConstructor.cpp"
, 11350); MOZ_PretendNoReturn(); } } while (0)
;
11351 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", 11351
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11351); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11352
11353 // We can't just move our guts to the other list if it already has
11354 // some information or if we're not moving our entire list.
11355 if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
11356 do {
11357 AppendItemToList(aTargetList);
11358 } while (*this != aEnd);
11359 return;
11360 }
11361
11362 // Move our entire list of items into the empty target list.
11363 aTargetList.mItems = std::move(mList.mItems);
11364
11365 // Copy over the various counters
11366 aTargetList.mInlineCount = mList.mInlineCount;
11367 aTargetList.mBlockCount = mList.mBlockCount;
11368 aTargetList.mItemCount = mList.mItemCount;
11369 memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
11370 sizeof(aTargetList.mDesiredParentCounts));
11371
11372 // reset mList
11373 mList.Reset(aFCtor);
11374
11375 // Point ourselves to aEnd, as advertised
11376 SetToEnd();
11377 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"
, 11377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this == aEnd"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11377); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11378}
11379
11380void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::InsertItem(
11381 FrameConstructionItem* aItem) {
11382 if (IsDone()) {
11383 mList.mItems.insertBack(aItem);
11384 } else {
11385 // Just insert the item before us. There's no magic here.
11386 mCurrent->setPrevious(aItem);
11387 }
11388 mList.AdjustCountsForItem(aItem, 1);
11389
11390 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", 11390
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aItem->getNext() == mCurrent"
") (" "How did that happen?" ")"); do { MOZ_CrashSequence(__null
, 11390); __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
11391}
11392
11393void nsCSSFrameConstructor::FrameConstructionItemList::Iterator::DeleteItemsTo(
11394 nsCSSFrameConstructor* aFCtor, const Iterator& aEnd) {
11395 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", 11395
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "&mList == &aEnd.mList"
") (" "End iterator for some other list?" ")"); do { MOZ_CrashSequence
(__null, 11395); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11396 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"
, 11396); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*this != aEnd"
") (" "Shouldn't be at aEnd yet" ")"); do { MOZ_CrashSequence
(__null, 11396); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
11397
11398 do {
11399 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"
, 11399); MOZ_PretendNoReturn(); } } while (0)
;
11400 FrameConstructionItem* item = mCurrent;
11401 Next();
11402 item->remove();
11403 mList.AdjustCountsForItem(item, -1);
11404 item->Delete(aFCtor);
11405 } while (*this != aEnd);
11406}
11407
11408void nsCSSFrameConstructor::QuotesDirty() {
11409 mQuotesDirty = true;
11410 mPresShell->SetNeedLayoutFlush();
11411}
11412
11413void nsCSSFrameConstructor::CountersDirty() {
11414 mCountersDirty = true;
11415 mPresShell->SetNeedLayoutFlush();
11416}
11417
11418void* nsCSSFrameConstructor::AllocateFCItem() {
11419 void* item;
11420 if (mFirstFreeFCItem) {
11421 item = mFirstFreeFCItem;
11422 mFirstFreeFCItem = mFirstFreeFCItem->mNext;
11423 } else {
11424 item = mFCItemPool.Allocate(sizeof(FrameConstructionItem));
11425 }
11426 ++mFCItemsInUse;
11427 return item;
11428}
11429
11430void nsCSSFrameConstructor::FreeFCItem(FrameConstructionItem* aItem) {
11431 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", 11431);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFCItemsInUse != 0"
")"); do { MOZ_CrashSequence(__null, 11431); __attribute__((
nomerge)) ::abort(); } while (false); } } while (false)
;
11432 if (--mFCItemsInUse == 0) {
11433 // The arena is now unused - clear it but retain one chunk.
11434 mFirstFreeFCItem = nullptr;
11435 mFCItemPool.Clear();
11436 } else {
11437 // Prepend it to the list of free items.
11438 FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
11439 item->mNext = mFirstFreeFCItem;
11440 mFirstFreeFCItem = item;
11441 }
11442}
11443
11444void nsCSSFrameConstructor::AddSizeOfIncludingThis(
11445 nsWindowSizes& aSizes) const {
11446 if (nsIFrame* rootFrame = GetRootFrame()) {
11447 rootFrame->AddSizeOfExcludingThisForTree(aSizes);
11448 if (RetainedDisplayListBuilder* builder =
11449 rootFrame->GetProperty(RetainedDisplayListBuilder::Cached())) {
11450 builder->AddSizeOfIncludingThis(aSizes);
11451 }
11452 }
11453
11454 // This must be done after measuring from the frame tree, since frame
11455 // manager will measure sizes of staled computed values and style
11456 // structs, which only make sense after we know what are being used.
11457 nsFrameManager::AddSizeOfIncludingThis(aSizes);
11458
11459 // Measurement of the following members may be added later if DMD finds it
11460 // is worthwhile:
11461 // - mFCItemPool
11462 // - mContainStyleScopeManager
11463}