Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp
Warning:line 3577, column 7
Value stored to 'createdContainer' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_layout_generic2.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/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 STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/painting -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/tables -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/cairo/cairo/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -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-deprecated-this-capture -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 -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ Unified_cpp_layout_generic2.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/* base class of all rendering objects */
8
9#include "nsIFrame.h"
10
11#include <stdarg.h>
12#include <algorithm>
13
14#include "gfx2DGlue.h"
15#include "gfxUtils.h"
16#include "mozilla/Attributes.h"
17#include "mozilla/CaretAssociationHint.h"
18#include "mozilla/ComputedStyle.h"
19#include "mozilla/DebugOnly.h"
20#include "mozilla/DisplayPortUtils.h"
21#include "mozilla/EventForwards.h"
22#include "mozilla/FocusModel.h"
23#include "mozilla/dom/CSSAnimation.h"
24#include "mozilla/dom/CSSTransition.h"
25#include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h"
26#include "mozilla/dom/DocumentInlines.h"
27#include "mozilla/dom/AncestorIterator.h"
28#include "mozilla/dom/ElementInlines.h"
29#include "mozilla/dom/ImageTracker.h"
30#include "mozilla/dom/Selection.h"
31#include "mozilla/gfx/2D.h"
32#include "mozilla/gfx/PathHelpers.h"
33#include "mozilla/IntegerRange.h"
34#include "mozilla/intl/BidiEmbeddingLevel.h"
35#include "mozilla/Maybe.h"
36#include "mozilla/PresShell.h"
37#include "mozilla/PresShellInlines.h"
38#include "mozilla/ResultExtensions.h"
39#include "mozilla/SelectionMovementUtils.h"
40#include "mozilla/Sprintf.h"
41#include "mozilla/StaticAnalysisFunctions.h"
42#include "mozilla/StaticPrefs_layout.h"
43#include "mozilla/StaticPrefs_print.h"
44#include "mozilla/StaticPrefs_ui.h"
45#include "mozilla/SVGMaskFrame.h"
46#include "mozilla/SVGObserverUtils.h"
47#include "mozilla/SVGTextFrame.h"
48#include "mozilla/SVGIntegrationUtils.h"
49#include "mozilla/SVGUtils.h"
50#include "mozilla/TextControlElement.h"
51#include "mozilla/ToString.h"
52#include "mozilla/Try.h"
53#include "mozilla/ViewportUtils.h"
54
55#include "nsCOMPtr.h"
56#include "nsFieldSetFrame.h"
57#include "nsFlexContainerFrame.h"
58#include "nsFocusManager.h"
59#include "nsFrameList.h"
60#include "nsPlaceholderFrame.h"
61#include "nsIBaseWindow.h"
62#include "nsIContent.h"
63#include "nsIContentInlines.h"
64#include "nsContentUtils.h"
65#include "nsCSSFrameConstructor.h"
66#include "nsCSSProps.h"
67#include "nsCSSPseudoElements.h"
68#include "nsCSSRendering.h"
69#include "nsAtom.h"
70#include "nsString.h"
71#include "nsReadableUtils.h"
72#include "nsTableWrapperFrame.h"
73#include "nsView.h"
74#include "nsViewManager.h"
75#include "nsIScrollableFrame.h"
76#include "nsPresContext.h"
77#include "nsPresContextInlines.h"
78#include "nsStyleConsts.h"
79#include "mozilla/Logging.h"
80#include "nsLayoutUtils.h"
81#include "LayoutLogging.h"
82#include "mozilla/RestyleManager.h"
83#include "nsImageFrame.h"
84#include "nsInlineFrame.h"
85#include "nsFrameSelection.h"
86#include "nsGkAtoms.h"
87#include "nsGridContainerFrame.h"
88#include "nsGfxScrollFrame.h"
89#include "nsCSSAnonBoxes.h"
90#include "nsCanvasFrame.h"
91
92#include "nsFieldSetFrame.h"
93#include "nsFrameTraversal.h"
94#include "nsRange.h"
95#include "nsITextControlFrame.h"
96#include "nsNameSpaceManager.h"
97#include "nsIPercentBSizeObserver.h"
98#include "nsStyleStructInlines.h"
99
100#include "nsBidiPresUtils.h"
101#include "RubyUtils.h"
102#include "TextOverflow.h"
103#include "nsAnimationManager.h"
104
105// For triple-click pref
106#include "imgIRequest.h"
107#include "nsError.h"
108#include "nsContainerFrame.h"
109#include "nsBlockFrame.h"
110#include "nsDisplayList.h"
111#include "nsChangeHint.h"
112#include "nsSubDocumentFrame.h"
113#include "RetainedDisplayListBuilder.h"
114
115#include "gfxContext.h"
116#include "nsAbsoluteContainingBlock.h"
117#include "ScrollSnap.h"
118#include "StickyScrollContainer.h"
119#include "nsFontInflationData.h"
120#include "nsRegion.h"
121#include "nsIFrameInlines.h"
122#include "nsStyleChangeList.h"
123#include "nsWindowSizes.h"
124
125#ifdef ACCESSIBILITY1
126# include "nsAccessibilityService.h"
127#endif
128
129#include "mozilla/AsyncEventDispatcher.h"
130#include "mozilla/CSSClipPathInstance.h"
131#include "mozilla/EffectCompositor.h"
132#include "mozilla/EffectSet.h"
133#include "mozilla/EventListenerManager.h"
134#include "mozilla/EventStateManager.h"
135#include "mozilla/Preferences.h"
136#include "mozilla/LookAndFeel.h"
137#include "mozilla/MouseEvents.h"
138#include "mozilla/ServoStyleSet.h"
139#include "mozilla/ServoStyleSetInlines.h"
140#include "mozilla/css/ImageLoader.h"
141#include "mozilla/dom/HTMLBodyElement.h"
142#include "mozilla/dom/SVGPathData.h"
143#include "mozilla/dom/TouchEvent.h"
144#include "mozilla/gfx/Tools.h"
145#include "mozilla/layers/WebRenderUserData.h"
146#include "mozilla/layout/ScrollAnchorContainer.h"
147#include "nsPrintfCString.h"
148#include "ActiveLayerTracker.h"
149
150#include "nsITheme.h"
151
152using namespace mozilla;
153using namespace mozilla::css;
154using namespace mozilla::dom;
155using namespace mozilla::gfx;
156using namespace mozilla::layers;
157using namespace mozilla::layout;
158typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
159using nsStyleTransformMatrix::TransformReferenceBox;
160
161nsIFrame* nsILineIterator::LineInfo::GetLastFrameOnLine() const {
162 if (!mNumFramesOnLine) {
163 return nullptr; // empty line, not illegal
164 }
165 MOZ_ASSERT(mFirstFrameOnLine)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFirstFrameOnLine)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFirstFrameOnLine))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mFirstFrameOnLine"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFirstFrameOnLine"
")"); do { *((volatile int*)__null) = 165; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
166 nsIFrame* maybeLastFrame = mFirstFrameOnLine;
167 for ([[maybe_unused]] int32_t i : IntegerRange(mNumFramesOnLine - 1)) {
168 maybeLastFrame = maybeLastFrame->GetNextSibling();
169 if (NS_WARN_IF(!maybeLastFrame)NS_warn_if_impl(!maybeLastFrame, "!maybeLastFrame", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 169)
) {
170 return nullptr;
171 }
172 }
173 return maybeLastFrame;
174}
175
176#ifdef HAVE_64BIT_BUILD1
177static_assert(sizeof(nsIFrame) == 120, "nsIFrame should remain small");
178#else
179static_assert(sizeof(void*) == 4, "Odd build config?");
180// FIXME(emilio): Investigate why win32 and android-arm32 have bigger sizes (80)
181// than Linux32 (76).
182static_assert(sizeof(nsIFrame) <= 80, "nsIFrame should remain small");
183#endif
184
185const mozilla::LayoutFrameType nsIFrame::sLayoutFrameTypes[kFrameClassCount] = {
186#define FRAME_ID(class_, type_, ...) mozilla::LayoutFrameType::type_,
187#define ABSTRACT_FRAME_ID(...)
188#include "mozilla/FrameIdList.h"
189#undef FRAME_ID
190#undef ABSTRACT_FRAME_ID
191};
192
193const nsIFrame::ClassFlags nsIFrame::sLayoutFrameClassFlags[kFrameClassCount] =
194 {
195#define FRAME_ID(class_, type_, flags_, ...) flags_,
196#define ABSTRACT_FRAME_ID(...)
197#include "mozilla/FrameIdList.h"
198#undef FRAME_ID
199#undef ABSTRACT_FRAME_ID
200};
201
202std::ostream& operator<<(std::ostream& aStream, const nsDirection& aDirection) {
203 return aStream << (aDirection == eDirNext ? "eDirNext" : "eDirPrevious");
204}
205
206struct nsContentAndOffset {
207 nsIContent* mContent = nullptr;
208 int32_t mOffset = 0;
209};
210
211#include "nsILineIterator.h"
212#include "prenv.h"
213
214// Utility function to set a nsRect-valued property table entry on aFrame,
215// reusing the existing storage if the property happens to be already set.
216template <typename T>
217static void SetOrUpdateRectValuedProperty(
218 nsIFrame* aFrame, FrameProperties::Descriptor<T> aProperty,
219 const nsRect& aNewValue) {
220 bool found;
221 nsRect* rectStorage = aFrame->GetProperty(aProperty, &found);
222 if (!found) {
223 rectStorage = new nsRect(aNewValue);
224 aFrame->AddProperty(aProperty, rectStorage);
225 } else {
226 *rectStorage = aNewValue;
227 }
228}
229
230FrameDestroyContext::~FrameDestroyContext() {
231 for (auto& content : mozilla::Reversed(mAnonymousContent)) {
232 mPresShell->NativeAnonymousContentRemoved(content);
233 content->UnbindFromTree();
234 }
235}
236
237// Formerly the nsIFrameDebug interface
238
239std::ostream& operator<<(std::ostream& aStream, const nsReflowStatus& aStatus) {
240 char complete = 'Y';
241 if (aStatus.IsIncomplete()) {
242 complete = 'N';
243 } else if (aStatus.IsOverflowIncomplete()) {
244 complete = 'O';
245 }
246
247 char brk = 'N';
248 if (aStatus.IsInlineBreakBefore()) {
249 brk = 'B';
250 } else if (aStatus.IsInlineBreakAfter()) {
251 brk = 'A';
252 }
253
254 aStream << "["
255 << "Complete=" << complete << ","
256 << "NIF=" << (aStatus.NextInFlowNeedsReflow() ? 'Y' : 'N') << ","
257 << "Break=" << brk << ","
258 << "FirstLetter=" << (aStatus.FirstLetterComplete() ? 'Y' : 'N')
259 << "]";
260 return aStream;
261}
262
263#ifdef DEBUG1
264
265/**
266 * Note: the log module is created during library initialization which
267 * means that you cannot perform logging before then.
268 */
269mozilla::LazyLogModule nsIFrame::sFrameLogModule("frame");
270
271#endif
272
273NS_DECLARE_FRAME_PROPERTY_DELETABLE(AbsoluteContainingBlockProperty,static const mozilla::FramePropertyDescriptor<nsAbsoluteContainingBlock
>* AbsoluteContainingBlockProperty() { static const auto descriptor
= mozilla::FramePropertyDescriptor<nsAbsoluteContainingBlock
>::NewWithDestructor<DeleteValue>(); return &descriptor
; }
274 nsAbsoluteContainingBlock)static const mozilla::FramePropertyDescriptor<nsAbsoluteContainingBlock
>* AbsoluteContainingBlockProperty() { static const auto descriptor
= mozilla::FramePropertyDescriptor<nsAbsoluteContainingBlock
>::NewWithDestructor<DeleteValue>(); return &descriptor
; }
275
276bool nsIFrame::HasAbsolutelyPositionedChildren() const {
277 return IsAbsoluteContainer() &&
278 GetAbsoluteContainingBlock()->HasAbsoluteFrames();
279}
280
281nsAbsoluteContainingBlock* nsIFrame::GetAbsoluteContainingBlock() const {
282 NS_ASSERTION(IsAbsoluteContainer(),do { if (!(IsAbsoluteContainer())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The frame is not marked as an abspos container correctly",
"IsAbsoluteContainer()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 283); MOZ_PretendNoReturn(); } } while (0)
283 "The frame is not marked as an abspos container correctly")do { if (!(IsAbsoluteContainer())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The frame is not marked as an abspos container correctly",
"IsAbsoluteContainer()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 283); MOZ_PretendNoReturn(); } } while (0)
;
284 nsAbsoluteContainingBlock* absCB =
285 GetProperty(AbsoluteContainingBlockProperty());
286 NS_ASSERTION(absCB,do { if (!(absCB)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The frame is marked as an abspos container but doesn't have "
"the property", "absCB", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 288); MOZ_PretendNoReturn(); } } while (0)
287 "The frame is marked as an abspos container but doesn't have "do { if (!(absCB)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The frame is marked as an abspos container but doesn't have "
"the property", "absCB", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 288); MOZ_PretendNoReturn(); } } while (0)
288 "the property")do { if (!(absCB)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "The frame is marked as an abspos container but doesn't have "
"the property", "absCB", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 288); MOZ_PretendNoReturn(); } } while (0)
;
289 return absCB;
290}
291
292void nsIFrame::MarkAsAbsoluteContainingBlock() {
293 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
")"); do { *((volatile int*)__null) = 293; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
294 NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()),do { if (!(!GetProperty(AbsoluteContainingBlockProperty()))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Already has an abs-pos containing block property?"
, "!GetProperty(AbsoluteContainingBlockProperty())", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 295); MOZ_PretendNoReturn(); } } while (0)
295 "Already has an abs-pos containing block property?")do { if (!(!GetProperty(AbsoluteContainingBlockProperty()))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Already has an abs-pos containing block property?"
, "!GetProperty(AbsoluteContainingBlockProperty())", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 295); MOZ_PretendNoReturn(); } } while (0)
;
296 NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),do { if (!(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?"
, "!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 297); MOZ_PretendNoReturn(); } } while (0)
297 "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?")do { if (!(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?"
, "!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 297); MOZ_PretendNoReturn(); } } while (0)
;
298 AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
299 SetProperty(AbsoluteContainingBlockProperty(),
300 new nsAbsoluteContainingBlock(GetAbsoluteListID()));
301}
302
303void nsIFrame::MarkAsNotAbsoluteContainingBlock() {
304 NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!")do { if (!(!HasAbsolutelyPositionedChildren())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Think of the children!", "!HasAbsolutelyPositionedChildren()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 304); MOZ_PretendNoReturn(); } } while (0)
;
305 NS_ASSERTION(GetProperty(AbsoluteContainingBlockProperty()),do { if (!(GetProperty(AbsoluteContainingBlockProperty()))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have an abs-pos containing block property"
, "GetProperty(AbsoluteContainingBlockProperty())", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 306); MOZ_PretendNoReturn(); } } while (0)
306 "Should have an abs-pos containing block property")do { if (!(GetProperty(AbsoluteContainingBlockProperty()))) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Should have an abs-pos containing block property"
, "GetProperty(AbsoluteContainingBlockProperty())", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 306); MOZ_PretendNoReturn(); } } while (0)
;
307 NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),do { if (!(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit"
, "HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 308); MOZ_PretendNoReturn(); } } while (0)
308 "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit")do { if (!(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit"
, "HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 308); MOZ_PretendNoReturn(); } } while (0)
;
309 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)"
")"); do { *((volatile int*)__null) = 309; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
310 RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
311 RemoveProperty(AbsoluteContainingBlockProperty());
312}
313
314bool nsIFrame::CheckAndClearPaintedState() {
315 bool result = HasAnyStateBits(NS_FRAME_PAINTED_THEBES);
316 RemoveStateBits(NS_FRAME_PAINTED_THEBES);
317
318 for (const auto& childList : ChildLists()) {
319 for (nsIFrame* child : childList.mList) {
320 if (child->CheckAndClearPaintedState()) {
321 result = true;
322 }
323 }
324 }
325 return result;
326}
327
328bool nsIFrame::CheckAndClearDisplayListState() {
329 bool result = BuiltDisplayList();
330 SetBuiltDisplayList(false);
331
332 for (const auto& childList : ChildLists()) {
333 for (nsIFrame* child : childList.mList) {
334 if (child->CheckAndClearDisplayListState()) {
335 result = true;
336 }
337 }
338 }
339 return result;
340}
341
342bool nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const {
343 if (!StyleVisibility()->IsVisible()) {
344 return false;
345 }
346
347 if (PresShell()->IsUnderHiddenEmbedderElement()) {
348 return false;
349 }
350
351 const nsIFrame* frame = this;
352 while (frame) {
353 nsView* view = frame->GetView();
354 if (view && view->GetVisibility() == ViewVisibility::Hide) {
355 return false;
356 }
357
358 if (frame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
359 return false;
360 }
361
362 // This method is used to determine if a frame is focusable, because it's
363 // called by nsIFrame::IsFocusable. `content-visibility: auto` should not
364 // force this frame to be unfocusable, so we only take into account
365 // `content-visibility: hidden` here.
366 if (this != frame &&
367 frame->HidesContent(IncludeContentVisibility::Hidden)) {
368 return false;
369 }
370
371 if (nsIFrame* parent = frame->GetParent()) {
372 frame = parent;
373 } else {
374 parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame);
375 if (!parent) break;
376
377 if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
378 parent->PresContext()->IsChrome() &&
379 !frame->PresContext()->IsChrome()) {
380 break;
381 }
382
383 frame = parent;
384 }
385 }
386
387 return true;
388}
389
390void nsIFrame::FindCloserFrameForSelection(
391 const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame) {
392 if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
393 aCurrentBestFrame->mXDistance,
394 aCurrentBestFrame->mYDistance)) {
395 aCurrentBestFrame->mFrame = this;
396 }
397}
398
399void nsIFrame::ElementStateChanged(mozilla::dom::ElementState aStates) {}
400
401void WeakFrame::Clear(mozilla::PresShell* aPresShell) {
402 if (aPresShell) {
403 aPresShell->RemoveWeakFrame(this);
404 }
405 mFrame = nullptr;
406}
407
408AutoWeakFrame::AutoWeakFrame(const WeakFrame& aOther)
409 : mPrev(nullptr), mFrame(nullptr) {
410 Init(aOther.GetFrame());
411}
412
413void AutoWeakFrame::Clear(mozilla::PresShell* aPresShell) {
414 if (aPresShell) {
415 aPresShell->RemoveAutoWeakFrame(this);
416 }
417 mFrame = nullptr;
418 mPrev = nullptr;
419}
420
421AutoWeakFrame::~AutoWeakFrame() {
422 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
423}
424
425void AutoWeakFrame::Init(nsIFrame* aFrame) {
426 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
427 mFrame = aFrame;
428 if (mFrame) {
429 mozilla::PresShell* presShell = mFrame->PresContext()->GetPresShell();
430 NS_WARNING_ASSERTION(presShell, "Null PresShell in AutoWeakFrame!")do { if (!(presShell)) { NS_DebugBreak(NS_DEBUG_WARNING, "Null PresShell in AutoWeakFrame!"
, "presShell", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 430); } } while (false)
;
431 if (presShell) {
432 presShell->AddAutoWeakFrame(this);
433 } else {
434 mFrame = nullptr;
435 }
436 }
437}
438
439void WeakFrame::Init(nsIFrame* aFrame) {
440 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
441 mFrame = aFrame;
442 if (mFrame) {
443 mozilla::PresShell* presShell = mFrame->PresContext()->GetPresShell();
444 MOZ_ASSERT(presShell, "Null PresShell in WeakFrame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presShell))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("presShell" " (" "Null PresShell in WeakFrame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presShell" ") ("
"Null PresShell in WeakFrame!" ")"); do { *((volatile int*)__null
) = 444; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
445 if (presShell) {
446 presShell->AddWeakFrame(this);
447 } else {
448 mFrame = nullptr;
449 }
450 }
451}
452
453nsIFrame* NS_NewEmptyFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
454 return new (aPresShell) nsIFrame(aStyle, aPresShell->GetPresContext());
455}
456
457nsIFrame::~nsIFrame() {
458 MOZ_COUNT_DTOR(nsIFrame)do { static_assert(std::is_class_v<nsIFrame>, "Token '"
"nsIFrame" "' is not a class type."); static_assert(!std::is_base_of
<nsISupports, nsIFrame>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "nsIFrame", sizeof
(*this)); } while (0)
;
459
460 MOZ_ASSERT(GetVisibility() != Visibility::ApproximatelyVisible,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetVisibility() != Visibility::ApproximatelyVisible)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(GetVisibility() != Visibility::ApproximatelyVisible)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("GetVisibility() != Visibility::ApproximatelyVisible"
" (" "Visible nsFrame is being destroyed" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetVisibility() != Visibility::ApproximatelyVisible"
") (" "Visible nsFrame is being destroyed" ")"); do { *((volatile
int*)__null) = 461; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
461 "Visible nsFrame is being destroyed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetVisibility() != Visibility::ApproximatelyVisible)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(GetVisibility() != Visibility::ApproximatelyVisible)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("GetVisibility() != Visibility::ApproximatelyVisible"
" (" "Visible nsFrame is being destroyed" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "GetVisibility() != Visibility::ApproximatelyVisible"
") (" "Visible nsFrame is being destroyed" ")"); do { *((volatile
int*)__null) = 461; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
462}
463
464NS_IMPL_FRAMEARENA_HELPERS(nsIFrame)void* nsIFrame ::operator new(size_t sz, mozilla::PresShell *
aShell) { return aShell->AllocateFrame(nsQueryFrame::nsIFrame_id
, sz); }
465
466// Dummy operator delete. Will never be called, but must be defined
467// to satisfy some C++ ABIs.
468void nsIFrame::operator delete(void*, size_t) {
469 MOZ_CRASH("nsIFrame::operator delete should never be called")do { do { } while (false); MOZ_ReportCrash("" "nsIFrame::operator delete should never be called"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 469); AnnotateMozCrashReason("MOZ_CRASH(" "nsIFrame::operator delete should never be called"
")"); do { *((volatile int*)__null) = 469; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
470}
471
472NS_QUERYFRAME_HEAD(nsIFrame)void* nsIFrame ::QueryFrame(FrameIID id) const { switch (id) {
473 NS_QUERYFRAME_ENTRY(nsIFrame)case nsIFrame ::kFrameIID: { static_assert( std::is_same_v<
nsIFrame, nsIFrame ::Has_NS_DECL_QUERYFRAME_TARGET>, "nsIFrame"
" must declare itself as a queryframe target"); return const_cast
<nsIFrame*>(static_cast<const nsIFrame*>(this)); }
474NS_QUERYFRAME_TAIL_INHERITANCE_ROOTdefault: break; } do { static_assert( mozilla::detail::AssertionConditionType
<decltype(id != GetFrameId())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(id != GetFrameId()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("id != GetFrameId()"
" (" "A frame failed to QueryFrame to its *own type*. " "It may be missing NS_DECL_QUERYFRAME, or a "
"NS_QUERYFRAME_ENTRY() line with its own type name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "id != GetFrameId()"
") (" "A frame failed to QueryFrame to its *own type*. " "It may be missing NS_DECL_QUERYFRAME, or a "
"NS_QUERYFRAME_ENTRY() line with its own type name" ")"); do
{ *((volatile int*)__null) = 474; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false); return nullptr; }
475
476/////////////////////////////////////////////////////////////////////////////
477// nsIFrame
478
479static bool IsFontSizeInflationContainer(nsIFrame* aFrame,
480 const nsStyleDisplay* aStyleDisplay) {
481 /*
482 * Font size inflation is built around the idea that we're inflating
483 * the fonts for a pan-and-zoom UI so that when the user scales up a
484 * block or other container to fill the width of the device, the fonts
485 * will be readable. To do this, we need to pick what counts as a
486 * container.
487 *
488 * From a code perspective, the only hard requirement is that frames
489 * that are line participants (nsIFrame::IsLineParticipant) are never
490 * containers, since line layout assumes that the inflation is consistent
491 * within a line.
492 *
493 * This is not an imposition, since we obviously want a bunch of text
494 * (possibly with inline elements) flowing within a block to count the
495 * block (or higher) as its container.
496 *
497 * We also want form controls, including the text in the anonymous
498 * content inside of them, to match each other and the text next to
499 * them, so they and their anonymous content should also not be a
500 * container.
501 *
502 * However, because we can't reliably compute sizes across XUL during
503 * reflow, any XUL frame with a XUL parent is always a container.
504 *
505 * There are contexts where it would be nice if some blocks didn't
506 * count as a container, so that, for example, an indented quotation
507 * didn't end up with a smaller font size. However, it's hard to
508 * distinguish these situations where we really do want the indented
509 * thing to count as a container, so we don't try, and blocks are
510 * always containers.
511 */
512
513 // The root frame should always be an inflation container.
514 if (!aFrame->GetParent()) {
515 return true;
516 }
517
518 nsIContent* content = aFrame->GetContent();
519 if (content && content->IsInNativeAnonymousSubtree()) {
520 // Native anonymous content shouldn't be a font inflation root,
521 // except for the canvas custom content container.
522 nsCanvasFrame* canvas = aFrame->PresShell()->GetCanvasFrame();
523 return canvas && canvas->GetCustomContentContainer() == content;
524 }
525
526 LayoutFrameType frameType = aFrame->Type();
527 bool isInline =
528 aFrame->GetDisplay().IsInlineFlow() || RubyUtils::IsRubyBox(frameType) ||
529 (aStyleDisplay->IsFloatingStyle() &&
530 frameType == LayoutFrameType::Letter) ||
531 // Given multiple frames for the same node, only the
532 // outer one should be considered a container.
533 // (Important, e.g., for nsSelectsAreaFrame.)
534 (aFrame->GetParent()->GetContent() == content) ||
535 (content &&
536 // Form controls shouldn't become inflation containers.
537 (content->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup,
538 nsGkAtoms::select, nsGkAtoms::input,
539 nsGkAtoms::button, nsGkAtoms::textarea)));
540 NS_ASSERTION(!aFrame->IsLineParticipant() || isInline ||do { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
541 // br frames and mathml frames report being linedo { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
542 // participants even when their position or display isdo { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
543 // setdo { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
544 aFrame->IsBrFrame() || aFrame->IsMathMLFrame(),do { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
545 "line participants must not be containers")do { if (!(!aFrame->IsLineParticipant() || isInline || aFrame
->IsBrFrame() || aFrame->IsMathMLFrame())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "line participants must not be containers"
, "!aFrame->IsLineParticipant() || isInline || aFrame->IsBrFrame() || aFrame->IsMathMLFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 545); MOZ_PretendNoReturn(); } } while (0)
;
546 return !isInline;
547}
548
549static void MaybeScheduleReflowSVGNonDisplayText(nsIFrame* aFrame) {
550 if (!aFrame->IsInSVGTextSubtree()) {
551 return;
552 }
553
554 // We need to ensure that any non-display SVGTextFrames get reflowed when a
555 // child text frame gets new style. Thus we need to schedule a reflow in
556 // |DidSetComputedStyle|. We also need to call it from |DestroyFrom|,
557 // because otherwise we won't get notified when style changes to
558 // "display:none".
559 SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
560 nsLayoutUtils::GetClosestFrameOfType(aFrame, LayoutFrameType::SVGText));
561 nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
562
563 // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
564 // anonymous block frame rather than our aFrame, since NS_FRAME_FIRST_REFLOW
565 // may be set on us if we're a new frame that has been inserted after the
566 // document's first reflow. (In which case this DidSetComputedStyle call may
567 // be happening under frame construction under a Reflow() call.)
568 if (!anonBlock || anonBlock->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
569 return;
570 }
571
572 if (!svgTextFrame->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY) ||
573 svgTextFrame->HasAnyStateBits(NS_STATE_SVG_TEXT_IN_REFLOW)) {
574 return;
575 }
576
577 svgTextFrame->ScheduleReflowSVGNonDisplayText(
578 IntrinsicDirty::FrameAncestorsAndDescendants);
579}
580
581bool nsIFrame::IsPrimaryFrameOfRootOrBodyElement() const {
582 if (!IsPrimaryFrame()) {
583 return false;
584 }
585 nsIContent* content = GetContent();
586 Document* document = content->OwnerDoc();
587 return content == document->GetRootElement() ||
588 content == document->GetBodyElement();
589}
590
591bool nsIFrame::IsRenderedLegend() const {
592 if (auto* parent = GetParent(); parent && parent->IsFieldSetFrame()) {
593 return static_cast<nsFieldSetFrame*>(parent)->GetLegend() == this;
594 }
595 return false;
596}
597
598void nsIFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
599 nsIFrame* aPrevInFlow) {
600 MOZ_ASSERT(nsQueryFrame::FrameIID(mClass) == GetFrameId())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsQueryFrame::FrameIID(mClass) == GetFrameId())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nsQueryFrame::FrameIID(mClass) == GetFrameId()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("nsQueryFrame::FrameIID(mClass) == GetFrameId()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsQueryFrame::FrameIID(mClass) == GetFrameId()"
")"); do { *((volatile int*)__null) = 600; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
601 MOZ_ASSERT(!mContent, "Double-initing a frame?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mContent" " (" "Double-initing a frame?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mContent" ") ("
"Double-initing a frame?" ")"); do { *((volatile int*)__null
) = 601; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
602
603 mContent = aContent;
604 mParent = aParent;
605 MOZ_DIAGNOSTIC_ASSERT(!mParent || PresShell() == mParent->PresShell())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mParent || PresShell() == mParent->PresShell())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mParent || PresShell() == mParent->PresShell()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mParent || PresShell() == mParent->PresShell()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 605); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mParent || PresShell() == mParent->PresShell()"
")"); do { *((volatile int*)__null) = 605; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
606
607 if (aPrevInFlow) {
608 mWritingMode = aPrevInFlow->GetWritingMode();
609
610 // Copy some state bits from prev-in-flow (the bits that should apply
611 // throughout a continuation chain). The bits are sorted according to their
612 // order in nsFrameStateBits.h.
613
614 // clang-format off
615 AddStateBits(aPrevInFlow->GetStateBits() &
616 (NS_FRAME_GENERATED_CONTENT |
617 NS_FRAME_OUT_OF_FLOW |
618 NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN |
619 NS_FRAME_INDEPENDENT_SELECTION |
620 NS_FRAME_PART_OF_IBSPLIT |
621 NS_FRAME_MAY_BE_TRANSFORMED |
622 NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR));
623 // clang-format on
624
625 // Copy other bits in nsIFrame from prev-in-flow.
626 mHasColumnSpanSiblings = aPrevInFlow->HasColumnSpanSiblings();
627 } else {
628 PresContext()->ConstructedFrame();
629 }
630
631 if (GetParent()) {
632 if (MOZ_UNLIKELY(mContent == PresContext()->Document()->GetRootElement() &&(__builtin_expect(!!(mContent == PresContext()->Document()
->GetRootElement() && mContent == GetParent()->
GetContent()), 0))
633 mContent == GetParent()->GetContent())(__builtin_expect(!!(mContent == PresContext()->Document()
->GetRootElement() && mContent == GetParent()->
GetContent()), 0))
) {
634 // Our content is the root element and we have the same content as our
635 // parent. That is, we are the internal anonymous frame of the root
636 // element. Copy the used mWritingMode from our parent because
637 // mDocElementContainingBlock gets its mWritingMode from <body>.
638 mWritingMode = GetParent()->GetWritingMode();
639 }
640
641 // Copy some state bits from our parent (the bits that should apply
642 // recursively throughout a subtree). The bits are sorted according to their
643 // order in nsFrameStateBits.h.
644
645 // clang-format off
646 AddStateBits(GetParent()->GetStateBits() &
647 (NS_FRAME_GENERATED_CONTENT |
648 NS_FRAME_INDEPENDENT_SELECTION |
649 NS_FRAME_IS_SVG_TEXT |
650 NS_FRAME_IN_POPUP |
651 NS_FRAME_IS_NONDISPLAY));
652 // clang-format on
653
654 if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
655 // Assume all frames in popups are visible.
656 IncApproximateVisibleCount();
657 }
658 }
659 if (aPrevInFlow) {
660 mMayHaveOpacityAnimation = aPrevInFlow->MayHaveOpacityAnimation();
661 mMayHaveTransformAnimation = aPrevInFlow->MayHaveTransformAnimation();
662 } else if (mContent) {
663 // It's fine to fetch the EffectSet for the style frame here because in the
664 // following code we take care of the case where animations may target
665 // a different frame.
666 EffectSet* effectSet = EffectSet::GetForStyleFrame(this);
667 if (effectSet) {
668 mMayHaveOpacityAnimation = effectSet->MayHaveOpacityAnimation();
669
670 if (effectSet->MayHaveTransformAnimation()) {
671 // If we are the inner table frame for display:table content, then
672 // transform animations should go on our parent frame (the table wrapper
673 // frame).
674 //
675 // We do this when initializing the child frame (table inner frame),
676 // because when initializng the table wrapper frame, we don't yet have
677 // access to its children so we can't tell if we have transform
678 // animations or not.
679 if (SupportsCSSTransforms()) {
680 mMayHaveTransformAnimation = true;
681 AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
682 } else if (aParent && nsLayoutUtils::GetStyleFrame(aParent) == this) {
683 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->SupportsCSSTransforms())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->SupportsCSSTransforms
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->SupportsCSSTransforms()" " (" "Style frames that don't support transforms should have parents"
" that do" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->SupportsCSSTransforms()"
") (" "Style frames that don't support transforms should have parents"
" that do" ")"); do { *((volatile int*)__null) = 686; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
684 aParent->SupportsCSSTransforms(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->SupportsCSSTransforms())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->SupportsCSSTransforms
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->SupportsCSSTransforms()" " (" "Style frames that don't support transforms should have parents"
" that do" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->SupportsCSSTransforms()"
") (" "Style frames that don't support transforms should have parents"
" that do" ")"); do { *((volatile int*)__null) = 686; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
685 "Style frames that don't support transforms should have parents"do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->SupportsCSSTransforms())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->SupportsCSSTransforms
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->SupportsCSSTransforms()" " (" "Style frames that don't support transforms should have parents"
" that do" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->SupportsCSSTransforms()"
") (" "Style frames that don't support transforms should have parents"
" that do" ")"); do { *((volatile int*)__null) = 686; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
686 " that do")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent->SupportsCSSTransforms())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent->SupportsCSSTransforms
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aParent->SupportsCSSTransforms()" " (" "Style frames that don't support transforms should have parents"
" that do" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent->SupportsCSSTransforms()"
") (" "Style frames that don't support transforms should have parents"
" that do" ")"); do { *((volatile int*)__null) = 686; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
687 aParent->mMayHaveTransformAnimation = true;
688 aParent->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
689 }
690 }
691 }
692 }
693
694 const nsStyleDisplay* disp = StyleDisplay();
695 if (disp->HasTransform(this)) {
696 // If 'transform' dynamically changes, RestyleManager takes care of
697 // updating this bit.
698 AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
699 }
700
701 if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) ||
702 !GetParent()
703#ifdef DEBUG1
704 // We have assertions that check inflation invariants even when
705 // font size inflation is not enabled.
706 || true
707#endif
708 ) {
709 if (IsFontSizeInflationContainer(this, disp)) {
710 AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
711 if (!GetParent() ||
712 // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
713 disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this) ||
714 GetParent()->IsFlexContainerFrame() ||
715 GetParent()->IsGridContainerFrame()) {
716 AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
717 }
718 }
719 NS_ASSERTION(do { if (!(GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "root frame should always be a container"
, "GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 721); MOZ_PretendNoReturn(); } } while (0)
720 GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER),do { if (!(GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "root frame should always be a container"
, "GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 721); MOZ_PretendNoReturn(); } } while (0)
721 "root frame should always be a container")do { if (!(GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "root frame should always be a container"
, "GetParent() || HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 721); MOZ_PretendNoReturn(); } } while (0)
;
722 }
723
724 if (TrackingVisibility() && PresShell()->AssumeAllFramesVisible()) {
725 IncApproximateVisibleCount();
726 }
727
728 DidSetComputedStyle(nullptr);
729
730 // For a newly created frame, we need to update this frame's visibility state.
731 // Usually we update the state when the frame is restyled and has a
732 // VisibilityChange change hint but we don't generate any change hints for
733 // newly created frames.
734 // Note: We don't need to do this for placeholders since placeholders have
735 // different styles so that the styles don't have visibility:hidden even if
736 // the parent has visibility:hidden style. We also don't need to update the
737 // state when creating continuations because its visibility is the same as its
738 // prev-in-flow, and the animation code cares only primary frames.
739 if (!IsPlaceholderFrame() && !aPrevInFlow) {
740 UpdateVisibleDescendantsState();
741 }
742
743 if (!aPrevInFlow && HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
744 // We aren't going to get a reflow, so nothing else will call
745 // InvalidateRenderingObservers, we have to do it here.
746 SVGObserverUtils::InvalidateRenderingObservers(this);
747 }
748}
749
750void nsIFrame::InitPrimaryFrame() {
751 MOZ_ASSERT(IsPrimaryFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPrimaryFrame()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsPrimaryFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPrimaryFrame()"
")"); do { *((volatile int*)__null) = 751; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
752 HandlePrimaryFrameStyleChange(nullptr);
753}
754
755void nsIFrame::HandlePrimaryFrameStyleChange(ComputedStyle* aOldStyle) {
756 const nsStyleDisplay* disp = StyleDisplay();
757 const nsStyleDisplay* oldDisp =
758 aOldStyle ? aOldStyle->StyleDisplay() : nullptr;
759
760 const bool wasQueryContainer = oldDisp && oldDisp->IsQueryContainer();
761 const bool isQueryContainer = disp->IsQueryContainer();
762 if (wasQueryContainer != isQueryContainer) {
763 auto* pc = PresContext();
764 if (isQueryContainer) {
765 pc->RegisterContainerQueryFrame(this);
766 } else {
767 pc->UnregisterContainerQueryFrame(this);
768 }
769 }
770
771 const auto cv = disp->ContentVisibility(*this);
772 if (!oldDisp || oldDisp->ContentVisibility(*this) != cv) {
773 if (cv == StyleContentVisibility::Auto) {
774 PresShell()->RegisterContentVisibilityAutoFrame(this);
775 } else {
776 if (auto* element = Element::FromNodeOrNull(GetContent())) {
777 element->ClearContentRelevancy();
778 }
779 PresShell()->UnregisterContentVisibilityAutoFrame(this);
780 }
781 PresContext()->SetNeedsToUpdateHiddenByContentVisibilityForAnimations();
782 }
783
784 HandleLastRememberedSize();
785}
786
787void nsIFrame::Destroy(DestroyContext& aContext) {
788 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),do { if (!(!nsContentUtils::IsSafeToRunScript())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "destroy called on frame while scripts not blocked"
, "!nsContentUtils::IsSafeToRunScript()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 789); MOZ_PretendNoReturn(); } } while (0)
789 "destroy called on frame while scripts not blocked")do { if (!(!nsContentUtils::IsSafeToRunScript())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "destroy called on frame while scripts not blocked"
, "!nsContentUtils::IsSafeToRunScript()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 789); MOZ_PretendNoReturn(); } } while (0)
;
790 NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),do { if (!(!GetNextSibling() && !GetPrevSibling())) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Frames should be removed before destruction."
, "!GetNextSibling() && !GetPrevSibling()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 791); MOZ_PretendNoReturn(); } } while (0)
791 "Frames should be removed before destruction.")do { if (!(!GetNextSibling() && !GetPrevSibling())) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "Frames should be removed before destruction."
, "!GetNextSibling() && !GetPrevSibling()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 791); MOZ_PretendNoReturn(); } } while (0)
;
792 MOZ_ASSERT(!HasAbsolutelyPositionedChildren())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasAbsolutelyPositionedChildren())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!HasAbsolutelyPositionedChildren
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!HasAbsolutelyPositionedChildren()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasAbsolutelyPositionedChildren()"
")"); do { *((volatile int*)__null) = 792; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
793 MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)"
" (" "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)"
") (" "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?"
")"); do { *((volatile int*)__null) = 794; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
794 "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)"
" (" "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)"
") (" "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?"
")"); do { *((volatile int*)__null) = 794; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
795
796 MaybeScheduleReflowSVGNonDisplayText(this);
797
798 SVGObserverUtils::InvalidateDirectRenderingObservers(this);
799
800 const auto* disp = StyleDisplay();
801 if (disp->mPosition == StylePositionProperty::Sticky) {
802 if (auto* ssc =
803 StickyScrollContainer::GetStickyScrollContainerForFrame(this)) {
804 ssc->RemoveFrame(this);
805 }
806 }
807
808 if (HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
809 if (nsPlaceholderFrame* placeholder = GetPlaceholderFrame()) {
810 placeholder->SetOutOfFlowFrame(nullptr);
811 }
812 }
813
814 nsPresContext* pc = PresContext();
815 mozilla::PresShell* ps = pc->GetPresShell();
816 if (IsPrimaryFrame()) {
817 if (disp->IsQueryContainer()) {
818 pc->UnregisterContainerQueryFrame(this);
819 }
820 if (disp->ContentVisibility(*this) == StyleContentVisibility::Auto) {
821 ps->UnregisterContentVisibilityAutoFrame(this);
822 }
823 // This needs to happen before we clear our Properties() table.
824 ActiveLayerTracker::TransferActivityToContent(this, mContent);
825 }
826
827 ScrollAnchorContainer* anchor = nullptr;
828 if (IsScrollAnchor(&anchor)) {
829 anchor->InvalidateAnchor();
830 }
831
832 if (HasCSSAnimations() || HasCSSTransitions() ||
833 // It's fine to look up the style frame here since if we're destroying the
834 // frames for display:table content we should be destroying both wrapper
835 // and inner frame.
836 EffectSet::GetForStyleFrame(this)) {
837 // If no new frame for this element is created by the end of the
838 // restyling process, stop animations and transitions for this frame
839 RestyleManager::AnimationsWithDestroyedFrame* adf =
840 pc->RestyleManager()->GetAnimationsWithDestroyedFrame();
841 // AnimationsWithDestroyedFrame only lives during the restyling process.
842 if (adf) {
843 adf->Put(mContent, mComputedStyle);
844 }
845 }
846
847 // Disable visibility tracking. Note that we have to do this before we clear
848 // frame properties and lose track of whether we were previously visible.
849 // XXX(seth): It'd be ideal to assert that we're already marked nonvisible
850 // here, but it's unfortunately tricky to guarantee in the face of things like
851 // frame reconstruction induced by style changes.
852 DisableVisibilityTracking();
853
854 // Ensure that we're not in the approximately visible list anymore.
855 ps->RemoveFrameFromApproximatelyVisibleList(this);
856
857 ps->NotifyDestroyingFrame(this);
858
859 if (HasAnyStateBits(NS_FRAME_EXTERNAL_REFERENCE)) {
860 ps->ClearFrameRefs(this);
861 }
862
863 nsView* view = GetView();
864 if (view) {
865 view->SetFrame(nullptr);
866 view->Destroy();
867 }
868
869 // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
870 if (IsPrimaryFrame()) {
871 mContent->SetPrimaryFrame(nullptr);
872
873 // Pass the root of a generated content subtree (e.g. ::after/::before) to
874 // aPostDestroyData to unbind it after frame destruction is done.
875 if (HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
876 mContent->IsRootOfNativeAnonymousSubtree()) {
877 aContext.AddAnonymousContent(mContent.forget());
878 }
879 }
880
881 // Remove all properties attached to the frame, to ensure any property
882 // destructors that need the frame pointer are handled properly.
883 RemoveAllProperties();
884
885 // Must retrieve the object ID before calling destructors, so the
886 // vtable is still valid.
887 //
888 // Note to future tweakers: having the method that returns the
889 // object size call the destructor will not avoid an indirect call;
890 // the compiler cannot devirtualize the call to the destructor even
891 // if it's from a method defined in the same class.
892
893 nsQueryFrame::FrameIID id = GetFrameId();
894 this->~nsIFrame();
895
896#ifdef DEBUG1
897 {
898 nsIFrame* rootFrame = ps->GetRootFrame();
899 MOZ_ASSERT(rootFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rootFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rootFrame))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("rootFrame", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rootFrame" ")"
); do { *((volatile int*)__null) = 899; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
900 if (this != rootFrame) {
901 auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(rootFrame);
902 auto* data = builder ? builder->Data() : nullptr;
903
904 const bool inData =
905 data && (data->IsModified(this) || data->HasProps(this));
906
907 if (inData) {
908 DL_LOG(LogLevel::Warning, "Frame %p found in retained data", this)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Warning)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Warning, "Frame %p found in retained data", this)
; } } while (0)
;
909 }
910
911 MOZ_ASSERT(!inData, "Deleted frame in retained data!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inData))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!inData" " (" "Deleted frame in retained data!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inData" ") ("
"Deleted frame in retained data!" ")"); do { *((volatile int
*)__null) = 911; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
912 }
913 }
914#endif
915
916 // Now that we're totally cleaned out, we need to add ourselves to
917 // the presshell's recycler.
918 ps->FreeFrame(id, this);
919}
920
921std::pair<int32_t, int32_t> nsIFrame::GetOffsets() const {
922 return std::make_pair(0, 0);
923}
924
925static void CompareLayers(
926 const nsStyleImageLayers* aFirstLayers,
927 const nsStyleImageLayers* aSecondLayers,
928 const std::function<void(imgRequestProxy* aReq)>& aCallback) {
929 NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aFirstLayers))for (uint32_t i = ((*aFirstLayers)).mImageCount; (i)-- != 0;) {
930 const auto& image = aFirstLayers->mLayers[i].mImage;
931 if (!image.IsImageRequestType() || !image.IsResolved()) {
932 continue;
933 }
934
935 // aCallback is called when the style image in aFirstLayers is thought to
936 // be different with the corresponded one in aSecondLayers
937 if (!aSecondLayers || i >= aSecondLayers->mImageCount ||
938 (!aSecondLayers->mLayers[i].mImage.IsResolved() ||
939 image.GetImageRequest() !=
940 aSecondLayers->mLayers[i].mImage.GetImageRequest())) {
941 if (imgRequestProxy* req = image.GetImageRequest()) {
942 aCallback(req);
943 }
944 }
945 }
946}
947
948static void AddAndRemoveImageAssociations(
949 ImageLoader& aImageLoader, nsIFrame* aFrame,
950 const nsStyleImageLayers* aOldLayers,
951 const nsStyleImageLayers* aNewLayers) {
952 // If the old context had a background-image image, or mask-image image,
953 // and new context does not have the same image, clear the image load
954 // notifier (which keeps the image loading, if it still is) for the frame.
955 // We want to do this conservatively because some frames paint their
956 // backgrounds from some other frame's style data, and we don't want
957 // to clear those notifiers unless we have to. (They'll be reset
958 // when we paint, although we could miss a notification in that
959 // interval.)
960 if (aOldLayers && aFrame->HasImageRequest()) {
961 CompareLayers(aOldLayers, aNewLayers, [&](imgRequestProxy* aReq) {
962 aImageLoader.DisassociateRequestFromFrame(aReq, aFrame);
963 });
964 }
965
966 CompareLayers(aNewLayers, aOldLayers, [&](imgRequestProxy* aReq) {
967 aImageLoader.AssociateRequestToFrame(aReq, aFrame);
968 });
969}
970
971void nsIFrame::AddDisplayItem(nsDisplayItem* aItem) {
972 MOZ_DIAGNOSTIC_ASSERT(!mDisplayItems.Contains(aItem))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDisplayItems.Contains(aItem))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDisplayItems.Contains(aItem
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mDisplayItems.Contains(aItem)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 972); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mDisplayItems.Contains(aItem)"
")"); do { *((volatile int*)__null) = 972; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
973 mDisplayItems.AppendElement(aItem);
974#ifdef ACCESSIBILITY1
975 if (nsAccessibilityService* accService = GetAccService()) {
976 accService->NotifyOfPossibleBoundsChange(PresShell(), mContent);
977 }
978#endif
979}
980
981bool nsIFrame::RemoveDisplayItem(nsDisplayItem* aItem) {
982 return mDisplayItems.RemoveElement(aItem);
983}
984
985bool nsIFrame::HasDisplayItems() { return !mDisplayItems.IsEmpty(); }
986
987bool nsIFrame::HasDisplayItem(nsDisplayItem* aItem) {
988 return mDisplayItems.Contains(aItem);
989}
990
991bool nsIFrame::HasDisplayItem(uint32_t aKey) {
992 for (nsDisplayItem* i : mDisplayItems) {
993 if (i->GetPerFrameKey() == aKey) {
994 return true;
995 }
996 }
997 return false;
998}
999
1000template <typename Condition>
1001static void DiscardDisplayItems(nsIFrame* aFrame, Condition aCondition) {
1002 for (nsDisplayItem* i : aFrame->DisplayItems()) {
1003 // Only discard items that are invalidated by this frame, as we're only
1004 // guaranteed to rebuild those items. Table background items are created by
1005 // the relevant table part, but have the cell frame as the primary frame,
1006 // and we don't want to remove them if this is the cell.
1007 if (aCondition(i) && i->FrameForInvalidation() == aFrame) {
1008 i->SetCantBeReused();
1009 }
1010 }
1011}
1012
1013static void DiscardOldItems(nsIFrame* aFrame) {
1014 DiscardDisplayItems(aFrame,
1015 [](nsDisplayItem* aItem) { return aItem->IsOldItem(); });
1016}
1017
1018void nsIFrame::RemoveDisplayItemDataForDeletion() {
1019 // Destroying a WebRenderUserDataTable can cause destruction of other objects
1020 // which can remove frame properties in their destructor. If we delete a frame
1021 // property it runs the destructor of the stored object in the middle of
1022 // updating the frame property table, so if the destruction of that object
1023 // causes another update to the frame property table it would leave the frame
1024 // property table in an inconsistent state. So we remove it from the table and
1025 // then destroy it. (bug 1530657)
1026 WebRenderUserDataTable* userDataTable =
1027 TakeProperty(WebRenderUserDataProperty::Key());
1028 if (userDataTable) {
1029 for (const auto& data : userDataTable->Values()) {
1030 data->RemoveFromTable();
1031 }
1032 delete userDataTable;
1033 }
1034
1035 if (!nsLayoutUtils::AreRetainedDisplayListsEnabled()) {
1036 // Retained display lists are disabled, no need to update
1037 // RetainedDisplayListData.
1038 return;
1039 }
1040
1041 auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this);
1042 if (!builder) {
1043 MOZ_ASSERT(DisplayItems().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(DisplayItems().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(DisplayItems().IsEmpty()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("DisplayItems().IsEmpty()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "DisplayItems().IsEmpty()"
")"); do { *((volatile int*)__null) = 1043; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1044 MOZ_ASSERT(!IsFrameModified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFrameModified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsFrameModified()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!IsFrameModified()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFrameModified()"
")"); do { *((volatile int*)__null) = 1044; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1045 return;
1046 }
1047
1048 for (nsDisplayItem* i : DisplayItems()) {
1049 if (i->GetDependentFrame() == this && !i->HasDeletedFrame()) {
1050 i->Frame()->MarkNeedsDisplayItemRebuild();
1051 }
1052 i->RemoveFrame(this);
1053 }
1054
1055 DisplayItems().Clear();
1056
1057 nsAutoString name;
1058#ifdef DEBUG_FRAME_DUMP1
1059 if (DL_LOG_TEST(LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(GetLoggerByProcess
(), LogLevel::Debug)), 0))
) {
1060 GetFrameName(name);
1061 }
1062#endif
1063 DL_LOGV("Removing display item data for frame %p (%s)", this,do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Removing display item data for frame %p (%s)"
, this, NS_ConvertUTF16toUTF8(name).get()); } } while (0)
1064 NS_ConvertUTF16toUTF8(name).get())do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Removing display item data for frame %p (%s)"
, this, NS_ConvertUTF16toUTF8(name).get()); } } while (0)
;
1065
1066 auto* data = builder->Data();
1067 if (MayHaveWillChangeBudget()) {
1068 // Keep the frame in list, so it can be removed from the will-change budget.
1069 data->Flags(this) = RetainedDisplayListData::FrameFlag::HadWillChange;
1070 } else {
1071 data->Remove(this);
1072 }
1073}
1074
1075void nsIFrame::MarkNeedsDisplayItemRebuild() {
1076 if (!nsLayoutUtils::AreRetainedDisplayListsEnabled() || IsFrameModified() ||
1077 HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1078 // Skip frames that are already marked modified.
1079 return;
1080 }
1081
1082 if (Type() == LayoutFrameType::Placeholder) {
1083 nsIFrame* oof = static_cast<nsPlaceholderFrame*>(this)->GetOutOfFlowFrame();
1084 if (oof) {
1085 oof->MarkNeedsDisplayItemRebuild();
1086 }
1087 // Do not mark placeholder frames modified.
1088 return;
1089 }
1090
1091#ifdef ACCESSIBILITY1
1092 if (nsAccessibilityService* accService = GetAccService()) {
1093 accService->NotifyOfPossibleBoundsChange(PresShell(), mContent);
1094 }
1095#endif
1096
1097 nsIFrame* rootFrame = PresShell()->GetRootFrame();
1098
1099 if (rootFrame->IsFrameModified()) {
1100 // The whole frame tree is modified.
1101 return;
1102 }
1103
1104 auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this);
1105 if (!builder) {
1106 MOZ_ASSERT(DisplayItems().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(DisplayItems().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(DisplayItems().IsEmpty()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("DisplayItems().IsEmpty()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "DisplayItems().IsEmpty()"
")"); do { *((volatile int*)__null) = 1106; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1107 return;
1108 }
1109
1110 RetainedDisplayListData* data = builder->Data();
1111 MOZ_ASSERT(data)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(data)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(data))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("data", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "data" ")");
do { *((volatile int*)__null) = 1111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1112
1113 if (data->AtModifiedFrameLimit()) {
1114 // This marks the whole frame tree modified.
1115 // See |RetainedDisplayListBuilder::ShouldBuildPartial()|.
1116 data->AddModifiedFrame(rootFrame);
1117 return;
1118 }
1119
1120 nsAutoString name;
1121#ifdef DEBUG_FRAME_DUMP1
1122 if (DL_LOG_TEST(LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(GetLoggerByProcess
(), LogLevel::Debug)), 0))
) {
1123 GetFrameName(name);
1124 }
1125#endif
1126
1127 DL_LOGV("RDL - Rebuilding display items for frame %p (%s)", this,do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "RDL - Rebuilding display items for frame %p (%s)"
, this, NS_ConvertUTF16toUTF8(name).get()); } } while (0)
1128 NS_ConvertUTF16toUTF8(name).get())do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "RDL - Rebuilding display items for frame %p (%s)"
, this, NS_ConvertUTF16toUTF8(name).get()); } } while (0)
;
1129
1130 data->AddModifiedFrame(this);
1131
1132 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding) == 0"
")"); do { *((volatile int*)__null) = 1133; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1133 PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding
) == 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PresContext()->LayoutPhaseCount(nsLayoutPhase::DisplayListBuilding) == 0"
")"); do { *((volatile int*)__null) = 1133; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1134
1135 // Hopefully this is cheap, but we could use a frame state bit to note
1136 // the presence of dependencies to speed it up.
1137 for (nsDisplayItem* i : DisplayItems()) {
1138 if (i->HasDeletedFrame() || i->Frame() == this) {
1139 // Ignore the items with deleted frames, and the items with |this| as
1140 // the primary frame.
1141 continue;
1142 }
1143
1144 if (i->GetDependentFrame() == this) {
1145 // For items with |this| as a dependent frame, mark the primary frame
1146 // for rebuild.
1147 i->Frame()->MarkNeedsDisplayItemRebuild();
1148 }
1149 }
1150}
1151
1152// Subclass hook for style post processing
1153/* virtual */
1154void nsIFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
1155#ifdef ACCESSIBILITY1
1156 // Don't notify for reconstructed frames here, since the frame is still being
1157 // constructed at this point and so LocalAccessible::GetFrame() will return
1158 // null. Style changes for reconstructed frames are handled in
1159 // DocAccessible::PruneOrInsertSubtree.
1160 if (aOldComputedStyle) {
1161 if (nsAccessibilityService* accService = GetAccService()) {
1162 accService->NotifyOfComputedStyleChange(PresShell(), mContent);
1163 }
1164 }
1165#endif
1166
1167 MaybeScheduleReflowSVGNonDisplayText(this);
1168
1169 Document* doc = PresContext()->Document();
1170 ImageLoader* loader = doc->StyleImageLoader();
1171 // Continuing text frame doesn't initialize its continuation pointer before
1172 // reaching here for the first time, so we have to exclude text frames. This
1173 // doesn't affect correctness because text can't match selectors.
1174 //
1175 // FIXME(emilio): We should consider fixing that.
1176 //
1177 // TODO(emilio): Can we avoid doing some / all of the image stuff when
1178 // isNonTextFirstContinuation is false? We should consider doing this just for
1179 // primary frames and pseudos, but the first-line reparenting code makes it
1180 // all bad, should get around to bug 1465474 eventually :(
1181 const bool isNonText = !IsTextFrame();
1182 if (isNonText) {
1183 mComputedStyle->StartImageLoads(*doc, aOldComputedStyle);
1184 }
1185
1186 const nsStyleImageLayers* oldLayers =
1187 aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage
1188 : nullptr;
1189 const nsStyleImageLayers* newLayers = &StyleBackground()->mImage;
1190 AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
1191
1192 oldLayers =
1193 aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr;
1194 newLayers = &StyleSVGReset()->mMask;
1195 AddAndRemoveImageAssociations(*loader, this, oldLayers, newLayers);
1196
1197 const nsStyleDisplay* disp = StyleDisplay();
1198 bool handleStickyChange = false;
1199 if (aOldComputedStyle) {
1200 // Detect style changes that should trigger a scroll anchor adjustment
1201 // suppression.
1202 // https://drafts.csswg.org/css-scroll-anchoring/#suppression-triggers
1203 bool needAnchorSuppression = false;
1204
1205 const nsStyleMargin* oldMargin = aOldComputedStyle->StyleMargin();
1206 if (oldMargin->mMargin != StyleMargin()->mMargin) {
1207 needAnchorSuppression = true;
1208 }
1209
1210 const nsStylePadding* oldPadding = aOldComputedStyle->StylePadding();
1211 if (oldPadding->mPadding != StylePadding()->mPadding) {
1212 SetHasPaddingChange(true);
1213 needAnchorSuppression = true;
1214 }
1215
1216 const nsStyleDisplay* oldDisp = aOldComputedStyle->StyleDisplay();
1217 if (oldDisp->mOverflowAnchor != disp->mOverflowAnchor) {
1218 if (auto* container = ScrollAnchorContainer::FindFor(this)) {
1219 container->InvalidateAnchor();
1220 }
1221 if (nsIScrollableFrame* scrollableFrame = do_QueryFrame(this)) {
1222 scrollableFrame->Anchor()->InvalidateAnchor();
1223 }
1224 }
1225
1226 if (mInScrollAnchorChain) {
1227 const nsStylePosition* pos = StylePosition();
1228 const nsStylePosition* oldPos = aOldComputedStyle->StylePosition();
1229 if (!needAnchorSuppression &&
1230 (oldPos->mOffset != pos->mOffset || oldPos->mWidth != pos->mWidth ||
1231 oldPos->mMinWidth != pos->mMinWidth ||
1232 oldPos->mMaxWidth != pos->mMaxWidth ||
1233 oldPos->mHeight != pos->mHeight ||
1234 oldPos->mMinHeight != pos->mMinHeight ||
1235 oldPos->mMaxHeight != pos->mMaxHeight ||
1236 oldDisp->mPosition != disp->mPosition ||
1237 oldDisp->mTransform != disp->mTransform)) {
1238 needAnchorSuppression = true;
1239 }
1240
1241 if (needAnchorSuppression &&
1242 StaticPrefs::layout_css_scroll_anchoring_suppressions_enabled()) {
1243 ScrollAnchorContainer::FindFor(this)->SuppressAdjustments();
1244 }
1245 }
1246
1247 if (disp->mPosition != oldDisp->mPosition) {
1248 if (!disp->IsRelativelyOrStickyPositionedStyle() &&
1249 oldDisp->IsRelativelyOrStickyPositionedStyle()) {
1250 RemoveProperty(NormalPositionProperty());
1251 }
1252
1253 handleStickyChange = disp->mPosition == StylePositionProperty::Sticky ||
1254 oldDisp->mPosition == StylePositionProperty::Sticky;
1255 }
1256 if (disp->mScrollSnapAlign != oldDisp->mScrollSnapAlign) {
1257 ScrollSnapUtils::PostPendingResnapFor(this);
1258 }
1259 if (aOldComputedStyle->IsRootElementStyle() &&
1260 disp->mScrollSnapType != oldDisp->mScrollSnapType) {
1261 if (nsIScrollableFrame* scrollableFrame =
1262 PresShell()->GetRootScrollFrameAsScrollable()) {
1263 scrollableFrame->PostPendingResnap();
1264 }
1265 }
1266 if (StyleUIReset()->mMozSubtreeHiddenOnlyVisually &&
1267 !aOldComputedStyle->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
1268 PresShell::ClearMouseCapture(this);
1269 }
1270 } else { // !aOldComputedStyle
1271 handleStickyChange = disp->mPosition == StylePositionProperty::Sticky;
1272 }
1273
1274 if (handleStickyChange && !HasAnyStateBits(NS_FRAME_IS_NONDISPLAY) &&
1275 !GetPrevInFlow()) {
1276 // Note that we only add first continuations, but we really only
1277 // want to add first continuation-or-ib-split-siblings. But since we don't
1278 // yet know if we're a later part of a block-in-inline split, we'll just
1279 // add later members of a block-in-inline split here, and then
1280 // StickyScrollContainer will remove them later.
1281 if (auto* ssc =
1282 StickyScrollContainer::GetStickyScrollContainerForFrame(this)) {
1283 if (disp->mPosition == StylePositionProperty::Sticky) {
1284 ssc->AddFrame(this);
1285 } else {
1286 ssc->RemoveFrame(this);
1287 }
1288 }
1289 }
1290
1291 imgIRequest* oldBorderImage =
1292 aOldComputedStyle
1293 ? aOldComputedStyle->StyleBorder()->GetBorderImageRequest()
1294 : nullptr;
1295 imgIRequest* newBorderImage = StyleBorder()->GetBorderImageRequest();
1296 // FIXME (Bug 759996): The following is no longer true.
1297 // For border-images, we can't be as conservative (we need to set the
1298 // new loaders if there has been any change) since the CalcDifference
1299 // call depended on the result of GetComputedBorder() and that result
1300 // depends on whether the image has loaded, start the image load now
1301 // so that we'll get notified when it completes loading and can do a
1302 // restyle. Otherwise, the image might finish loading from the
1303 // network before we start listening to its notifications, and then
1304 // we'll never know that it's finished loading. Likewise, we want to
1305 // do this for freshly-created frames to prevent a similar race if the
1306 // image loads between reflow (which can depend on whether the image
1307 // is loaded) and paint. We also don't really care about any callers who try
1308 // to paint borders with a different style, because they won't have the
1309 // correct size for the border either.
1310 if (oldBorderImage != newBorderImage) {
1311 // stop and restart the image loading/notification
1312 if (oldBorderImage && HasImageRequest()) {
1313 loader->DisassociateRequestFromFrame(oldBorderImage, this);
1314 }
1315 if (newBorderImage) {
1316 loader->AssociateRequestToFrame(newBorderImage, this);
1317 }
1318 }
1319
1320 auto GetShapeImageRequest = [](const ComputedStyle* aStyle) -> imgIRequest* {
1321 if (!aStyle) {
1322 return nullptr;
1323 }
1324 auto& shape = aStyle->StyleDisplay()->mShapeOutside;
1325 if (!shape.IsImage()) {
1326 return nullptr;
1327 }
1328 return shape.AsImage().GetImageRequest();
1329 };
1330
1331 imgIRequest* oldShapeImage = GetShapeImageRequest(aOldComputedStyle);
1332 imgIRequest* newShapeImage = GetShapeImageRequest(Style());
1333 if (oldShapeImage != newShapeImage) {
1334 if (oldShapeImage && HasImageRequest()) {
1335 loader->DisassociateRequestFromFrame(oldShapeImage, this);
1336 }
1337 if (newShapeImage) {
1338 loader->AssociateRequestToFrame(
1339 newShapeImage, this,
1340 ImageLoader::Flags::
1341 RequiresReflowOnFirstFrameCompleteAndLoadEventBlocking);
1342 }
1343 }
1344
1345 // SVGObserverUtils::GetEffectProperties() asserts that we only invoke it with
1346 // the first continuation so we need to check that in advance.
1347 const bool isNonTextFirstContinuation = isNonText && !GetPrevContinuation();
1348 if (isNonTextFirstContinuation) {
1349 // Kick off loading of external SVG resources referenced from properties if
1350 // any. This currently includes filter, clip-path, and mask.
1351 SVGObserverUtils::InitiateResourceDocLoads(this);
1352 }
1353
1354 // If the page contains markup that overrides text direction, and
1355 // does not contain any characters that would activate the Unicode
1356 // bidi algorithm, we need to call |SetBidiEnabled| on the pres
1357 // context before reflow starts. See bug 115921.
1358 if (StyleVisibility()->mDirection == StyleDirection::Rtl) {
1359 PresContext()->SetBidiEnabled();
1360 }
1361
1362 // The following part is for caching offset-path:path(). We cache the
1363 // flatten gfx path, so we don't have to rebuild and re-flattern it at
1364 // each cycle if we have animations on offset-* with a fixed offset-path.
1365 const StyleOffsetPath* oldPath =
1366 aOldComputedStyle ? &aOldComputedStyle->StyleDisplay()->mOffsetPath
1367 : nullptr;
1368 const StyleOffsetPath& newPath = StyleDisplay()->mOffsetPath;
1369 if (!oldPath || *oldPath != newPath) {
1370 // FIXME: Bug 1837042. Cache all basic shapes.
1371 if (newPath.IsPath()) {
1372 RefPtr<gfx::PathBuilder> builder = MotionPathUtils::GetPathBuilder();
1373 RefPtr<gfx::Path> path =
1374 MotionPathUtils::BuildSVGPath(newPath.AsSVGPathData(), builder);
1375 if (path) {
1376 // The newPath could be path('') (i.e. empty path), so its gfx path
1377 // could be nullptr, and so we only set property for a non-empty path.
1378 SetProperty(nsIFrame::OffsetPathCache(), path.forget().take());
1379 } else {
1380 // May have an old cached path, so we have to delete it.
1381 RemoveProperty(nsIFrame::OffsetPathCache());
1382 }
1383 } else if (oldPath) {
1384 RemoveProperty(nsIFrame::OffsetPathCache());
1385 }
1386 }
1387
1388 if (IsPrimaryFrame()) {
1389 MOZ_ASSERT(aOldComputedStyle)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOldComputedStyle)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOldComputedStyle))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aOldComputedStyle"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOldComputedStyle"
")"); do { *((volatile int*)__null) = 1389; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1390 HandlePrimaryFrameStyleChange(aOldComputedStyle);
1391 }
1392
1393 RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS | NS_FRAME_SIMPLE_DISPLAYLIST);
1394
1395 mMayHaveRoundedCorners = true;
1396}
1397
1398void nsIFrame::HandleLastRememberedSize() {
1399 MOZ_ASSERT(IsPrimaryFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPrimaryFrame()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsPrimaryFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPrimaryFrame()"
")"); do { *((volatile int*)__null) = 1399; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1400 // Storing a last remembered size requires contain-intrinsic-size, and using
1401 // a previously stored last remembered size requires content-visibility.
1402 if (!StaticPrefs::layout_css_contain_intrinsic_size_enabled() ||
1403 !StaticPrefs::layout_css_content_visibility_enabled()) {
1404 return;
1405 }
1406 auto* element = Element::FromNodeOrNull(mContent);
1407 if (!element) {
1408 return;
1409 }
1410 const WritingMode wm = GetWritingMode();
1411 const nsStylePosition* stylePos = StylePosition();
1412 bool canRememberBSize = stylePos->ContainIntrinsicBSize(wm).HasAuto();
1413 bool canRememberISize = stylePos->ContainIntrinsicISize(wm).HasAuto();
1414 if (!canRememberBSize) {
1415 element->RemoveLastRememberedBSize();
1416 }
1417 if (!canRememberISize) {
1418 element->RemoveLastRememberedISize();
1419 }
1420 if ((canRememberBSize || canRememberISize) && !HidesContent()) {
1421 bool isNonReplacedInline = IsLineParticipant() && !IsReplaced();
1422 if (!isNonReplacedInline) {
1423 PresContext()->Document()->ObserveForLastRememberedSize(*element);
1424 return;
1425 }
1426 }
1427 PresContext()->Document()->UnobserveForLastRememberedSize(*element);
1428}
1429
1430#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
1431void nsIFrame::AssertNewStyleIsSane(ComputedStyle& aNewStyle) {
1432 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1433 aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 // ::first-line continuations are weird, this should probably be fixed viado { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1435 // bug 1465474.do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1436 (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1437 aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1438 // ::first-letter continuations are broken, in particular floating ones,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1439 // see bug 1490281. The construction code tries to fix this up after thedo { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1440 // fact, then restyling undoes it...do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1441 (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1442 aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1443 (mComputedStyle->GetPseudoType() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1444 PseudoStyleType::firstLetterContinuation &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1445 aNewStyle.GetPseudoType() == PseudoStyleType::mozText))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType
() || (mComputedStyle->GetPseudoType() == PseudoStyleType::
firstLine && aNewStyle.GetPseudoType() == PseudoStyleType
::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType
::mozText && aNewStyle.GetPseudoType() == PseudoStyleType
::firstLetterContinuation) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLetterContinuation && aNewStyle
.GetPseudoType() == PseudoStyleType::mozText))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewStyle.GetPseudoType() ==
mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType
() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType
() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType
() == PseudoStyleType::mozText && aNewStyle.GetPseudoType
() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle
->GetPseudoType() == PseudoStyleType::firstLetterContinuation
&& aNewStyle.GetPseudoType() == PseudoStyleType::mozText
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1445); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNewStyle.GetPseudoType() == mComputedStyle->GetPseudoType() || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLine && aNewStyle.GetPseudoType() == PseudoStyleType::mozLineFrame) || (mComputedStyle->GetPseudoType() == PseudoStyleType::mozText && aNewStyle.GetPseudoType() == PseudoStyleType::firstLetterContinuation) || (mComputedStyle->GetPseudoType() == PseudoStyleType::firstLetterContinuation && aNewStyle.GetPseudoType() == PseudoStyleType::mozText)"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1446}
1447#endif
1448
1449void nsIFrame::ReparentFrameViewTo(nsViewManager* aViewManager,
1450 nsView* aNewParentView) {
1451 if (HasView()) {
1452 if (IsMenuPopupFrame()) {
1453 // This view must be parented by the root view, don't reparent it.
1454 return;
1455 }
1456 nsView* view = GetView();
1457 aViewManager->RemoveChild(view);
1458
1459 // The view will remember the Z-order and other attributes that have been
1460 // set on it.
1461 nsView* insertBefore =
1462 nsLayoutUtils::FindSiblingViewFor(aNewParentView, this);
1463 aViewManager->InsertChild(aNewParentView, view, insertBefore,
1464 insertBefore != nullptr);
1465 } else if (HasAnyStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW)) {
1466 for (const auto& childList : ChildLists()) {
1467 // Iterate the child frames, and check each child frame to see if it has
1468 // a view
1469 for (nsIFrame* child : childList.mList) {
1470 child->ReparentFrameViewTo(aViewManager, aNewParentView);
1471 }
1472 }
1473 }
1474}
1475
1476void nsIFrame::SyncFrameViewProperties(nsView* aView) {
1477 if (!aView) {
1478 aView = GetView();
1479 if (!aView) {
1480 return;
1481 }
1482 }
1483
1484 nsViewManager* vm = aView->GetViewManager();
1485
1486 // Make sure visibility is correct. This only affects nsSubDocumentFrame.
1487 if (!SupportsVisibilityHidden()) {
1488 // See if the view should be hidden or visible
1489 ComputedStyle* sc = Style();
1490 vm->SetViewVisibility(aView, sc->StyleVisibility()->IsVisible()
1491 ? ViewVisibility::Show
1492 : ViewVisibility::Hide);
1493 }
1494
1495 const auto zIndex = ZIndex();
1496 const bool autoZIndex = !zIndex;
1497 vm->SetViewZIndex(aView, autoZIndex, zIndex.valueOr(0));
1498}
1499
1500void nsIFrame::CreateView() {
1501 MOZ_ASSERT(!HasView())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasView())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!HasView()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!HasView()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1501); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasView()"
")"); do { *((volatile int*)__null) = 1501; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1502
1503 nsView* parentView = GetParent()->GetClosestView();
1504 MOZ_ASSERT(parentView, "no parent with view")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(parentView)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(parentView))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("parentView" " (" "no parent with view"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parentView"
") (" "no parent with view" ")"); do { *((volatile int*)__null
) = 1504; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1505
1506 nsViewManager* viewManager = parentView->GetViewManager();
1507 MOZ_ASSERT(viewManager, "null view manager")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(viewManager)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(viewManager))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("viewManager" " ("
"null view manager" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "viewManager"
") (" "null view manager" ")"); do { *((volatile int*)__null
) = 1507; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1508
1509 nsView* view = viewManager->CreateView(GetRect(), parentView);
1510 SyncFrameViewProperties(view);
1511
1512 nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, this);
1513 // we insert this view 'above' the insertBefore view, unless insertBefore is
1514 // null, in which case we want to call with aAbove == false to insert at the
1515 // beginning in document order
1516 viewManager->InsertChild(parentView, view, insertBefore,
1517 insertBefore != nullptr);
1518
1519 // REVIEW: Don't create a widget for fixed-pos elements anymore.
1520 // ComputeRepaintRegionForCopy will calculate the right area to repaint
1521 // when we scroll.
1522 // Reparent views on any child frames (or their descendants) to this
1523 // view. We can just call ReparentFrameViewTo on this frame because
1524 // we know this frame has no view, so it will crawl the children. Also,
1525 // we know that any descendants with views must have 'parentView' as their
1526 // parent view.
1527 ReparentFrameViewTo(viewManager, view);
1528
1529 // Remember our view
1530 SetView(view);
1531
1532 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsIFrame::CreateView: frame=%p view=%p"
, this, view); } } while (0)
1533 ("nsIFrame::CreateView: frame=%p view=%p", this, view))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { printf_stderr ("nsIFrame::CreateView: frame=%p view=%p"
, this, view); } } while (0)
;
1534}
1535
1536/* virtual */
1537nsMargin nsIFrame::GetUsedMargin() const {
1538 nsMargin margin;
1539 if (((mState & NS_FRAME_FIRST_REFLOW) && !(mState & NS_FRAME_IN_REFLOW)) ||
1540 IsInSVGTextSubtree()) {
1541 return margin;
1542 }
1543
1544 if (nsMargin* m = GetProperty(UsedMarginProperty())) {
1545 margin = *m;
1546 } else if (!StyleMargin()->GetMargin(margin)) {
1547 // If we get here, our caller probably shouldn't be calling us...
1548 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized margin, because this margin "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1550); MOZ_PretendNoReturn(); } while (0)
1549 "Returning bogus 0-sized margin, because this margin "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized margin, because this margin "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1550); MOZ_PretendNoReturn(); } while (0)
1550 "depends on layout & isn't cached!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized margin, because this margin "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1550); MOZ_PretendNoReturn(); } while (0)
;
1551 }
1552 return margin;
1553}
1554
1555/* virtual */
1556nsMargin nsIFrame::GetUsedBorder() const {
1557 if (((mState & NS_FRAME_FIRST_REFLOW) && !(mState & NS_FRAME_IN_REFLOW)) ||
1558 IsInSVGTextSubtree()) {
1559 return {};
1560 }
1561
1562 const nsStyleDisplay* disp = StyleDisplay();
1563 if (IsThemed(disp)) {
1564 // Theme methods don't use const-ness.
1565 auto* mutable_this = const_cast<nsIFrame*>(this);
1566 nsPresContext* pc = PresContext();
1567 LayoutDeviceIntMargin widgetBorder = pc->Theme()->GetWidgetBorder(
1568 pc->DeviceContext(), mutable_this, disp->EffectiveAppearance());
1569 return LayoutDevicePixel::ToAppUnits(widgetBorder,
1570 pc->AppUnitsPerDevPixel());
1571 }
1572
1573 return StyleBorder()->GetComputedBorder();
1574}
1575
1576/* virtual */
1577nsMargin nsIFrame::GetUsedPadding() const {
1578 nsMargin padding;
1579 if (((mState & NS_FRAME_FIRST_REFLOW) && !(mState & NS_FRAME_IN_REFLOW)) ||
1580 IsInSVGTextSubtree()) {
1581 return padding;
1582 }
1583
1584 const nsStyleDisplay* disp = StyleDisplay();
1585 if (IsThemed(disp)) {
1586 // Theme methods don't use const-ness.
1587 nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1588 nsPresContext* pc = PresContext();
1589 LayoutDeviceIntMargin widgetPadding;
1590 if (pc->Theme()->GetWidgetPadding(pc->DeviceContext(), mutable_this,
1591 disp->EffectiveAppearance(),
1592 &widgetPadding)) {
1593 return LayoutDevicePixel::ToAppUnits(widgetPadding,
1594 pc->AppUnitsPerDevPixel());
1595 }
1596 }
1597
1598 if (nsMargin* p = GetProperty(UsedPaddingProperty())) {
1599 padding = *p;
1600 } else if (!StylePadding()->GetPadding(padding)) {
1601 // If we get here, our caller probably shouldn't be calling us...
1602 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized padding, because this padding "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1604); MOZ_PretendNoReturn(); } while (0)
1603 "Returning bogus 0-sized padding, because this padding "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized padding, because this padding "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1604); MOZ_PretendNoReturn(); } while (0)
1604 "depends on layout & isn't cached!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Returning bogus 0-sized padding, because this padding "
"depends on layout & isn't cached!", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1604); MOZ_PretendNoReturn(); } while (0)
;
1605 }
1606 return padding;
1607}
1608
1609nsIFrame::Sides nsIFrame::GetSkipSides() const {
1610 if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Clone), 0))
1611 StyleBoxDecorationBreak::Clone)(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Clone), 0))
&&
1612 !HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1613 return Sides();
1614 }
1615
1616 // Convert the logical skip sides to physical sides using the frame's
1617 // writing mode
1618 WritingMode writingMode = GetWritingMode();
1619 LogicalSides logicalSkip = GetLogicalSkipSides();
1620 Sides skip;
1621
1622 if (logicalSkip.BStart()) {
1623 if (writingMode.IsVertical()) {
1624 skip |= writingMode.IsVerticalLR() ? SideBits::eLeft : SideBits::eRight;
1625 } else {
1626 skip |= SideBits::eTop;
1627 }
1628 }
1629
1630 if (logicalSkip.BEnd()) {
1631 if (writingMode.IsVertical()) {
1632 skip |= writingMode.IsVerticalLR() ? SideBits::eRight : SideBits::eLeft;
1633 } else {
1634 skip |= SideBits::eBottom;
1635 }
1636 }
1637
1638 if (logicalSkip.IStart()) {
1639 if (writingMode.IsVertical()) {
1640 skip |= SideBits::eTop;
1641 } else {
1642 skip |= writingMode.IsBidiLTR() ? SideBits::eLeft : SideBits::eRight;
1643 }
1644 }
1645
1646 if (logicalSkip.IEnd()) {
1647 if (writingMode.IsVertical()) {
1648 skip |= SideBits::eBottom;
1649 } else {
1650 skip |= writingMode.IsBidiLTR() ? SideBits::eRight : SideBits::eLeft;
1651 }
1652 }
1653 return skip;
1654}
1655
1656nsRect nsIFrame::GetPaddingRectRelativeToSelf() const {
1657 nsMargin border = GetUsedBorder().ApplySkipSides(GetSkipSides());
1658 nsRect r(0, 0, mRect.width, mRect.height);
1659 r.Deflate(border);
1660 return r;
1661}
1662
1663nsRect nsIFrame::GetPaddingRect() const {
1664 return GetPaddingRectRelativeToSelf() + GetPosition();
1665}
1666
1667WritingMode nsIFrame::WritingModeForLine(WritingMode aSelfWM,
1668 nsIFrame* aSubFrame) const {
1669 MOZ_ASSERT(aSelfWM == GetWritingMode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSelfWM == GetWritingMode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSelfWM == GetWritingMode())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aSelfWM == GetWritingMode()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSelfWM == GetWritingMode()"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1670 WritingMode writingMode = aSelfWM;
1671
1672 if (StyleTextReset()->mUnicodeBidi == StyleUnicodeBidi::Plaintext) {
1673 mozilla::intl::BidiEmbeddingLevel frameLevel =
1674 nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
1675 writingMode.SetDirectionFromBidiLevel(frameLevel);
1676 }
1677
1678 return writingMode;
1679}
1680
1681nsRect nsIFrame::GetMarginRect() const {
1682 return GetMarginRectRelativeToSelf() + GetPosition();
1683}
1684
1685nsRect nsIFrame::GetMarginRectRelativeToSelf() const {
1686 nsMargin m = GetUsedMargin().ApplySkipSides(GetSkipSides());
1687 nsRect r(0, 0, mRect.width, mRect.height);
1688 r.Inflate(m);
1689 return r;
1690}
1691
1692bool nsIFrame::IsTransformed() const {
1693 if (!HasAnyStateBits(NS_FRAME_MAY_BE_TRANSFORMED)) {
1694 MOZ_ASSERT(!IsCSSTransformed())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsCSSTransformed())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsCSSTransformed()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!IsCSSTransformed()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCSSTransformed()"
")"); do { *((volatile int*)__null) = 1694; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1695 MOZ_ASSERT(!IsSVGTransformed())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsSVGTransformed())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsSVGTransformed()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!IsSVGTransformed()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1695); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsSVGTransformed()"
")"); do { *((volatile int*)__null) = 1695; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1696 return false;
1697 }
1698 return IsCSSTransformed() || IsSVGTransformed();
1699}
1700
1701bool nsIFrame::IsCSSTransformed() const {
1702 return HasAnyStateBits(NS_FRAME_MAY_BE_TRANSFORMED) &&
1703 (StyleDisplay()->HasTransform(this) || HasAnimationOfTransform());
1704}
1705
1706bool nsIFrame::HasAnimationOfTransform() const {
1707 return IsPrimaryFrame() &&
1708 nsLayoutUtils::HasAnimationOfTransformAndMotionPath(this) &&
1709 SupportsCSSTransforms();
1710}
1711
1712bool nsIFrame::ChildrenHavePerspective(
1713 const nsStyleDisplay* aStyleDisplay) const {
1714 MOZ_ASSERT(aStyleDisplay == StyleDisplay())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStyleDisplay == StyleDisplay())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStyleDisplay == StyleDisplay
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aStyleDisplay == StyleDisplay()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStyleDisplay == StyleDisplay()"
")"); do { *((volatile int*)__null) = 1714; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1715 return aStyleDisplay->HasPerspective(this);
1716}
1717
1718bool nsIFrame::HasAnimationOfOpacity(EffectSet* aEffectSet) const {
1719 return ((nsLayoutUtils::IsPrimaryStyleFrame(this) ||
1720 nsLayoutUtils::FirstContinuationOrIBSplitSibling(this)
1721 ->IsPrimaryFrame()) &&
1722 nsLayoutUtils::HasAnimationOfPropertySet(
1723 this, nsCSSPropertyIDSet::OpacityProperties(), aEffectSet));
1724}
1725
1726bool nsIFrame::HasOpacityInternal(float aThreshold,
1727 const nsStyleDisplay* aStyleDisplay,
1728 const nsStyleEffects* aStyleEffects,
1729 EffectSet* aEffectSet) const {
1730 MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(0.0 <= aThreshold && aThreshold <= 1.0
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(0.0 <= aThreshold && aThreshold <= 1.0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"0.0 <= aThreshold && aThreshold <= 1.0" " (" "Invalid argument"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 1730); AnnotateMozCrashReason("MOZ_ASSERT" "(" "0.0 <= aThreshold && aThreshold <= 1.0"
") (" "Invalid argument" ")"); do { *((volatile int*)__null)
= 1730; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1731 if (aStyleEffects->mOpacity < aThreshold ||
1732 aStyleDisplay->mWillChange.bits & StyleWillChangeBits::OPACITY) {
1733 return true;
1734 }
1735
1736 if (!mMayHaveOpacityAnimation) {
1737 return false;
1738 }
1739
1740 return HasAnimationOfOpacity(aEffectSet);
1741}
1742
1743bool nsIFrame::IsSVGTransformed(gfx::Matrix* aOwnTransforms,
1744 gfx::Matrix* aFromParentTransforms) const {
1745 return false;
1746}
1747
1748bool nsIFrame::Extend3DContext(const nsStyleDisplay* aStyleDisplay,
1749 const nsStyleEffects* aStyleEffects,
1750 mozilla::EffectSet* aEffectSetForOpacity) const {
1751 if (!HasAnyStateBits(NS_FRAME_MAY_BE_TRANSFORMED)) {
1752 return false;
1753 }
1754 const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
1755 if (disp->mTransformStyle != StyleTransformStyle::Preserve3d ||
1756 !SupportsCSSTransforms()) {
1757 return false;
1758 }
1759
1760 // If we're all scroll frame, then all descendants will be clipped, so we
1761 // can't preserve 3d.
1762 if (IsScrollFrame()) {
1763 return false;
1764 }
1765
1766 const nsStyleEffects* effects = StyleEffectsWithOptionalParam(aStyleEffects);
1767 if (HasOpacity(disp, effects, aEffectSetForOpacity)) {
1768 return false;
1769 }
1770
1771 return ShouldApplyOverflowClipping(disp) == PhysicalAxes::None &&
1772 !GetClipPropClipRect(disp, effects, GetSize()) &&
1773 !SVGIntegrationUtils::UsingEffectsForFrame(this) &&
1774 !effects->HasMixBlendMode() &&
1775 disp->mIsolation != StyleIsolation::Isolate;
1776}
1777
1778bool nsIFrame::Combines3DTransformWithAncestors() const {
1779 // Check these first as they are faster then both calls below and are we are
1780 // likely to hit the early return (backface hidden is uncommon and
1781 // GetReferenceFrame is a hot caller of this which only calls this if
1782 // IsCSSTransformed is false).
1783 if (!IsCSSTransformed() && !BackfaceIsHidden()) {
1784 return false;
1785 }
1786 nsIFrame* parent = GetClosestFlattenedTreeAncestorPrimaryFrame();
1787 return parent && parent->Extend3DContext();
1788}
1789
1790bool nsIFrame::In3DContextAndBackfaceIsHidden() const {
1791 // While both tests fail most of the time, test BackfaceIsHidden()
1792 // first since it's likely to fail faster.
1793 return BackfaceIsHidden() && Combines3DTransformWithAncestors();
1794}
1795
1796bool nsIFrame::HasPerspective() const {
1797 if (!IsCSSTransformed()) {
1798 return false;
1799 }
1800 nsIFrame* parent = GetClosestFlattenedTreeAncestorPrimaryFrame();
1801 if (!parent) {
1802 return false;
1803 }
1804 return parent->ChildrenHavePerspective();
1805}
1806
1807nsRect nsIFrame::GetContentRectRelativeToSelf() const {
1808 nsMargin bp = GetUsedBorderAndPadding().ApplySkipSides(GetSkipSides());
1809 nsRect r(0, 0, mRect.width, mRect.height);
1810 r.Deflate(bp);
1811 return r;
1812}
1813
1814nsRect nsIFrame::GetContentRect() const {
1815 return GetContentRectRelativeToSelf() + GetPosition();
1816}
1817
1818bool nsIFrame::ComputeBorderRadii(const BorderRadius& aBorderRadius,
1819 const nsSize& aFrameSize,
1820 const nsSize& aBorderArea, Sides aSkipSides,
1821 nscoord aRadii[8]) {
1822 // Percentages are relative to whichever side they're on.
1823 for (const auto i : mozilla::AllPhysicalHalfCorners()) {
1824 const LengthPercentage& c = aBorderRadius.Get(i);
1825 nscoord axis = HalfCornerIsX(i) ? aFrameSize.width : aFrameSize.height;
1826 aRadii[i] = std::max(0, c.Resolve(axis));
1827 }
1828
1829 if (aSkipSides.Top()) {
1830 aRadii[eCornerTopLeftX] = 0;
1831 aRadii[eCornerTopLeftY] = 0;
1832 aRadii[eCornerTopRightX] = 0;
1833 aRadii[eCornerTopRightY] = 0;
1834 }
1835
1836 if (aSkipSides.Right()) {
1837 aRadii[eCornerTopRightX] = 0;
1838 aRadii[eCornerTopRightY] = 0;
1839 aRadii[eCornerBottomRightX] = 0;
1840 aRadii[eCornerBottomRightY] = 0;
1841 }
1842
1843 if (aSkipSides.Bottom()) {
1844 aRadii[eCornerBottomRightX] = 0;
1845 aRadii[eCornerBottomRightY] = 0;
1846 aRadii[eCornerBottomLeftX] = 0;
1847 aRadii[eCornerBottomLeftY] = 0;
1848 }
1849
1850 if (aSkipSides.Left()) {
1851 aRadii[eCornerBottomLeftX] = 0;
1852 aRadii[eCornerBottomLeftY] = 0;
1853 aRadii[eCornerTopLeftX] = 0;
1854 aRadii[eCornerTopLeftY] = 0;
1855 }
1856
1857 // css3-background specifies this algorithm for reducing
1858 // corner radii when they are too big.
1859 bool haveRadius = false;
1860 double ratio = 1.0f;
1861 for (const auto side : mozilla::AllPhysicalSides()) {
1862 uint32_t hc1 = SideToHalfCorner(side, false, true);
1863 uint32_t hc2 = SideToHalfCorner(side, true, true);
1864 nscoord length =
1865 SideIsVertical(side) ? aBorderArea.height : aBorderArea.width;
1866 nscoord sum = aRadii[hc1] + aRadii[hc2];
1867 if (sum) {
1868 haveRadius = true;
1869 // avoid floating point division in the normal case
1870 if (length < sum) {
1871 ratio = std::min(ratio, double(length) / sum);
1872 }
1873 }
1874 }
1875 if (ratio < 1.0) {
1876 for (const auto corner : mozilla::AllPhysicalHalfCorners()) {
1877 aRadii[corner] *= ratio;
1878 }
1879 }
1880
1881 return haveRadius;
1882}
1883
1884void nsIFrame::AdjustBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets) {
1885 auto AdjustOffset = [](const uint32_t aRadius, const nscoord aOffset) {
1886 // Implement the cubic formula to adjust offset when aOffset > 0 and
1887 // aRadius / aOffset < 1.
1888 // https://drafts.csswg.org/css-shapes/#valdef-shape-box-margin-box
1889 if (aOffset > 0) {
1890 const double ratio = aRadius / double(aOffset);
1891 if (ratio < 1.0) {
1892 return nscoord(aOffset * (1.0 + std::pow(ratio - 1, 3)));
1893 }
1894 }
1895 return aOffset;
1896 };
1897
1898 for (const auto side : mozilla::AllPhysicalSides()) {
1899 const nscoord offset = aOffsets.Side(side);
1900 const uint32_t hc1 = SideToHalfCorner(side, false, false);
1901 const uint32_t hc2 = SideToHalfCorner(side, true, false);
1902 if (aRadii[hc1] > 0) {
1903 const nscoord offset1 = AdjustOffset(aRadii[hc1], offset);
1904 aRadii[hc1] = std::max(0, aRadii[hc1] + offset1);
1905 }
1906 if (aRadii[hc2] > 0) {
1907 const nscoord offset2 = AdjustOffset(aRadii[hc2], offset);
1908 aRadii[hc2] = std::max(0, aRadii[hc2] + offset2);
1909 }
1910 }
1911}
1912
1913static inline bool RadiiAreDefinitelyZero(const BorderRadius& aBorderRadius) {
1914 for (const auto corner : mozilla::AllPhysicalHalfCorners()) {
1915 if (!aBorderRadius.Get(corner).IsDefinitelyZero()) {
1916 return false;
1917 }
1918 }
1919 return true;
1920}
1921
1922/* virtual */
1923bool nsIFrame::GetBorderRadii(const nsSize& aFrameSize,
1924 const nsSize& aBorderArea, Sides aSkipSides,
1925 nscoord aRadii[8]) const {
1926 if (!mMayHaveRoundedCorners) {
1927 memset(aRadii, 0, sizeof(nscoord) * 8);
1928 return false;
1929 }
1930
1931 if (IsThemed()) {
1932 // When we're themed, the native theme code draws the border and
1933 // background, and therefore it doesn't make sense to tell other
1934 // code that's interested in border-radius that we have any radii.
1935 //
1936 // In an ideal world, we might have a way for the them to tell us an
1937 // border radius, but since we don't, we're better off assuming
1938 // zero.
1939 for (const auto corner : mozilla::AllPhysicalHalfCorners()) {
1940 aRadii[corner] = 0;
1941 }
1942 return false;
1943 }
1944
1945 const auto& radii = StyleBorder()->mBorderRadius;
1946 const bool hasRadii =
1947 ComputeBorderRadii(radii, aFrameSize, aBorderArea, aSkipSides, aRadii);
1948 if (!hasRadii) {
1949 // TODO(emilio): Maybe we can just remove this bit and do the
1950 // IsDefinitelyZero check unconditionally. That should still avoid most of
1951 // the work, though maybe not the cache miss of going through the style and
1952 // the border struct.
1953 const_cast<nsIFrame*>(this)->mMayHaveRoundedCorners =
1954 !RadiiAreDefinitelyZero(radii);
1955 }
1956 return hasRadii;
1957}
1958
1959bool nsIFrame::GetBorderRadii(nscoord aRadii[8]) const {
1960 nsSize sz = GetSize();
1961 return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
1962}
1963
1964bool nsIFrame::GetMarginBoxBorderRadii(nscoord aRadii[8]) const {
1965 return GetBoxBorderRadii(aRadii, GetUsedMargin());
1966}
1967
1968bool nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const {
1969 return GetBoxBorderRadii(aRadii, -GetUsedBorder());
1970}
1971
1972bool nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const {
1973 return GetBoxBorderRadii(aRadii, -GetUsedBorderAndPadding());
1974}
1975
1976bool nsIFrame::GetBoxBorderRadii(nscoord aRadii[8],
1977 const nsMargin& aOffsets) const {
1978 if (!GetBorderRadii(aRadii)) {
1979 return false;
1980 }
1981 AdjustBorderRadii(aRadii, aOffsets);
1982 for (const auto corner : mozilla::AllPhysicalHalfCorners()) {
1983 if (aRadii[corner]) {
1984 return true;
1985 }
1986 }
1987 return false;
1988}
1989
1990bool nsIFrame::GetShapeBoxBorderRadii(nscoord aRadii[8]) const {
1991 using Tag = StyleShapeOutside::Tag;
1992 auto& shapeOutside = StyleDisplay()->mShapeOutside;
1993 auto box = StyleShapeBox::MarginBox;
1994 switch (shapeOutside.tag) {
1995 case Tag::Image:
1996 case Tag::None:
1997 return false;
1998 case Tag::Box:
1999 box = shapeOutside.AsBox();
2000 break;
2001 case Tag::Shape:
2002 box = shapeOutside.AsShape()._1;
2003 break;
2004 }
2005
2006 switch (box) {
2007 case StyleShapeBox::ContentBox:
2008 return GetContentBoxBorderRadii(aRadii);
2009 case StyleShapeBox::PaddingBox:
2010 return GetPaddingBoxBorderRadii(aRadii);
2011 case StyleShapeBox::BorderBox:
2012 return GetBorderRadii(aRadii);
2013 case StyleShapeBox::MarginBox:
2014 return GetMarginBoxBorderRadii(aRadii);
2015 default:
2016 MOZ_ASSERT_UNREACHABLE("Unexpected box 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: "
"Unexpected box value" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2016); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected box value" ")"); do {
*((volatile int*)__null) = 2016; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2017 return false;
2018 }
2019}
2020
2021nscoord nsIFrame::OneEmInAppUnits() const {
2022 return StyleFont()
2023 ->mFont.size.ScaledBy(nsLayoutUtils::FontSizeInflationFor(this))
2024 .ToAppUnits();
2025}
2026
2027ComputedStyle* nsIFrame::GetAdditionalComputedStyle(int32_t aIndex) const {
2028 MOZ_ASSERT(aIndex >= 0, "invalid index number")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIndex >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aIndex >= 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aIndex >= 0"
" (" "invalid index number" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2028); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIndex >= 0"
") (" "invalid index number" ")"); do { *((volatile int*)__null
) = 2028; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2029 return nullptr;
2030}
2031
2032void nsIFrame::SetAdditionalComputedStyle(int32_t aIndex,
2033 ComputedStyle* aComputedStyle) {
2034 MOZ_ASSERT(aIndex >= 0, "invalid index number")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIndex >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aIndex >= 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aIndex >= 0"
" (" "invalid index number" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIndex >= 0"
") (" "invalid index number" ")"); do { *((volatile int*)__null
) = 2034; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2035}
2036
2037nscoord nsIFrame::SynthesizeFallbackBaseline(
2038 WritingMode aWM, BaselineSharingGroup aBaselineGroup) const {
2039 const auto margin = GetLogicalUsedMargin(aWM);
2040 NS_ASSERTION(!IsSubtreeDirty(), "frame must not be dirty")do { if (!(!IsSubtreeDirty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "frame must not be dirty", "!IsSubtreeDirty()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2040); MOZ_PretendNoReturn(); } } while (0)
;
2041 if (aWM.IsCentralBaseline()) {
2042 return (BSize(aWM) + GetLogicalUsedMargin(aWM).BEnd(aWM)) / 2;
2043 }
2044 // Baseline for inverted line content is the top (block-start) margin edge,
2045 // as the frame is in effect "flipped" for alignment purposes.
2046 if (aWM.IsLineInverted()) {
2047 const auto marginStart = margin.BStart(aWM);
2048 return aBaselineGroup == BaselineSharingGroup::First
2049 ? -marginStart
2050 : BSize(aWM) + marginStart;
2051 }
2052 // Otherwise, the bottom margin edge, per CSS2.1's definition of the
2053 // 'baseline' value of 'vertical-align'.
2054 const auto marginEnd = margin.BEnd(aWM);
2055 return aBaselineGroup == BaselineSharingGroup::First ? BSize(aWM) + marginEnd
2056 : -marginEnd;
2057}
2058
2059nscoord nsIFrame::GetLogicalBaseline(WritingMode aWM) const {
2060 return GetLogicalBaseline(aWM, GetDefaultBaselineSharingGroup(),
2061 BaselineExportContext::LineLayout);
2062}
2063
2064nscoord nsIFrame::GetLogicalBaseline(
2065 WritingMode aWM, BaselineSharingGroup aBaselineGroup,
2066 BaselineExportContext aExportContext) const {
2067 const auto result =
2068 GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext)
2069 .valueOrFrom([this, aWM, aBaselineGroup]() {
2070 return SynthesizeFallbackBaseline(aWM, aBaselineGroup);
2071 });
2072 if (aBaselineGroup == BaselineSharingGroup::Last) {
2073 return BSize(aWM) - result;
2074 }
2075 return result;
2076}
2077
2078const nsFrameList& nsIFrame::GetChildList(ChildListID aListID) const {
2079 if (IsAbsoluteContainer() && aListID == GetAbsoluteListID()) {
2080 return GetAbsoluteContainingBlock()->GetChildList();
2081 } else {
2082 return nsFrameList::EmptyList();
2083 }
2084}
2085
2086void nsIFrame::GetChildLists(nsTArray<ChildList>* aLists) const {
2087 if (IsAbsoluteContainer()) {
2088 const nsFrameList& absoluteList =
2089 GetAbsoluteContainingBlock()->GetChildList();
2090 absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
2091 }
2092}
2093
2094AutoTArray<nsIFrame::ChildList, 4> nsIFrame::CrossDocChildLists() {
2095 AutoTArray<ChildList, 4> childLists;
2096 nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
2097 if (subdocumentFrame) {
2098 // Descend into the subdocument
2099 nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
2100 if (root) {
2101 childLists.EmplaceBack(
2102 nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
2103 FrameChildListID::Principal);
2104 }
2105 }
2106
2107 GetChildLists(&childLists);
2108 return childLists;
2109}
2110
2111nsIFrame::CaretBlockAxisMetrics nsIFrame::GetCaretBlockAxisMetrics(
2112 mozilla::WritingMode aWM, const nsFontMetrics& aFM) const {
2113 // Note(dshin): Ultimately, this does something highly similar (But still
2114 // different) to `nsLayoutUtils::GetFirstLinePosition`.
2115 const auto baseline = GetCaretBaseline();
2116 nscoord ascent = 0, descent = 0;
2117 ascent = aFM.MaxAscent();
2118 descent = aFM.MaxDescent();
2119 const nscoord height = ascent + descent;
2120 if (aWM.IsVertical() && aWM.IsLineInverted()) {
2121 return CaretBlockAxisMetrics{.mOffset = baseline - descent,
2122 .mExtent = height};
2123 }
2124 return CaretBlockAxisMetrics{.mOffset = baseline - ascent, .mExtent = height};
2125}
2126
2127const nsAtom* nsIFrame::ComputePageValue(const nsAtom* aAutoValue) const {
2128 const nsAtom* value = aAutoValue ? aAutoValue : nsGkAtoms::_empty;
2129 const nsIFrame* frame = this;
2130 // Find what CSS page name value this frame's subtree has, if any.
2131 // Starting with this frame, check if a page name other than auto is present,
2132 // and record it if so. Then, if the current frame is a container frame, find
2133 // the first non-placeholder child and repeat.
2134 // This will find the most deeply nested first in-flow child of this frame's
2135 // subtree, and return its page name (with auto resolved if applicable, and
2136 // subtrees with no page-names returning the empty atom rather than null).
2137 do {
2138 if (const nsAtom* maybePageName = frame->GetStylePageName()) {
2139 value = maybePageName;
2140 }
2141 // Get the next frame to read from.
2142 const nsIFrame* firstNonPlaceholderFrame = nullptr;
2143 // If this is a container frame, inspect its in-flow children.
2144 if (const nsContainerFrame* containerFrame = do_QueryFrame(frame)) {
2145 for (const nsIFrame* childFrame : containerFrame->PrincipalChildList()) {
2146 if (!childFrame->IsPlaceholderFrame()) {
2147 firstNonPlaceholderFrame = childFrame;
2148 break;
2149 }
2150 }
2151 }
2152 frame = firstNonPlaceholderFrame;
2153 } while (frame);
2154 return value;
2155}
2156
2157Visibility nsIFrame::GetVisibility() const {
2158 if (!HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)) {
2159 return Visibility::Untracked;
2160 }
2161
2162 bool isSet = false;
2163 uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
2164
2165 MOZ_ASSERT(isSet,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2167; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2166 "Should have a VisibilityStateProperty value "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2167; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2167 "if NS_FRAME_VISIBILITY_IS_TRACKED is set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2167; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2168
2169 return visibleCount > 0 ? Visibility::ApproximatelyVisible
2170 : Visibility::ApproximatelyNonVisible;
2171}
2172
2173void nsIFrame::UpdateVisibilitySynchronously() {
2174 mozilla::PresShell* presShell = PresShell();
2175 if (!presShell) {
2176 return;
2177 }
2178
2179 if (presShell->AssumeAllFramesVisible()) {
2180 presShell->EnsureFrameInApproximatelyVisibleList(this);
2181 return;
2182 }
2183
2184 bool visible = StyleVisibility()->IsVisible();
2185 nsIFrame* f = GetParent();
2186 nsRect rect = GetRectRelativeToSelf();
2187 nsIFrame* rectFrame = this;
2188 while (f && visible) {
2189 nsIScrollableFrame* sf = do_QueryFrame(f);
2190 if (sf) {
2191 nsRect transformedRect =
2192 nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
2193 if (!sf->IsRectNearlyVisible(transformedRect)) {
2194 visible = false;
2195 break;
2196 }
2197
2198 // In this code we're trying to synchronously update *approximate*
2199 // visibility. (In the future we may update precise visibility here as
2200 // well, which is why the method name does not contain 'approximate'.) The
2201 // IsRectNearlyVisible() check above tells us that the rect we're checking
2202 // is approximately visible within the scrollframe, but we still need to
2203 // ensure that, even if it was scrolled into view, it'd be visible when we
2204 // consider the rest of the document. To do that, we move transformedRect
2205 // to be contained in the scrollport as best we can (it might not fit) to
2206 // pretend that it was scrolled into view.
2207 rect = transformedRect.MoveInsideAndClamp(sf->GetScrollPortRect());
2208 rectFrame = f;
2209 }
2210 nsIFrame* parent = f->GetParent();
2211 if (!parent) {
2212 parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(f);
2213 if (parent && parent->PresContext()->IsChrome()) {
2214 break;
2215 }
2216 }
2217 f = parent;
2218 }
2219
2220 if (visible) {
2221 presShell->EnsureFrameInApproximatelyVisibleList(this);
2222 } else {
2223 presShell->RemoveFrameFromApproximatelyVisibleList(this);
2224 }
2225}
2226
2227void nsIFrame::EnableVisibilityTracking() {
2228 if (HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)) {
2229 return; // Nothing to do.
2230 }
2231
2232 MOZ_ASSERT(!HasProperty(VisibilityStateProperty()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasProperty(VisibilityStateProperty()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!HasProperty(VisibilityStateProperty())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!HasProperty(VisibilityStateProperty())"
" (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasProperty(VisibilityStateProperty())"
") (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")"); do { *((volatile int*)__null) = 2234; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2233 "Shouldn't have a VisibilityStateProperty value "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasProperty(VisibilityStateProperty()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!HasProperty(VisibilityStateProperty())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!HasProperty(VisibilityStateProperty())"
" (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasProperty(VisibilityStateProperty())"
") (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")"); do { *((volatile int*)__null) = 2234; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2234 "if NS_FRAME_VISIBILITY_IS_TRACKED is not set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasProperty(VisibilityStateProperty()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!HasProperty(VisibilityStateProperty())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!HasProperty(VisibilityStateProperty())"
" (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasProperty(VisibilityStateProperty())"
") (" "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"
")"); do { *((volatile int*)__null) = 2234; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2235
2236 // Add the state bit so we know to track visibility for this frame, and
2237 // initialize the frame property.
2238 AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
2239 SetProperty(VisibilityStateProperty(), 0);
2240
2241 mozilla::PresShell* presShell = PresShell();
2242 if (!presShell) {
2243 return;
2244 }
2245
2246 // Schedule a visibility update. This method will virtually always be called
2247 // when layout has changed anyway, so it's very unlikely that any additional
2248 // visibility updates will be triggered by this, but this way we guarantee
2249 // that if this frame is currently visible we'll eventually find out.
2250 presShell->ScheduleApproximateFrameVisibilityUpdateSoon();
2251}
2252
2253void nsIFrame::DisableVisibilityTracking() {
2254 if (!HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)) {
2255 return; // Nothing to do.
2256 }
2257
2258 bool isSet = false;
2259 uint32_t visibleCount = TakeProperty(VisibilityStateProperty(), &isSet);
2260
2261 MOZ_ASSERT(isSet,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2262 "Should have a VisibilityStateProperty value "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2263 "if NS_FRAME_VISIBILITY_IS_TRACKED is set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2264
2265 RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
2266
2267 if (visibleCount == 0) {
2268 return; // We were nonvisible.
2269 }
2270
2271 // We were visible, so send an OnVisibilityChange() notification.
2272 OnVisibilityChange(Visibility::ApproximatelyNonVisible);
2273}
2274
2275void nsIFrame::DecApproximateVisibleCount(
2276 const Maybe<OnNonvisible>& aNonvisibleAction
2277 /* = Nothing() */) {
2278 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)"
")"); do { *((volatile int*)__null) = 2278; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2279
2280 bool isSet = false;
2281 uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
2282
2283 MOZ_ASSERT(isSet,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2284 "Should have a VisibilityStateProperty value "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2285 "if NS_FRAME_VISIBILITY_IS_TRACKED is set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2286 MOZ_ASSERT(visibleCount > 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(visibleCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(visibleCount > 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("visibleCount > 0"
" (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2288); AnnotateMozCrashReason("MOZ_ASSERT" "(" "visibleCount > 0"
") (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")"); do { *((volatile int*)__null) = 2288; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2287 "Frame is already nonvisible and we're "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(visibleCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(visibleCount > 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("visibleCount > 0"
" (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2288); AnnotateMozCrashReason("MOZ_ASSERT" "(" "visibleCount > 0"
") (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")"); do { *((volatile int*)__null) = 2288; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2288 "decrementing its visible count?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(visibleCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(visibleCount > 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("visibleCount > 0"
" (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2288); AnnotateMozCrashReason("MOZ_ASSERT" "(" "visibleCount > 0"
") (" "Frame is already nonvisible and we're " "decrementing its visible count?"
")"); do { *((volatile int*)__null) = 2288; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2289
2290 visibleCount--;
2291 SetProperty(VisibilityStateProperty(), visibleCount);
2292 if (visibleCount > 0) {
2293 return;
2294 }
2295
2296 // We just became nonvisible, so send an OnVisibilityChange() notification.
2297 OnVisibilityChange(Visibility::ApproximatelyNonVisible, aNonvisibleAction);
2298}
2299
2300void nsIFrame::IncApproximateVisibleCount() {
2301 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2301); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED)"
")"); do { *((volatile int*)__null) = 2301; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2302
2303 bool isSet = false;
2304 uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
2305
2306 MOZ_ASSERT(isSet,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2308; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2307 "Should have a VisibilityStateProperty value "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2308; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2308 "if NS_FRAME_VISIBILITY_IS_TRACKED is set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSet)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(isSet))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("isSet" " (" "Should have a VisibilityStateProperty value "
"if NS_FRAME_VISIBILITY_IS_TRACKED is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSet" ") ("
"Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"
")"); do { *((volatile int*)__null) = 2308; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2309
2310 visibleCount++;
2311 SetProperty(VisibilityStateProperty(), visibleCount);
2312 if (visibleCount > 1) {
2313 return;
2314 }
2315
2316 // We just became visible, so send an OnVisibilityChange() notification.
2317 OnVisibilityChange(Visibility::ApproximatelyVisible);
2318}
2319
2320void nsIFrame::OnVisibilityChange(Visibility aNewVisibility,
2321 const Maybe<OnNonvisible>& aNonvisibleAction
2322 /* = Nothing() */) {
2323 // XXX(seth): In bug 1218990 we'll implement visibility tracking for CSS
2324 // images here.
2325}
2326
2327static nsIFrame* GetActiveSelectionFrame(nsPresContext* aPresContext,
2328 nsIFrame* aFrame) {
2329 nsIContent* capturingContent = PresShell::GetCapturingContent();
2330 if (capturingContent) {
2331 nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
2332 return activeFrame ? activeFrame : aFrame;
2333 }
2334
2335 return aFrame;
2336}
2337
2338int16_t nsIFrame::DetermineDisplaySelection() {
2339 int16_t selType = nsISelectionController::SELECTION_OFF;
2340
2341 nsCOMPtr<nsISelectionController> selCon;
2342 nsresult result =
2343 GetSelectionController(PresContext(), getter_AddRefs(selCon));
2344 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1))) && selCon) {
2345 result = selCon->GetDisplaySelection(&selType);
2346 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1))) &&
2347 (selType != nsISelectionController::SELECTION_OFF)) {
2348 // Check whether style allows selection.
2349 if (!IsSelectable(nullptr)) {
2350 selType = nsISelectionController::SELECTION_OFF;
2351 }
2352 }
2353 }
2354 return selType;
2355}
2356
2357static Element* FindElementAncestorForMozSelection(nsIContent* aContent) {
2358 NS_ENSURE_TRUE(aContent, nullptr)do { if ((__builtin_expect(!!(!(aContent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aContent" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2358); return nullptr; } } while (false)
;
2359 while (aContent && aContent->IsInNativeAnonymousSubtree()) {
2360 aContent = aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost();
2361 }
2362 NS_ASSERTION(aContent, "aContent isn't in non-anonymous tree?")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "aContent isn't in non-anonymous tree?"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2362); MOZ_PretendNoReturn(); } } while (0)
;
2363 return aContent ? aContent->GetAsElementOrParentElement() : nullptr;
2364}
2365
2366already_AddRefed<ComputedStyle> nsIFrame::ComputeSelectionStyle(
2367 int16_t aSelectionStatus) const {
2368 // Just bail out if not a selection-status that ::selection applies to.
2369 if (aSelectionStatus != nsISelectionController::SELECTION_ON &&
2370 aSelectionStatus != nsISelectionController::SELECTION_DISABLED) {
2371 return nullptr;
2372 }
2373 Element* element = FindElementAncestorForMozSelection(GetContent());
2374 if (!element) {
2375 return nullptr;
2376 }
2377 RefPtr<ComputedStyle> pseudoStyle =
2378 PresContext()->StyleSet()->ProbePseudoElementStyle(
2379 *element, PseudoStyleType::selection, nullptr, Style());
2380 if (!pseudoStyle) {
2381 return nullptr;
2382 }
2383 // When in high-contrast mode, the style system ends up ignoring the color
2384 // declarations, which means that the ::selection style becomes the inherited
2385 // color, and default background. That's no good.
2386 // When force-color-adjust is set to none allow using the color styles,
2387 // as they will not be replaced.
2388 if (PresContext()->ForcingColors() &&
2389 pseudoStyle->StyleText()->mForcedColorAdjust !=
2390 StyleForcedColorAdjust::None) {
2391 return nullptr;
2392 }
2393 return do_AddRef(pseudoStyle);
2394}
2395
2396already_AddRefed<ComputedStyle> nsIFrame::ComputeHighlightSelectionStyle(
2397 nsAtom* aHighlightName) {
2398 Element* element = FindElementAncestorForMozSelection(GetContent());
2399 if (!element) {
2400 return nullptr;
2401 }
2402 return PresContext()->StyleSet()->ProbePseudoElementStyle(
2403 *element, PseudoStyleType::highlight, aHighlightName, Style());
2404}
2405
2406already_AddRefed<ComputedStyle> nsIFrame::ComputeTargetTextStyle() const {
2407 const Element* element = FindElementAncestorForMozSelection(GetContent());
2408 if (!element) {
2409 return nullptr;
2410 }
2411 return PresContext()->StyleSet()->ProbePseudoElementStyle(
2412 *element, PseudoStyleType::targetText, nullptr, Style());
2413}
2414
2415template <typename SizeOrMaxSize>
2416static inline bool IsIntrinsicKeyword(const SizeOrMaxSize& aSize) {
2417 // All keywords other than auto/none/-moz-available depend on intrinsic sizes.
2418 return aSize.IsMaxContent() || aSize.IsMinContent() || aSize.IsFitContent() ||
2419 aSize.IsFitContentFunction();
2420}
2421
2422bool nsIFrame::CanBeDynamicReflowRoot() const {
2423 const auto& display = *StyleDisplay();
2424 if (IsLineParticipant() || display.mDisplay.IsRuby() ||
2425 display.IsInnerTableStyle() ||
2426 display.DisplayInside() == StyleDisplayInside::Table) {
2427 // We have a display type where 'width' and 'height' don't actually set the
2428 // width or height (i.e., the size depends on content).
2429 MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)"
" (" "should not have dynamic reflow root bit" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2430); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)"
") (" "should not have dynamic reflow root bit" ")"); do { *
((volatile int*)__null) = 2430; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
2430 "should not have dynamic reflow root bit")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)"
" (" "should not have dynamic reflow root bit" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2430); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT)"
") (" "should not have dynamic reflow root bit" ")"); do { *
((volatile int*)__null) = 2430; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
2431 return false;
2432 }
2433
2434 // In general, frames that have contain:layout+size can be reflow roots.
2435 // (One exception: table-wrapper frames don't work well as reflow roots,
2436 // because their inner-table ReflowInput init path tries to reuse & deref
2437 // the wrapper's containing block's reflow input, which may be null if we
2438 // initiate reflow from the table-wrapper itself.)
2439 //
2440 // Changes to `contain` force frame reconstructions, so we used to use
2441 // NS_FRAME_REFLOW_ROOT, this bit could be set for the whole lifetime of
2442 // this frame. But after the support of `content-visibility: auto` which
2443 // is with contain layout + size when it's not relevant to user, and only
2444 // with contain layout when it is relevant. The frame does not reconstruct
2445 // when the relevancy changes. So we use NS_FRAME_DYNAMIC_REFLOW_ROOT instead.
2446 //
2447 // We place it above the pref check on purpose, to make sure it works for
2448 // containment even with the pref disabled.
2449 if (display.IsContainLayout() && GetContainSizeAxes().IsBoth()) {
2450 return true;
2451 }
2452
2453 if (!StaticPrefs::layout_dynamic_reflow_roots_enabled()) {
2454 return false;
2455 }
2456
2457 // We can't serve as a dynamic reflow root if our used 'width' and 'height'
2458 // might be influenced by content.
2459 //
2460 // FIXME: For display:block, we should probably optimize inline-size: auto.
2461 // FIXME: Other flex and grid cases?
2462 const auto& pos = *StylePosition();
2463 const auto& width = pos.mWidth;
2464 const auto& height = pos.mHeight;
2465 if (!width.IsLengthPercentage() || width.HasPercent() ||
2466 !height.IsLengthPercentage() || height.HasPercent() ||
2467 IsIntrinsicKeyword(pos.mMinWidth) || IsIntrinsicKeyword(pos.mMaxWidth) ||
2468 IsIntrinsicKeyword(pos.mMinHeight) ||
2469 IsIntrinsicKeyword(pos.mMaxHeight) ||
2470 ((pos.mMinWidth.IsAuto() || pos.mMinHeight.IsAuto()) &&
2471 IsFlexOrGridItem())) {
2472 return false;
2473 }
2474
2475 // If our flex-basis is 'auto', it'll defer to 'width' (or 'height') which
2476 // we've already checked. Otherwise, it preempts them, so we need to
2477 // perform the same "could-this-value-be-influenced-by-content" checks that
2478 // we performed for 'width' and 'height' above.
2479 if (IsFlexItem()) {
2480 const auto& flexBasis = pos.mFlexBasis;
2481 if (!flexBasis.IsAuto()) {
2482 if (!flexBasis.IsSize() || !flexBasis.AsSize().IsLengthPercentage() ||
2483 flexBasis.AsSize().HasPercent()) {
2484 return false;
2485 }
2486 }
2487 }
2488
2489 if (!IsFixedPosContainingBlock()) {
2490 // We can't treat this frame as a reflow root, since dynamic changes
2491 // to absolutely-positioned frames inside of it require that we
2492 // reflow the placeholder before we reflow the absolutely positioned
2493 // frame.
2494 // FIXME: Alternatively, we could sort the reflow roots in
2495 // PresShell::ProcessReflowCommands by depth in the tree, from
2496 // deepest to least deep. However, for performance (FIXME) we
2497 // should really be sorting them in the opposite order!
2498 return false;
2499 }
2500
2501 // If we participate in a container's block reflow context, or margins
2502 // can collapse through us, we can't be a dynamic reflow root.
2503 if (IsBlockFrameOrSubclass() && !HasAnyStateBits(NS_BLOCK_BFC)) {
2504 return false;
2505 }
2506
2507 // Subgrids are never reflow roots, but 'contain:layout/paint' prevents
2508 // creating a subgrid in the first place.
2509 if (pos.mGridTemplateColumns.IsSubgrid() ||
2510 pos.mGridTemplateRows.IsSubgrid()) {
2511 // NOTE: we could check that 'display' of our parent's primary frame is
2512 // '[inline-]grid' here but that's probably not worth it in practice.
2513 if (!display.IsContainLayout() && !display.IsContainPaint()) {
2514 return false;
2515 }
2516 }
2517
2518 // If we are split, we can't be a dynamic reflow root. Our reflow status may
2519 // change after reflow, and our parent is responsible to create or delete our
2520 // next-in-flow.
2521 if (GetPrevContinuation() || GetNextContinuation()) {
2522 return false;
2523 }
2524
2525 return true;
2526}
2527
2528/********************************************************
2529 * Refreshes each content's frame
2530 *********************************************************/
2531
2532void nsIFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
2533 const nsDisplayListSet& aLists) {
2534 // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides:
2535 // "All css properties of table-column and table-column-group boxes are
2536 // ignored, except when explicitly specified by this specification."
2537 // CSS outlines fall into this category, so we skip them on these boxes.
2538 MOZ_ASSERT(!IsTableColGroupFrame() && !IsTableColFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsTableColGroupFrame() && !IsTableColFrame(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!IsTableColGroupFrame() && !IsTableColFrame(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsTableColGroupFrame() && !IsTableColFrame()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsTableColGroupFrame() && !IsTableColFrame()"
")"); do { *((volatile int*)__null) = 2538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2539 const auto& outline = *StyleOutline();
2540
2541 if (!outline.ShouldPaintOutline()) {
2542 return;
2543 }
2544
2545 // Outlines are painted by the table wrapper frame.
2546 if (IsTableFrame()) {
2547 return;
2548 }
2549
2550 if (HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
2551 ScrollableOverflowRect().IsEmpty()) {
2552 // Skip parts of IB-splits with an empty overflow rect, see bug 434301.
2553 // We may still want to fix some of the overflow area calculations over in
2554 // that bug.
2555 return;
2556 }
2557
2558 // We don't display outline-style: auto on themed frames that have their own
2559 // focus indicators.
2560 if (outline.mOutlineStyle.IsAuto()) {
2561 auto* disp = StyleDisplay();
2562 if (IsThemed(disp) && PresContext()->Theme()->ThemeDrawsFocusForWidget(
2563 this, disp->EffectiveAppearance())) {
2564 return;
2565 }
2566 }
2567
2568 aLists.Outlines()->AppendNewToTop<nsDisplayOutline>(aBuilder, this);
2569}
2570
2571void nsIFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
2572 const nsDisplayListSet& aLists) {
2573 if (!IsVisibleForPainting()) return;
2574
2575 DisplayOutlineUnconditional(aBuilder, aLists);
2576}
2577
2578void nsIFrame::DisplayInsetBoxShadowUnconditional(
2579 nsDisplayListBuilder* aBuilder, nsDisplayList* aList) {
2580 // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
2581 // just because we're visible? Or should it depend on the cell visibility
2582 // when we're not the whole table?
2583 const auto* effects = StyleEffects();
2584 if (effects->HasBoxShadowWithInset(true)) {
2585 aList->AppendNewToTop<nsDisplayBoxShadowInner>(aBuilder, this);
2586 }
2587}
2588
2589void nsIFrame::DisplayInsetBoxShadow(nsDisplayListBuilder* aBuilder,
2590 nsDisplayList* aList) {
2591 if (!IsVisibleForPainting()) return;
2592
2593 DisplayInsetBoxShadowUnconditional(aBuilder, aList);
2594}
2595
2596void nsIFrame::DisplayOutsetBoxShadowUnconditional(
2597 nsDisplayListBuilder* aBuilder, nsDisplayList* aList) {
2598 // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
2599 // just because we're visible? Or should it depend on the cell visibility
2600 // when we're not the whole table?
2601 const auto* effects = StyleEffects();
2602 if (effects->HasBoxShadowWithInset(false)) {
2603 aList->AppendNewToTop<nsDisplayBoxShadowOuter>(aBuilder, this);
2604 }
2605}
2606
2607void nsIFrame::DisplayOutsetBoxShadow(nsDisplayListBuilder* aBuilder,
2608 nsDisplayList* aList) {
2609 if (!IsVisibleForPainting()) return;
2610
2611 DisplayOutsetBoxShadowUnconditional(aBuilder, aList);
2612}
2613
2614void nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
2615 nsDisplayList* aList) {
2616 if (!IsVisibleForPainting()) return;
2617
2618 aList->AppendNewToTop<nsDisplayCaret>(aBuilder, this);
2619}
2620
2621nscolor nsIFrame::GetCaretColorAt(int32_t aOffset) {
2622 return nsLayoutUtils::GetColor(this, &nsStyleUI::mCaretColor);
2623}
2624
2625auto nsIFrame::ComputeShouldPaintBackground() const -> ShouldPaintBackground {
2626 nsPresContext* pc = PresContext();
2627 ShouldPaintBackground settings{pc->GetBackgroundColorDraw(),
2628 pc->GetBackgroundImageDraw()};
2629 if (settings.mColor && settings.mImage) {
2630 return settings;
2631 }
2632
2633 if (StyleVisibility()->mPrintColorAdjust == StylePrintColorAdjust::Exact) {
2634 return {true, true};
2635 }
2636
2637 return settings;
2638}
2639
2640bool nsIFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
2641 const nsDisplayListSet& aLists) {
2642 if (aBuilder->IsForEventDelivery() && !aBuilder->HitTestIsForVisibility()) {
2643 // For hit-testing, we generally just need a light-weight data structure
2644 // like nsDisplayEventReceiver. But if the hit-testing is for visibility,
2645 // then we need to know the opaque region in order to determine whether to
2646 // stop or not.
2647 aLists.BorderBackground()->AppendNewToTop<nsDisplayEventReceiver>(aBuilder,
2648 this);
2649 return false;
2650 }
2651
2652 const AppendedBackgroundType result =
2653 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
2654 aBuilder, this,
2655 GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this),
2656 aLists.BorderBackground());
2657
2658 if (result == AppendedBackgroundType::None) {
2659 aBuilder->BuildCompositorHitTestInfoIfNeeded(this,
2660 aLists.BorderBackground());
2661 }
2662
2663 return result == AppendedBackgroundType::ThemedBackground;
2664}
2665
2666void nsIFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
2667 const nsDisplayListSet& aLists) {
2668 // The visibility check belongs here since child elements have the
2669 // opportunity to override the visibility property and display even if
2670 // their parent is hidden.
2671 if (!IsVisibleForPainting()) {
2672 return;
2673 }
2674
2675 DisplayOutsetBoxShadowUnconditional(aBuilder, aLists.BorderBackground());
2676
2677 bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists);
2678 DisplayInsetBoxShadowUnconditional(aBuilder, aLists.BorderBackground());
2679
2680 // If there's a themed background, we should not create a border item.
2681 // It won't be rendered.
2682 // Don't paint borders for tables here, since they paint them in a different
2683 // order.
2684 if (!bgIsThemed && StyleBorder()->HasBorder() && !IsTableFrame()) {
2685 aLists.BorderBackground()->AppendNewToTop<nsDisplayBorder>(aBuilder, this);
2686 }
2687
2688 DisplayOutlineUnconditional(aBuilder, aLists);
2689}
2690
2691inline static bool IsSVGContentWithCSSClip(const nsIFrame* aFrame) {
2692 // The CSS spec says that the 'clip' property only applies to absolutely
2693 // positioned elements, whereas the SVG spec says that it applies to SVG
2694 // elements regardless of the value of the 'position' property. Here we obey
2695 // the CSS spec for outer-<svg> (since that's what we generally do), but
2696 // obey the SVG spec for other SVG elements to which 'clip' applies.
2697 return aFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
2698 aFrame->GetContent()->IsAnyOfSVGElements(nsGkAtoms::svg,
2699 nsGkAtoms::foreignObject);
2700}
2701
2702Maybe<nsRect> nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp,
2703 const nsStyleEffects* aEffects,
2704 const nsSize& aSize) const {
2705 if (aEffects->mClip.IsAuto() ||
2706 !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
2707 return Nothing();
2708 }
2709
2710 auto& clipRect = aEffects->mClip.AsRect();
2711 nsRect rect = clipRect.ToLayoutRect();
2712 if (MOZ_LIKELY(StyleBorder()->mBoxDecorationBreak ==(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Slice), 1))
2713 StyleBoxDecorationBreak::Slice)(__builtin_expect(!!(StyleBorder()->mBoxDecorationBreak ==
StyleBoxDecorationBreak::Slice), 1))
) {
2714 // The clip applies to the joined boxes so it's relative the first
2715 // continuation.
2716 nscoord y = 0;
2717 for (nsIFrame* f = GetPrevContinuation(); f; f = f->GetPrevContinuation()) {
2718 y += f->GetRect().height;
2719 }
2720 rect.MoveBy(nsPoint(0, -y));
2721 }
2722
2723 if (clipRect.right.IsAuto()) {
2724 rect.width = aSize.width - rect.x;
2725 }
2726 if (clipRect.bottom.IsAuto()) {
2727 rect.height = aSize.height - rect.y;
2728 }
2729 return Some(rect);
2730}
2731
2732/**
2733 * If the CSS 'overflow' property applies to this frame, and is not
2734 * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
2735 * for that overflow in aBuilder->ClipState() to clip all containing-block
2736 * descendants.
2737 */
2738static void ApplyOverflowClipping(
2739 nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame,
2740 nsIFrame::PhysicalAxes aClipAxes,
2741 DisplayListClipState::AutoClipMultiple& aClipState) {
2742 // Only 'clip' is handled here (and 'hidden' for table frames, and any
2743 // non-'visible' value for blocks in a paginated context).
2744 // We allow 'clip' to apply to any kind of frame. This is required by
2745 // comboboxes which make their display text (an inline frame) have clipping.
2746 MOZ_ASSERT(aClipAxes != nsIFrame::PhysicalAxes::None)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClipAxes != nsIFrame::PhysicalAxes::None)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aClipAxes != nsIFrame::PhysicalAxes::None))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aClipAxes != nsIFrame::PhysicalAxes::None"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClipAxes != nsIFrame::PhysicalAxes::None"
")"); do { *((volatile int*)__null) = 2746; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2747 MOZ_ASSERT(aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay
()) == aClipAxes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->ShouldApplyOverflowClipping
(aFrame->StyleDisplay()) == aClipAxes))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) == aClipAxes"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2748); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) == aClipAxes"
")"); do { *((volatile int*)__null) = 2748; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2748 aClipAxes)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay
()) == aClipAxes)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aFrame->ShouldApplyOverflowClipping
(aFrame->StyleDisplay()) == aClipAxes))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) == aClipAxes"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2748); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) == aClipAxes"
")"); do { *((volatile int*)__null) = 2748; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2749
2750 nsRect clipRect;
2751 bool haveRadii = false;
2752 nscoord radii[8];
2753 auto* disp = aFrame->StyleDisplay();
2754 // Only deflate the padding if we clip to the content-box in that axis.
2755 auto wm = aFrame->GetWritingMode();
2756 bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
2757 : disp->mOverflowClipBoxInline) ==
2758 StyleOverflowClipBox::ContentBox;
2759 bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
2760 : disp->mOverflowClipBoxBlock) ==
2761 StyleOverflowClipBox::ContentBox;
2762
2763 nsMargin boxMargin = -aFrame->GetUsedPadding();
2764 if (!cbH) {
2765 boxMargin.left = boxMargin.right = nscoord(0);
2766 }
2767 if (!cbV) {
2768 boxMargin.top = boxMargin.bottom = nscoord(0);
2769 }
2770
2771 auto clipMargin = aFrame->OverflowClipMargin(aClipAxes);
2772
2773 boxMargin -= aFrame->GetUsedBorder();
2774 boxMargin += nsMargin(clipMargin.height, clipMargin.width, clipMargin.height,
2775 clipMargin.width);
2776 boxMargin.ApplySkipSides(aFrame->GetSkipSides());
2777
2778 nsRect rect(nsPoint(0, 0), aFrame->GetSize());
2779 rect.Inflate(boxMargin);
2780 if (MOZ_UNLIKELY(!(aClipAxes & nsIFrame::PhysicalAxes::Horizontal))(__builtin_expect(!!(!(aClipAxes & nsIFrame::PhysicalAxes
::Horizontal)), 0))
) {
2781 // NOTE(mats) We shouldn't be clipping at all in this dimension really,
2782 // but clipping in just one axis isn't supported by our GFX APIs so we
2783 // clip to our visual overflow rect instead.
2784 nsRect o = aFrame->InkOverflowRect();
2785 rect.x = o.x;
2786 rect.width = o.width;
2787 }
2788 if (MOZ_UNLIKELY(!(aClipAxes & nsIFrame::PhysicalAxes::Vertical))(__builtin_expect(!!(!(aClipAxes & nsIFrame::PhysicalAxes
::Vertical)), 0))
) {
2789 // See the note above.
2790 nsRect o = aFrame->InkOverflowRect();
2791 rect.y = o.y;
2792 rect.height = o.height;
2793 }
2794 clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
2795 haveRadii = aFrame->GetBoxBorderRadii(radii, boxMargin);
2796 aClipState.ClipContainingBlockDescendantsExtra(clipRect,
2797 haveRadii ? radii : nullptr);
2798}
2799
2800nsSize nsIFrame::OverflowClipMargin(PhysicalAxes aClipAxes) const {
2801 nsSize result;
2802 if (aClipAxes == PhysicalAxes::None) {
2803 return result;
2804 }
2805 const auto& margin = StyleMargin()->mOverflowClipMargin;
2806 if (margin.IsZero()) {
2807 return result;
2808 }
2809 nscoord marginAu = margin.ToAppUnits();
2810 if (aClipAxes & PhysicalAxes::Horizontal) {
2811 result.width = marginAu;
2812 }
2813 if (aClipAxes & PhysicalAxes::Vertical) {
2814 result.height = marginAu;
2815 }
2816 return result;
2817}
2818
2819/**
2820 * Returns whether a display item that gets created with the builder's current
2821 * state will have a scrolled clip, i.e. a clip that is scrolled by a scroll
2822 * frame which does not move the item itself.
2823 */
2824static bool BuilderHasScrolledClip(nsDisplayListBuilder* aBuilder) {
2825 const DisplayItemClipChain* currentClip =
2826 aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
2827 if (!currentClip) {
2828 return false;
2829 }
2830
2831 const ActiveScrolledRoot* currentClipASR = currentClip->mASR;
2832 const ActiveScrolledRoot* currentASR = aBuilder->CurrentActiveScrolledRoot();
2833 return ActiveScrolledRoot::PickDescendant(currentClipASR, currentASR) !=
2834 currentASR;
2835}
2836
2837class AutoSaveRestoreContainsBlendMode {
2838 nsDisplayListBuilder& mBuilder;
2839 bool mSavedContainsBlendMode;
2840
2841 public:
2842 explicit AutoSaveRestoreContainsBlendMode(nsDisplayListBuilder& aBuilder)
2843 : mBuilder(aBuilder),
2844 mSavedContainsBlendMode(aBuilder.ContainsBlendMode()) {}
2845
2846 ~AutoSaveRestoreContainsBlendMode() {
2847 mBuilder.SetContainsBlendMode(mSavedContainsBlendMode);
2848 }
2849};
2850
2851static bool IsFrameOrAncestorApzAware(nsIFrame* aFrame) {
2852 nsIContent* node = aFrame->GetContent();
2853 if (!node) {
2854 return false;
2855 }
2856
2857 do {
2858 if (node->IsNodeApzAware()) {
2859 return true;
2860 }
2861 nsIContent* shadowRoot = node->GetShadowRoot();
2862 if (shadowRoot && shadowRoot->IsNodeApzAware()) {
2863 return true;
2864 }
2865
2866 // Even if the node owning aFrame doesn't have apz-aware event listeners
2867 // itself, its shadow root or display: contents ancestors (which have no
2868 // frames) might, so we need to account for them too.
2869 } while ((node = node->GetFlattenedTreeParent()) && node->IsElement() &&
2870 node->AsElement()->IsDisplayContents());
2871
2872 return false;
2873}
2874
2875static void CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder,
2876 nsIFrame* aFrame) {
2877 if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
2878 return;
2879 }
2880
2881 if (IsFrameOrAncestorApzAware(aFrame)) {
2882 aBuilder->SetAncestorHasApzAwareEventHandler(true);
2883 }
2884}
2885
2886static void UpdateCurrentHitTestInfo(nsDisplayListBuilder* aBuilder,
2887 nsIFrame* aFrame) {
2888 if (!aBuilder->BuildCompositorHitTestInfo()) {
2889 // Compositor hit test info is not used.
2890 return;
2891 }
2892
2893 CheckForApzAwareEventHandlers(aBuilder, aFrame);
2894
2895 const CompositorHitTestInfo info = aFrame->GetCompositorHitTestInfo(aBuilder);
2896 aBuilder->SetCompositorHitTestInfo(info);
2897}
2898
2899/**
2900 * True if aDescendant participates the context aAncestor participating.
2901 */
2902static bool FrameParticipatesIn3DContext(nsIFrame* aAncestor,
2903 nsIFrame* aDescendant) {
2904 MOZ_ASSERT(aAncestor != aDescendant)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAncestor != aDescendant)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAncestor != aDescendant))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aAncestor != aDescendant"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAncestor != aDescendant"
")"); do { *((volatile int*)__null) = 2904; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2905 MOZ_ASSERT(aAncestor->GetContent() != aDescendant->GetContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAncestor->GetContent() != aDescendant->GetContent
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aAncestor->GetContent() != aDescendant->GetContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAncestor->GetContent() != aDescendant->GetContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAncestor->GetContent() != aDescendant->GetContent()"
")"); do { *((volatile int*)__null) = 2905; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2906 MOZ_ASSERT(aAncestor->Extend3DContext())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aAncestor->Extend3DContext())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aAncestor->Extend3DContext
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aAncestor->Extend3DContext()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2906); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aAncestor->Extend3DContext()"
")"); do { *((volatile int*)__null) = 2906; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2907
2908 nsIFrame* ancestor = aAncestor->FirstContinuation();
2909 MOZ_ASSERT(ancestor->IsPrimaryFrame())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestor->IsPrimaryFrame())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ancestor->IsPrimaryFrame(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("ancestor->IsPrimaryFrame()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2909); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestor->IsPrimaryFrame()"
")"); do { *((volatile int*)__null) = 2909; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2910
2911 nsIFrame* frame;
2912 for (frame = aDescendant->GetClosestFlattenedTreeAncestorPrimaryFrame();
2913 frame && ancestor != frame;
2914 frame = frame->GetClosestFlattenedTreeAncestorPrimaryFrame()) {
2915 if (!frame->Extend3DContext()) {
2916 return false;
2917 }
2918 }
2919
2920 MOZ_ASSERT(frame == ancestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(frame == ancestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(frame == ancestor))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("frame == ancestor"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 2920); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frame == ancestor"
")"); do { *((volatile int*)__null) = 2920; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2921 return true;
2922}
2923
2924static bool ItemParticipatesIn3DContext(nsIFrame* aAncestor,
2925 nsDisplayItem* aItem) {
2926 auto type = aItem->GetType();
2927 const bool isContainer = type == DisplayItemType::TYPE_WRAP_LIST ||
2928 type == DisplayItemType::TYPE_CONTAINER;
2929
2930 if (isContainer && aItem->GetChildren()->Length() == 1) {
2931 // If the wraplist has only one child item, use the type of that item.
2932 type = aItem->GetChildren()->GetBottom()->GetType();
2933 }
2934
2935 if (type != DisplayItemType::TYPE_TRANSFORM &&
2936 type != DisplayItemType::TYPE_PERSPECTIVE) {
2937 return false;
2938 }
2939 nsIFrame* transformFrame = aItem->Frame();
2940 if (aAncestor->GetContent() == transformFrame->GetContent()) {
2941 return true;
2942 }
2943 return FrameParticipatesIn3DContext(aAncestor, transformFrame);
2944}
2945
2946static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder,
2947 nsIFrame* aFrame,
2948 nsDisplayList* aNonParticipants,
2949 nsDisplayList* aParticipants, int aIndex,
2950 nsDisplayItem** aSeparator) {
2951 if (aNonParticipants->IsEmpty()) {
2952 return;
2953 }
2954
2955 nsDisplayTransform* item = MakeDisplayItemWithIndex<nsDisplayTransform>(
2956 aBuilder, aFrame, aIndex, aNonParticipants, aBuilder->GetVisibleRect());
2957
2958 if (*aSeparator == nullptr && item) {
2959 *aSeparator = item;
2960 }
2961
2962 aParticipants->AppendToTop(item);
2963}
2964
2965// Try to compute a clip rect to bound the contents of the mask item
2966// that will be built for |aMaskedFrame|. If we're not able to compute
2967// one, return an empty Maybe.
2968// The returned clip rect, if there is one, is relative to |aMaskedFrame|.
2969static Maybe<nsRect> ComputeClipForMaskItem(
2970 nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame,
2971 const SVGUtils::MaskUsage& aMaskUsage) {
2972 const nsStyleSVGReset* svgReset = aMaskedFrame->StyleSVGReset();
2973
2974 nsPoint offsetToUserSpace =
2975 nsLayoutUtils::ComputeOffsetToUserSpace(aBuilder, aMaskedFrame);
2976 int32_t devPixelRatio = aMaskedFrame->PresContext()->AppUnitsPerDevPixel();
2977 gfxPoint devPixelOffsetToUserSpace =
2978 nsLayoutUtils::PointToGfxPoint(offsetToUserSpace, devPixelRatio);
2979 CSSToLayoutDeviceScale cssToDevScale =
2980 aMaskedFrame->PresContext()->CSSToDevPixelScale();
2981
2982 nsPoint toReferenceFrame;
2983 aBuilder->FindReferenceFrameFor(aMaskedFrame, &toReferenceFrame);
2984
2985 Maybe<gfxRect> combinedClip;
2986 if (aMaskUsage.ShouldApplyBasicShapeOrPath()) {
2987 Maybe<Rect> result =
2988 CSSClipPathInstance::GetBoundingRectForBasicShapeOrPathClip(
2989 aMaskedFrame, svgReset->mClipPath);
2990 if (result) {
2991 combinedClip = Some(ThebesRect(*result));
2992 }
2993 } else if (aMaskUsage.ShouldApplyClipPath()) {
2994 gfxRect result = SVGUtils::GetBBox(
2995 aMaskedFrame,
2996 SVGUtils::eBBoxIncludeClipped | SVGUtils::eBBoxIncludeFill |
2997 SVGUtils::eBBoxIncludeMarkers | SVGUtils::eBBoxIncludeStroke |
2998 SVGUtils::eDoNotClipToBBoxOfContentInsideClipPath);
2999 combinedClip = Some(
3000 ThebesRect((CSSRect::FromUnknownRect(ToRect(result)) * cssToDevScale)
3001 .ToUnknownRect()));
3002 } else {
3003 // The code for this case is adapted from ComputeMaskGeometry().
3004
3005 nsRect borderArea(toReferenceFrame, aMaskedFrame->GetSize());
3006 borderArea -= offsetToUserSpace;
3007
3008 // Use an infinite dirty rect to pass into nsCSSRendering::
3009 // GetImageLayerClip() because we don't have an actual dirty rect to
3010 // pass in. This is fine because the only time GetImageLayerClip() will
3011 // not intersect the incoming dirty rect with something is in the "NoClip"
3012 // case, and we handle that specially.
3013 nsRect dirtyRect(nscoord_MIN / 2, nscoord_MIN / 2, nscoord_MAX,
3014 nscoord_MAX);
3015
3016 nsIFrame* firstFrame =
3017 nsLayoutUtils::FirstContinuationOrIBSplitSibling(aMaskedFrame);
3018 nsTArray<SVGMaskFrame*> maskFrames;
3019 // XXX check return value?
3020 SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
3021
3022 for (uint32_t i = 0; i < maskFrames.Length(); ++i) {
3023 gfxRect clipArea;
3024 if (maskFrames[i]) {
3025 clipArea = maskFrames[i]->GetMaskArea(aMaskedFrame);
3026 clipArea = ThebesRect(
3027 (CSSRect::FromUnknownRect(ToRect(clipArea)) * cssToDevScale)
3028 .ToUnknownRect());
3029 } else {
3030 const auto& layer = svgReset->mMask.mLayers[i];
3031 if (layer.mClip == StyleGeometryBox::NoClip) {
3032 return Nothing();
3033 }
3034
3035 nsCSSRendering::ImageLayerClipState clipState;
3036 nsCSSRendering::GetImageLayerClip(
3037 layer, aMaskedFrame, *aMaskedFrame->StyleBorder(), borderArea,
3038 dirtyRect, false /* aWillPaintBorder */, devPixelRatio, &clipState);
3039 clipArea = clipState.mDirtyRectInDevPx;
3040 }
3041 combinedClip = UnionMaybeRects(combinedClip, Some(clipArea));
3042 }
3043 }
3044 if (combinedClip) {
3045 if (combinedClip->IsEmpty()) {
3046 // *clipForMask might be empty if all mask references are not resolvable
3047 // or the size of them are empty. We still need to create a transparent
3048 // mask before bug 1276834 fixed, so don't clip ctx by an empty rectangle
3049 // for for now.
3050 return Nothing();
3051 }
3052
3053 // Convert to user space.
3054 *combinedClip += devPixelOffsetToUserSpace;
3055
3056 // Round the clip out. In FrameLayerBuilder we round clips to nearest
3057 // pixels, and if we have a really thin clip here, that can cause the
3058 // clip to become empty if we didn't round out here.
3059 // The rounding happens in coordinates that are relative to the reference
3060 // frame, which matches what FrameLayerBuilder does.
3061 combinedClip->RoundOut();
3062
3063 // Convert to app units.
3064 nsRect result =
3065 nsLayoutUtils::RoundGfxRectToAppRect(*combinedClip, devPixelRatio);
3066
3067 // The resulting clip is relative to the reference frame, but the caller
3068 // expects it to be relative to the masked frame, so adjust it.
3069 result -= toReferenceFrame;
3070 return Some(result);
3071 }
3072 return Nothing();
3073}
3074
3075struct AutoCheckBuilder {
3076 explicit AutoCheckBuilder(nsDisplayListBuilder* aBuilder)
3077 : mBuilder(aBuilder) {
3078 aBuilder->Check();
3079 }
3080
3081 ~AutoCheckBuilder() { mBuilder->Check(); }
3082
3083 nsDisplayListBuilder* mBuilder;
3084};
3085
3086/**
3087 * Tries to reuse a top-level stacking context item from the previous paint.
3088 * Returns true if an item was reused, otherwise false.
3089 */
3090bool TryToReuseStackingContextItem(nsDisplayListBuilder* aBuilder,
3091 nsDisplayList* aList, nsIFrame* aFrame) {
3092 if (!aBuilder->IsForPainting() || !aBuilder->IsPartialUpdate() ||
3093 aBuilder->InInvalidSubtree()) {
3094 return false;
3095 }
3096
3097 if (aFrame->IsFrameModified() || aFrame->HasModifiedDescendants()) {
3098 return false;
3099 }
3100
3101 auto& items = aFrame->DisplayItems();
3102 auto* res = std::find_if(
3103 items.begin(), items.end(),
3104 [](nsDisplayItem* aItem) { return aItem->IsPreProcessed(); });
3105
3106 if (res == items.end()) {
3107 return false;
3108 }
3109
3110 nsDisplayItem* container = *res;
3111 MOZ_ASSERT(container->Frame() == aFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(container->Frame() == aFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(container->Frame() == aFrame
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"container->Frame() == aFrame", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "container->Frame() == aFrame"
")"); do { *((volatile int*)__null) = 3111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3112 DL_LOGD("RDL - Found SC item %p (%s) (frame: %p)", container,do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "RDL - Found SC item %p (%s) (frame: %p)",
container, container->Name(), container->Frame()); } }
while (0)
3113 container->Name(), container->Frame())do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "RDL - Found SC item %p (%s) (frame: %p)",
container, container->Name(), container->Frame()); } }
while (0)
;
3114
3115 aList->AppendToTop(container);
3116 aBuilder->ReuseDisplayItem(container);
3117 return true;
3118}
3119
3120void nsIFrame::BuildDisplayListForStackingContext(
3121 nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
3122 bool* aCreatedContainerItem) {
3123#ifdef DEBUG1
3124 DL_LOGV("BuildDisplayListForStackingContext (%p) <", this)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "BuildDisplayListForStackingContext (%p) <"
, this); } } while (0)
;
3125 ScopeExit e(
3126 [this]() { DL_LOGV("> BuildDisplayListForStackingContext (%p)", this)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "> BuildDisplayListForStackingContext (%p)"
, this); } } while (0)
; });
3127#endif
3128
3129 AutoCheckBuilder check(aBuilder);
3130
3131 if (aBuilder->IsReusingStackingContextItems() &&
3132 TryToReuseStackingContextItem(aBuilder, aList, this)) {
3133 if (aCreatedContainerItem) {
3134 *aCreatedContainerItem = true;
3135 }
3136 return;
3137 }
3138
3139 if (HasAnyStateBits(NS_FRAME_TOO_DEEP_IN_FRAME_TREE)) {
3140 return;
3141 }
3142
3143 const auto& style = *Style();
3144 const nsStyleDisplay* disp = style.StyleDisplay();
3145 const nsStyleEffects* effects = style.StyleEffects();
3146 EffectSet* effectSetForOpacity =
3147 EffectSet::GetForFrame(this, nsCSSPropertyIDSet::OpacityProperties());
3148 // We can stop right away if this is a zero-opacity stacking context and
3149 // we're painting, and we're not animating opacity.
3150 bool needHitTestInfo = aBuilder->BuildCompositorHitTestInfo() &&
3151 Style()->PointerEvents() != StylePointerEvents::None;
3152 bool opacityItemForEventsOnly = false;
3153 if (effects->IsTransparent() && aBuilder->IsForPainting() &&
3154 !(disp->mWillChange.bits & StyleWillChangeBits::OPACITY) &&
3155 !nsLayoutUtils::HasAnimationOfPropertySet(
3156 this, nsCSSPropertyIDSet::OpacityProperties(), effectSetForOpacity)) {
3157 if (needHitTestInfo) {
3158 opacityItemForEventsOnly = true;
3159 } else {
3160 return;
3161 }
3162 }
3163
3164 if (aBuilder->IsForPainting() && disp->mWillChange.bits) {
3165 aBuilder->AddToWillChangeBudget(this, GetSize());
3166 }
3167
3168 // For preserves3d, use the dirty rect already installed on the
3169 // builder, since aDirtyRect maybe distorted for transforms along
3170 // the chain.
3171 nsRect visibleRect = aBuilder->GetVisibleRect();
3172 nsRect dirtyRect = aBuilder->GetDirtyRect();
3173
3174 // We build an opacity item if it's not going to be drawn by SVG content.
3175 // We could in principle skip creating an nsDisplayOpacity item if
3176 // nsDisplayOpacity::NeedsActiveLayer returns false and usingSVGEffects is
3177 // true (the nsDisplayFilter/nsDisplayMasksAndClipPaths could handle the
3178 // opacity). Since SVG has perf issues where we sometimes spend a lot of
3179 // time creating display list items that might be helpful. We'd need to
3180 // restore our mechanism to do that (changed in bug 1482403), and we'd
3181 // need to invalidate the frame if the value that would be return from
3182 // NeedsActiveLayer was to change, which we don't currently do.
3183 const bool useOpacity =
3184 HasVisualOpacity(disp, effects, effectSetForOpacity) &&
3185 !SVGUtils::CanOptimizeOpacity(this);
3186
3187 const bool isTransformed = IsTransformed();
3188 const bool hasPerspective = isTransformed && HasPerspective();
3189 const bool extend3DContext =
3190 Extend3DContext(disp, effects, effectSetForOpacity);
3191 const bool combines3DTransformWithAncestors =
3192 (extend3DContext || isTransformed) && Combines3DTransformWithAncestors();
3193
3194 Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
3195 if (extend3DContext && !combines3DTransformWithAncestors) {
3196 // Start a new preserves3d context to keep informations on
3197 // nsDisplayListBuilder.
3198 autoPreserves3DContext.emplace(aBuilder);
3199 // Save dirty rect on the builder to avoid being distorted for
3200 // multiple transforms along the chain.
3201 aBuilder->SavePreserves3DRect();
3202
3203 // We rebuild everything within preserve-3d and don't try
3204 // to retain, so override the dirty rect now.
3205 if (aBuilder->IsRetainingDisplayList()) {
3206 dirtyRect = visibleRect;
3207 aBuilder->SetDisablePartialUpdates(true);
3208 }
3209 }
3210
3211 const bool useBlendMode = effects->mMixBlendMode != StyleBlend::Normal;
3212 if (useBlendMode) {
3213 aBuilder->SetContainsBlendMode(true);
3214 }
3215
3216 // reset blend mode so we can keep track if this stacking context needs have
3217 // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
3218 // so we keep track if the parent stacking context needs a container too.
3219 AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
3220 aBuilder->SetContainsBlendMode(false);
3221
3222 // NOTE: When changing this condition make sure to tweak nsGfxScrollFrame as
3223 // well.
3224 bool usingBackdropFilter = effects->HasBackdropFilters() &&
3225 IsVisibleForPainting() &&
3226 !style.IsRootElementStyle();
3227
3228 nsRect visibleRectOutsideTransform = visibleRect;
3229 nsDisplayTransform::PrerenderInfo prerenderInfo;
3230 bool inTransform = aBuilder->IsInTransform();
3231 if (isTransformed) {
3232 prerenderInfo = nsDisplayTransform::ShouldPrerenderTransformedContent(
3233 aBuilder, this, &visibleRect);
3234
3235 switch (prerenderInfo.mDecision) {
3236 case nsDisplayTransform::PrerenderDecision::Full:
3237 case nsDisplayTransform::PrerenderDecision::Partial:
3238 dirtyRect = visibleRect;
3239 break;
3240 case nsDisplayTransform::PrerenderDecision::No: {
3241 // If we didn't prerender an animated frame in a preserve-3d context,
3242 // then we want disable async animations for the rest of the preserve-3d
3243 // (especially ancestors).
3244 if ((extend3DContext || combines3DTransformWithAncestors) &&
3245 prerenderInfo.mHasAnimations) {
3246 aBuilder->SavePreserves3DAllowAsyncAnimation(false);
3247 }
3248
3249 const nsRect overflow = InkOverflowRectRelativeToSelf();
3250 if (overflow.IsEmpty() && !extend3DContext) {
3251 return;
3252 }
3253
3254 // If we're in preserve-3d then grab the dirty rect that was given to
3255 // the root and transform using the combined transform.
3256 if (combines3DTransformWithAncestors) {
3257 visibleRect = dirtyRect = aBuilder->GetPreserves3DRect();
3258 }
3259
3260 float appPerDev = PresContext()->AppUnitsPerDevPixel();
3261 auto transform = nsDisplayTransform::GetResultingTransformMatrix(
3262 this, nsPoint(), appPerDev,
3263 nsDisplayTransform::kTransformRectFlags);
3264 nsRect untransformedDirtyRect;
3265 if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, transform,
3266 appPerDev,
3267 &untransformedDirtyRect)) {
3268 dirtyRect = untransformedDirtyRect;
3269 nsDisplayTransform::UntransformRect(visibleRect, overflow, transform,
3270 appPerDev, &visibleRect);
3271 } else {
3272 // This should only happen if the transform is singular, in which case
3273 // nothing is visible anyway
3274 dirtyRect.SetEmpty();
3275 visibleRect.SetEmpty();
3276 }
3277 }
3278 }
3279 inTransform = true;
3280 } else if (IsFixedPosContainingBlock()) {
3281 // Restict the building area to the overflow rect for these frames, since
3282 // RetainedDisplayListBuilder uses it to know if the size of the stacking
3283 // context changed.
3284 visibleRect.IntersectRect(visibleRect, InkOverflowRect());
3285 dirtyRect.IntersectRect(dirtyRect, InkOverflowRect());
3286 }
3287
3288 bool hasOverrideDirtyRect = false;
3289 // If we're doing a partial build, we're not invalid and we're capable
3290 // of having an override building rect (stacking context and fixed pos
3291 // containing block), then we should assume we have one.
3292 // Either we have an explicit one, or nothing in our subtree changed and
3293 // we have an implicit empty rect.
3294 //
3295 // These conditions should match |CanStoreDisplayListBuildingRect()| in
3296 // RetainedDisplayListBuilder.cpp
3297 if (!aBuilder->IsReusingStackingContextItems() &&
3298 aBuilder->IsPartialUpdate() && !aBuilder->InInvalidSubtree() &&
3299 !IsFrameModified() && IsFixedPosContainingBlock() &&
3300 !GetPrevContinuation() && !GetNextContinuation()) {
3301 dirtyRect = nsRect();
3302 if (HasOverrideDirtyRegion()) {
3303 nsDisplayListBuilder::DisplayListBuildingData* data =
3304 GetProperty(nsDisplayListBuilder::DisplayListBuildingRect());
3305 if (data) {
3306 dirtyRect = data->mDirtyRect.Intersect(visibleRect);
3307 hasOverrideDirtyRect = true;
3308 }
3309 }
3310 }
3311
3312 bool usingFilter = effects->HasFilters() && !style.IsRootElementStyle();
3313 SVGUtils::MaskUsage maskUsage = SVGUtils::DetermineMaskUsage(this, false);
3314 bool usingMask = maskUsage.UsingMaskOrClipPath();
3315 bool usingSVGEffects = usingFilter || usingMask;
3316
3317 nsRect visibleRectOutsideSVGEffects = visibleRect;
3318 nsDisplayList hoistedScrollInfoItemsStorage(aBuilder);
3319 if (usingSVGEffects) {
3320 dirtyRect =
3321 SVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
3322 visibleRect =
3323 SVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, visibleRect);
3324 aBuilder->EnterSVGEffectsContents(this, &hoistedScrollInfoItemsStorage);
3325 }
3326
3327 bool useStickyPosition = disp->mPosition == StylePositionProperty::Sticky;
3328
3329 bool useFixedPosition =
3330 disp->mPosition == StylePositionProperty::Fixed &&
3331 (DisplayPortUtils::IsFixedPosFrameInDisplayPort(this) ||
3332 BuilderHasScrolledClip(aBuilder));
3333
3334 nsDisplayListBuilder::AutoBuildingDisplayList buildingDisplayList(
3335 aBuilder, this, visibleRect, dirtyRect, isTransformed);
3336
3337 UpdateCurrentHitTestInfo(aBuilder, this);
3338
3339 // Depending on the effects that are applied to this frame, we can create
3340 // multiple container display items and wrap them around our contents.
3341 // This enum lists all the potential container display items, in the order
3342 // outside to inside.
3343 enum class ContainerItemType : uint8_t {
3344 None = 0,
3345 OwnLayerIfNeeded,
3346 BlendMode,
3347 FixedPosition,
3348 OwnLayerForTransformWithRoundedClip,
3349 Perspective,
3350 Transform,
3351 SeparatorTransforms,
3352 Opacity,
3353 Filter,
3354 BlendContainer
3355 };
3356
3357 nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
3358
3359 auto cssClip = GetClipPropClipRect(disp, effects, GetSize());
3360 auto ApplyClipProp = [&](DisplayListClipState::AutoSaveRestore& aClipState) {
3361 if (!cssClip) {
3362 return;
3363 }
3364 nsPoint offset = aBuilder->GetCurrentFrameOffsetToReferenceFrame();
3365 aBuilder->IntersectDirtyRect(*cssClip);
3366 aBuilder->IntersectVisibleRect(*cssClip);
3367 aClipState.ClipContentDescendants(*cssClip + offset);
3368 };
3369
3370 // The CSS clip property is effectively inside the transform, but outside the
3371 // filters. So if we're not transformed we can apply it just here for
3372 // simplicity, instead of on each of the places that handle clipCapturedBy.
3373 DisplayListClipState::AutoSaveRestore untransformedCssClip(aBuilder);
3374 if (!isTransformed) {
3375 ApplyClipProp(untransformedCssClip);
3376 }
3377
3378 // If there is a current clip, then depending on the container items we
3379 // create, different things can happen to it. Some container items simply
3380 // propagate the clip to their children and aren't clipped themselves.
3381 // But other container items, especially those that establish a different
3382 // geometry for their contents (e.g. transforms), capture the clip on
3383 // themselves and unset the clip for their contents. If we create more than
3384 // one of those container items, the clip will be captured on the outermost
3385 // one and the inner container items will be unclipped.
3386 ContainerItemType clipCapturedBy = ContainerItemType::None;
3387 if (useFixedPosition) {
3388 clipCapturedBy = ContainerItemType::FixedPosition;
3389 } else if (isTransformed) {
3390 const DisplayItemClipChain* currentClip =
3391 aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
3392 if ((hasPerspective || extend3DContext) &&
3393 (currentClip && currentClip->HasRoundedCorners())) {
3394 // If we're creating an nsDisplayTransform item that is going to combine
3395 // its transform with its children (preserve-3d or perspective), then we
3396 // can't have an intermediate surface. Mask layers force an intermediate
3397 // surface, so if we're going to need both then create a separate
3398 // wrapping layer for the mask.
3399 clipCapturedBy = ContainerItemType::OwnLayerForTransformWithRoundedClip;
3400 } else if (hasPerspective) {
3401 clipCapturedBy = ContainerItemType::Perspective;
3402 } else {
3403 clipCapturedBy = ContainerItemType::Transform;
3404 }
3405 } else if (usingFilter) {
3406 clipCapturedBy = ContainerItemType::Filter;
3407 }
3408
3409 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
3410 if (clipCapturedBy != ContainerItemType::None) {
3411 clipState.Clear();
3412 }
3413
3414 DisplayListClipState::AutoSaveRestore transformedCssClip(aBuilder);
3415 if (isTransformed) {
3416 // FIXME(emilio, bug 1525159): In the case we have a both a transform _and_
3417 // filters, this clips the input to the filters as well, which is not
3418 // correct (clipping by the `clip` property is supposed to happen after
3419 // applying the filter effects, per [1].
3420 //
3421 // This is not a regression though, since we used to do that anyway before
3422 // bug 1514384, and even without the transform we get it wrong.
3423 //
3424 // [1]: https://drafts.fxtf.org/css-masking/#placement
3425 ApplyClipProp(transformedCssClip);
3426 }
3427
3428 uint32_t numActiveScrollframesEncounteredBefore =
3429 aBuilder->GetNumActiveScrollframesEncountered();
3430
3431 nsDisplayListCollection set(aBuilder);
3432 Maybe<nsRect> clipForMask;
3433 {
3434 DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
3435 nsDisplayListBuilder::AutoInTransformSetter inTransformSetter(aBuilder,
3436 inTransform);
3437 nsDisplayListBuilder::AutoEnterFilter filterASRSetter(aBuilder,
3438 usingFilter);
3439 nsDisplayListBuilder::AutoInEventsOnly inEventsSetter(
3440 aBuilder, opacityItemForEventsOnly);
3441
3442 // If we have a mask, compute a clip to bound the masked content.
3443 // This is necessary in case the content moves with an ancestor
3444 // ASR of the mask.
3445 // Don't do this if we also have a filter, because then the clip
3446 // would be applied before the filter, violating
3447 // https://www.w3.org/TR/filter-effects-1/#placement.
3448 // Filters are a containing block for fixed and absolute descendants,
3449 // so the masked content cannot move with an ancestor ASR.
3450 if (usingMask && !usingFilter) {
3451 clipForMask = ComputeClipForMaskItem(aBuilder, this, maskUsage);
3452 if (clipForMask) {
3453 aBuilder->IntersectDirtyRect(*clipForMask);
3454 aBuilder->IntersectVisibleRect(*clipForMask);
3455 nestedClipState.ClipContentDescendants(
3456 *clipForMask + aBuilder->GetCurrentFrameOffsetToReferenceFrame());
3457 }
3458 }
3459
3460 // extend3DContext also guarantees that applyAbsPosClipping and
3461 // usingSVGEffects are false We only modify the preserve-3d rect if we are
3462 // the top of a preserve-3d heirarchy
3463 if (extend3DContext) {
3464 // Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
3465 // going to be forced to descend into frames.
3466 aBuilder->MarkPreserve3DFramesForDisplayList(this);
3467 }
3468
3469 aBuilder->AdjustWindowDraggingRegion(this);
3470
3471 MarkAbsoluteFramesForDisplayList(aBuilder);
3472 aBuilder->Check();
3473 BuildDisplayList(aBuilder, set);
3474 SetBuiltDisplayList(true);
3475 aBuilder->Check();
3476 aBuilder->DisplayCaret(this, set.Outlines());
3477
3478 // Blend modes are a real pain for retained display lists. We build a blend
3479 // container item if the built list contains any blend mode items within
3480 // the current stacking context. This can change without an invalidation
3481 // to the stacking context frame, or the blend mode frame (e.g. by moving
3482 // an intermediate frame).
3483 // When we gain/remove a blend container item, we need to mark this frame
3484 // as invalid and have the full display list for merging to track
3485 // the change correctly.
3486 // It seems really hard to track this in advance, as the bookkeeping
3487 // required to note which stacking contexts have blend descendants
3488 // is complex and likely to be buggy.
3489 // Instead we're doing the sad thing, detecting it afterwards, and just
3490 // repeating display list building if it changed.
3491 // We have to repeat building for the entire display list (or at least
3492 // the outer stacking context), since we need to mark this frame as invalid
3493 // to remove any existing content that isn't wrapped in the blend container,
3494 // and then we need to build content infront/behind the blend container
3495 // to get correct positioning during merging.
3496 if (aBuilder->ContainsBlendMode() && aBuilder->IsRetainingDisplayList()) {
3497 if (aBuilder->IsPartialUpdate()) {
3498 aBuilder->SetPartialBuildFailed(true);
3499 } else {
3500 aBuilder->SetDisablePartialUpdates(true);
3501 }
3502 }
3503 }
3504
3505 if (aBuilder->IsBackgroundOnly()) {
3506 set.BlockBorderBackgrounds()->DeleteAll(aBuilder);
3507 set.Floats()->DeleteAll(aBuilder);
3508 set.Content()->DeleteAll(aBuilder);
3509 set.PositionedDescendants()->DeleteAll(aBuilder);
3510 set.Outlines()->DeleteAll(aBuilder);
3511 }
3512
3513 if (hasOverrideDirtyRect &&
3514 StaticPrefs::layout_display_list_show_rebuild_area()) {
3515 nsDisplaySolidColor* color = MakeDisplayItem<nsDisplaySolidColor>(
3516 aBuilder, this,
3517 dirtyRect + aBuilder->GetCurrentFrameOffsetToReferenceFrame(),
3518 NS_RGBA(255, 0, 0, 64)((nscolor)(((64) << 24) | ((0) << 16) | ((0) <<
8) | (255)))
, false);
3519 if (color) {
3520 color->SetOverrideZIndex(INT32_MAX(2147483647));
3521 set.PositionedDescendants()->AppendToTop(color);
3522 }
3523 }
3524
3525 nsIContent* content = GetContent();
3526 if (!content) {
3527 content = PresContext()->Document()->GetRootElement();
3528 }
3529
3530 nsDisplayList resultList(aBuilder);
3531 set.SerializeWithCorrectZOrder(&resultList, content);
3532
3533 // Get the ASR to use for the container items that we create here.
3534 const ActiveScrolledRoot* containerItemASR = contASRTracker.GetContainerASR();
3535
3536 bool createdContainer = false;
3537
3538 // If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
3539 // same list, the nsDisplayBlendContainer should be added first. This only
3540 // happens when the element creating this stacking context has mix-blend-mode
3541 // and also contains a child which has mix-blend-mode.
3542 // The nsDisplayBlendContainer must be added to the list first, so it does not
3543 // isolate the containing element blending as well.
3544 if (aBuilder->ContainsBlendMode()) {
3545 resultList.AppendToTop(nsDisplayBlendContainer::CreateForMixBlendMode(
3546 aBuilder, this, &resultList, containerItemASR));
3547 createdContainer = true;
3548 }
3549
3550 if (usingBackdropFilter) {
3551 nsRect backdropRect =
3552 GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
3553 resultList.AppendNewToTop<nsDisplayBackdropFilters>(
3554 aBuilder, this, &resultList, backdropRect, this);
3555 createdContainer = true;
3556 }
3557
3558 // If there are any SVG effects, wrap the list up in an SVG effects item
3559 // (which also handles CSS group opacity). Note that we create an SVG effects
3560 // item even if resultList is empty, since a filter can produce graphical
3561 // output even if the element being filtered wouldn't otherwise do so.
3562 if (usingSVGEffects) {
3563 MOZ_ASSERT(usingFilter || usingMask,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(usingFilter || usingMask)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(usingFilter || usingMask))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("usingFilter || usingMask"
" (" "Beside filter & mask/clip-path, what else effect do we have?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usingFilter || usingMask"
") (" "Beside filter & mask/clip-path, what else effect do we have?"
")"); do { *((volatile int*)__null) = 3564; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3564 "Beside filter & mask/clip-path, what else effect do we have?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(usingFilter || usingMask)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(usingFilter || usingMask))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("usingFilter || usingMask"
" (" "Beside filter & mask/clip-path, what else effect do we have?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usingFilter || usingMask"
") (" "Beside filter & mask/clip-path, what else effect do we have?"
")"); do { *((volatile int*)__null) = 3564; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3565
3566 if (clipCapturedBy == ContainerItemType::Filter) {
3567 clipState.Restore();
3568 }
3569 // Revert to the post-filter dirty rect.
3570 aBuilder->SetVisibleRect(visibleRectOutsideSVGEffects);
3571
3572 // Skip all filter effects while generating glyph mask.
3573 if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
3574 /* List now emptied, so add the new list to the top. */
3575 resultList.AppendNewToTop<nsDisplayFilters>(aBuilder, this, &resultList,
3576 this, usingBackdropFilter);
3577 createdContainer = true;
Value stored to 'createdContainer' is never read
3578 }
3579
3580 if (usingMask) {
3581 // The mask should move with aBuilder->CurrentActiveScrolledRoot(), so
3582 // that's the ASR we prefer to use for the mask item. However, we can
3583 // only do this if the mask if clipped with respect to that ASR, because
3584 // an item always needs to have finite bounds with respect to its ASR.
3585 // If we weren't able to compute a clip for the mask, we fall back to
3586 // using containerItemASR, which is the lowest common ancestor clip of
3587 // the mask's contents. That's not entirely correct, but it satisfies
3588 // the base requirement of the ASR system (that items have finite bounds
3589 // wrt. their ASR).
3590 const ActiveScrolledRoot* maskASR =
3591 clipForMask.isSome() ? aBuilder->CurrentActiveScrolledRoot()
3592 : containerItemASR;
3593 /* List now emptied, so add the new list to the top. */
3594 resultList.AppendNewToTop<nsDisplayMasksAndClipPaths>(
3595 aBuilder, this, &resultList, maskASR, usingBackdropFilter);
3596 createdContainer = true;
3597 }
3598
3599 // TODO(miko): We could probably create a wraplist here and avoid creating
3600 // it later in |BuildDisplayListForChild()|.
3601 createdContainer = false;
3602
3603 // Also add the hoisted scroll info items. We need those for APZ scrolling
3604 // because nsDisplayMasksAndClipPaths items can't build active layers.
3605 aBuilder->ExitSVGEffectsContents();
3606 resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
3607 }
3608
3609 // If the list is non-empty and there is CSS group opacity without SVG
3610 // effects, wrap it up in an opacity item.
3611 if (useOpacity) {
3612 const bool needsActiveOpacityLayer =
3613 nsDisplayOpacity::NeedsActiveLayer(aBuilder, this);
3614 resultList.AppendNewToTop<nsDisplayOpacity>(
3615 aBuilder, this, &resultList, containerItemASR, opacityItemForEventsOnly,
3616 needsActiveOpacityLayer, usingBackdropFilter);
3617 createdContainer = true;
3618 }
3619
3620 // If we're going to apply a transformation and don't have preserve-3d set,
3621 // wrap everything in an nsDisplayTransform. If there's nothing in the list,
3622 // don't add anything.
3623 //
3624 // For the preserve-3d case we want to individually wrap every child in the
3625 // list with a separate nsDisplayTransform instead. When the child is already
3626 // an nsDisplayTransform, we can skip this step, as the computed transform
3627 // will already include our own.
3628 //
3629 // We also traverse into sublists created by nsDisplayWrapList, so that we
3630 // find all the correct children.
3631 if (isTransformed && extend3DContext) {
3632 // Install dummy nsDisplayTransform as a leaf containing
3633 // descendants not participating this 3D rendering context.
3634 nsDisplayList nonparticipants(aBuilder);
3635 nsDisplayList participants(aBuilder);
3636 int index = 1;
3637
3638 nsDisplayItem* separator = nullptr;
3639
3640 // TODO: This can be simplified: |participants| is just |resultList|.
3641 for (nsDisplayItem* item : resultList.TakeItems()) {
3642 if (ItemParticipatesIn3DContext(this, item) &&
3643 !item->GetClip().HasClip()) {
3644 // The frame of this item participates the same 3D context.
3645 WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants,
3646 index++, &separator);
3647
3648 participants.AppendToTop(item);
3649 } else {
3650 // The frame of the item doesn't participate the current
3651 // context, or has no transform.
3652 //
3653 // For items participating but not transformed, they are add
3654 // to nonparticipants to get a separator layer for handling
3655 // clips, if there is, on an intermediate surface.
3656 // \see ContainerLayer::DefaultComputeEffectiveTransforms().
3657 nonparticipants.AppendToTop(item);
3658 }
3659 }
3660 WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants,
3661 index++, &separator);
3662
3663 if (separator) {
3664 createdContainer = true;
3665 }
3666
3667 resultList.AppendToTop(&participants);
3668 }
3669
3670 if (isTransformed) {
3671 transformedCssClip.Restore();
3672 if (clipCapturedBy == ContainerItemType::Transform) {
3673 // Restore clip state now so nsDisplayTransform is clipped properly.
3674 clipState.Restore();
3675 }
3676 // Revert to the dirtyrect coming in from the parent, without our transform
3677 // taken into account.
3678 aBuilder->SetVisibleRect(visibleRectOutsideTransform);
3679
3680 if (this != aBuilder->RootReferenceFrame()) {
3681 // Revert to the outer reference frame and offset because all display
3682 // items we create from now on are outside the transform.
3683 nsPoint toOuterReferenceFrame;
3684 const nsIFrame* outerReferenceFrame =
3685 aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame);
3686 toOuterReferenceFrame += GetPosition();
3687
3688 buildingDisplayList.SetReferenceFrameAndCurrentOffset(
3689 outerReferenceFrame, toOuterReferenceFrame);
3690 }
3691
3692 // We would like to block async animations for ancestors of ones not
3693 // prerendered in the preserve-3d tree. Now that we've finished processing
3694 // all descendants, update allowAsyncAnimation to take their prerender
3695 // state into account
3696 // FIXME: We don't block async animations for previous siblings because
3697 // their prerender decisions have been made. We may have to figure out a
3698 // better way to rollback their prerender decisions.
3699 // Alternatively we could not block animations for later siblings, and only
3700 // block them for ancestors of a blocked one.
3701 if ((extend3DContext || combines3DTransformWithAncestors) &&
3702 prerenderInfo.CanUseAsyncAnimations() &&
3703 !aBuilder->GetPreserves3DAllowAsyncAnimation()) {
3704 // aBuilder->GetPreserves3DAllowAsyncAnimation() means the inner or
3705 // previous silbing frames are allowed/disallowed for async animations.
3706 prerenderInfo.mDecision = nsDisplayTransform::PrerenderDecision::No;
3707 }
3708
3709 nsDisplayTransform* transformItem = MakeDisplayItem<nsDisplayTransform>(
3710 aBuilder, this, &resultList, visibleRect, prerenderInfo.mDecision);
3711 if (transformItem) {
3712 resultList.AppendToTop(transformItem);
3713 createdContainer = true;
3714
3715 if (numActiveScrollframesEncounteredBefore !=
3716 aBuilder->GetNumActiveScrollframesEncountered()) {
3717 transformItem->SetContainsASRs(true);
3718 }
3719
3720 if (hasPerspective) {
3721 transformItem->MarkWithAssociatedPerspective();
3722
3723 if (clipCapturedBy == ContainerItemType::Perspective) {
3724 clipState.Restore();
3725 }
3726 resultList.AppendNewToTop<nsDisplayPerspective>(aBuilder, this,
3727 &resultList);
3728 createdContainer = true;
3729 }
3730 }
3731 }
3732
3733 if (clipCapturedBy ==
3734 ContainerItemType::OwnLayerForTransformWithRoundedClip) {
3735 clipState.Restore();
3736 resultList.AppendNewToTopWithIndex<nsDisplayOwnLayer>(
3737 aBuilder, this,
3738 /* aIndex = */ nsDisplayOwnLayer::OwnLayerForTransformWithRoundedClip,
3739 &resultList, aBuilder->CurrentActiveScrolledRoot(),
3740 nsDisplayOwnLayerFlags::None, ScrollbarData{},
3741 /* aForceActive = */ false, false);
3742 createdContainer = true;
3743 }
3744
3745 // If we have sticky positioning, wrap it in a sticky position item.
3746 if (useFixedPosition) {
3747 if (clipCapturedBy == ContainerItemType::FixedPosition) {
3748 clipState.Restore();
3749 }
3750 // The ASR for the fixed item should be the ASR of our containing block,
3751 // which has been set as the builder's current ASR, unless this frame is
3752 // invisible and we hadn't saved display item data for it. In that case,
3753 // we need to take the containerItemASR since we might have fixed children.
3754 // For WebRender, we want to the know what |containerItemASR| is for the
3755 // case where the fixed-pos item is not a "real" fixed-pos item (e.g. it's
3756 // nested inside a scrolling transform), so we stash that on the display
3757 // item as well.
3758 const ActiveScrolledRoot* fixedASR = ActiveScrolledRoot::PickAncestor(
3759 containerItemASR, aBuilder->CurrentActiveScrolledRoot());
3760 resultList.AppendNewToTop<nsDisplayFixedPosition>(
3761 aBuilder, this, &resultList, fixedASR, containerItemASR);
3762 createdContainer = true;
3763 } else if (useStickyPosition) {
3764 // For position:sticky, the clip needs to be applied both to the sticky
3765 // container item and to the contents. The container item needs the clip
3766 // because a scrolled clip needs to move independently from the sticky
3767 // contents, and the contents need the clip so that they have finite
3768 // clipped bounds with respect to the container item's ASR. The latter is
3769 // a little tricky in the case where the sticky item has both fixed and
3770 // non-fixed descendants, because that means that the sticky container
3771 // item's ASR is the ASR of the fixed descendant.
3772 // For WebRender display list building, though, we still want to know the
3773 // the ASR that the sticky container item would normally have, so we stash
3774 // that on the display item as the "container ASR" (i.e. the normal ASR of
3775 // the container item, excluding the special behaviour induced by fixed
3776 // descendants).
3777 const ActiveScrolledRoot* stickyASR = ActiveScrolledRoot::PickAncestor(
3778 containerItemASR, aBuilder->CurrentActiveScrolledRoot());
3779
3780 auto* stickyItem = MakeDisplayItem<nsDisplayStickyPosition>(
3781 aBuilder, this, &resultList, stickyASR,
3782 aBuilder->CurrentActiveScrolledRoot(),
3783 clipState.IsClippedToDisplayPort());
3784
3785 bool shouldFlatten = true;
3786
3787 StickyScrollContainer* stickyScrollContainer =
3788 StickyScrollContainer::GetStickyScrollContainerForFrame(this);
3789 if (stickyScrollContainer &&
3790 stickyScrollContainer->ScrollFrame()->IsMaybeAsynchronouslyScrolled()) {
3791 shouldFlatten = false;
3792 }
3793
3794 stickyItem->SetShouldFlatten(shouldFlatten);
3795
3796 resultList.AppendToTop(stickyItem);
3797 createdContainer = true;
3798
3799 // If the sticky element is inside a filter, annotate the scroll frame that
3800 // scrolls the filter as having out-of-flow content inside a filter (this
3801 // inhibits paint skipping).
3802 if (aBuilder->GetFilterASR() && aBuilder->GetFilterASR() == stickyASR) {
3803 aBuilder->GetFilterASR()
3804 ->mScrollableFrame->SetHasOutOfFlowContentInsideFilter();
3805 }
3806 }
3807
3808 // If there's blending, wrap up the list in a blend-mode item. Note that
3809 // opacity can be applied before blending as the blend color is not affected
3810 // by foreground opacity (only background alpha).
3811 if (useBlendMode) {
3812 DisplayListClipState::AutoSaveRestore blendModeClipState(aBuilder);
3813 resultList.AppendNewToTop<nsDisplayBlendMode>(aBuilder, this, &resultList,
3814 effects->mMixBlendMode,
3815 containerItemASR, false);
3816 createdContainer = true;
3817 }
3818
3819 if (aBuilder->IsReusingStackingContextItems()) {
3820 if (resultList.IsEmpty()) {
3821 return;
3822 }
3823
3824 nsDisplayItem* container = resultList.GetBottom();
3825 if (resultList.Length() > 1 || container->Frame() != this) {
3826 container = MakeDisplayItem<nsDisplayContainer>(
3827 aBuilder, this, containerItemASR, &resultList);
3828 } else {
3829 MOZ_ASSERT(resultList.Length() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(resultList.Length() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(resultList.Length() == 1))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("resultList.Length() == 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "resultList.Length() == 1"
")"); do { *((volatile int*)__null) = 3829; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3830 resultList.Clear();
3831 }
3832
3833 // Mark the outermost display item as reusable. These display items and
3834 // their chidren can be reused during the next paint if no ancestor or
3835 // descendant frames have been modified.
3836 if (!container->IsReusedItem()) {
3837 container->SetReusable();
3838 }
3839 aList->AppendToTop(container);
3840 createdContainer = true;
3841 } else {
3842 aList->AppendToTop(&resultList);
3843 }
3844
3845 if (aCreatedContainerItem) {
3846 *aCreatedContainerItem = createdContainer;
3847 }
3848}
3849
3850static nsDisplayItem* WrapInWrapList(nsDisplayListBuilder* aBuilder,
3851 nsIFrame* aFrame, nsDisplayList* aList,
3852 const ActiveScrolledRoot* aContainerASR,
3853 bool aBuiltContainerItem = false) {
3854 nsDisplayItem* item = aList->GetBottom();
3855 if (!item) {
3856 return nullptr;
3857 }
3858
3859 // We need a wrap list if there are multiple items, or if the single
3860 // item has a different frame. This can change in a partial build depending
3861 // on which items we build, so we need to ensure that we don't transition
3862 // to/from a wrap list without invalidating correctly.
3863 bool needsWrapList =
3864 aList->Length() > 1 || item->Frame() != aFrame || item->GetChildren();
3865
3866 // If we have an explicit container item (that can't change without an
3867 // invalidation) or we're doing a full build and don't need a wrap list, then
3868 // we can skip adding one.
3869 if (aBuiltContainerItem || (!aBuilder->IsPartialUpdate() && !needsWrapList)) {
3870 MOZ_ASSERT(aList->Length() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aList->Length() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aList->Length() == 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aList->Length() == 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aList->Length() == 1"
")"); do { *((volatile int*)__null) = 3870; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3871 aList->Clear();
3872 return item;
3873 }
3874
3875 // If we're doing a partial build and we didn't need a wrap list
3876 // previously then we can try to work from there.
3877 if (aBuilder->IsPartialUpdate() &&
3878 !aFrame->HasDisplayItem(uint32_t(DisplayItemType::TYPE_CONTAINER))) {
3879 // If we now need a wrap list, we must previously have had no display items
3880 // or a single one belonging to this frame. Mark the item itself as
3881 // discarded so that RetainedDisplayListBuilder uses the ones we just built.
3882 // We don't want to mark the frame as modified as that would invalidate
3883 // positioned descendants that might be outside of this list, and might not
3884 // have been rebuilt this time.
3885 if (needsWrapList) {
3886 DiscardOldItems(aFrame);
3887 } else {
3888 MOZ_ASSERT(aList->Length() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aList->Length() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aList->Length() == 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aList->Length() == 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aList->Length() == 1"
")"); do { *((volatile int*)__null) = 3888; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3889 aList->Clear();
3890 return item;
3891 }
3892 }
3893
3894 // The last case we could try to handle is when we previously had a wrap list,
3895 // but no longer need it. Unfortunately we can't differentiate this case from
3896 // a partial build where other children exist but we just didn't build them
3897 // this time.
3898 // TODO:RetainedDisplayListBuilder's merge phase has the full list and
3899 // could strip them out.
3900
3901 return MakeDisplayItem<nsDisplayContainer>(aBuilder, aFrame, aContainerASR,
3902 aList);
3903}
3904
3905/**
3906 * Check if a frame should be visited for building display list.
3907 */
3908static bool DescendIntoChild(nsDisplayListBuilder* aBuilder,
3909 const nsIFrame* aChild, const nsRect& aVisible,
3910 const nsRect& aDirty) {
3911 if (aChild->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
3912 return true;
3913 }
3914
3915 // If the child is a scrollframe that we want to ignore, then we need
3916 // to descend into it because its scrolled child may intersect the dirty
3917 // area even if the scrollframe itself doesn't.
3918 if (aChild == aBuilder->GetIgnoreScrollFrame()) {
3919 return true;
3920 }
3921
3922 // There are cases where the "ignore scroll frame" on the builder is not set
3923 // correctly, and so we additionally want to catch cases where the child is
3924 // a root scrollframe and we are ignoring scrolling on the viewport.
3925 if (aChild == aBuilder->GetPresShellIgnoreScrollFrame()) {
3926 return true;
3927 }
3928
3929 nsRect overflow = aChild->InkOverflowRect();
3930
3931 // On mobile, there may be a dynamic toolbar. The root content document's
3932 // root scroll frame's ink overflow rect does not include the toolbar
3933 // height, but if the toolbar is hidden, we still want to be able to target
3934 // content underneath the toolbar, so expand the overflow rect here to
3935 // allow display list building to descend into the scroll frame.
3936 if (aBuilder->IsForEventDelivery() &&
3937 aChild == aChild->PresShell()->GetRootScrollFrame() &&
3938 aChild->PresContext()->IsRootContentDocumentCrossProcess() &&
3939 aChild->PresContext()->HasDynamicToolbar()) {
3940 overflow.SizeTo(nsLayoutUtils::ExpandHeightForDynamicToolbar(
3941 aChild->PresContext(), overflow.Size()));
3942 }
3943
3944 if (aDirty.Intersects(overflow)) {
3945 return true;
3946 }
3947
3948 if (aChild->ForceDescendIntoIfVisible() && aVisible.Intersects(overflow)) {
3949 return true;
3950 }
3951
3952 if (aChild->IsTablePart()) {
3953 // Relative positioning and transforms can cause table parts to move, but we
3954 // will still paint the backgrounds for their ancestor parts under them at
3955 // their 'normal' position. That means that we must consider the overflow
3956 // rects at both positions.
3957
3958 // We convert the overflow rect into the nsTableFrame's coordinate
3959 // space, applying the normal position offset at each step. Then we
3960 // compare that against the builder's cached dirty rect in table
3961 // coordinate space.
3962 const nsIFrame* f = aChild;
3963 nsRect normalPositionOverflowRelativeToTable = overflow;
3964
3965 while (f->IsTablePart()) {
3966 normalPositionOverflowRelativeToTable += f->GetNormalPosition();
3967 f = f->GetParent();
3968 }
3969
3970 nsDisplayTableBackgroundSet* tableBGs = aBuilder->GetTableBackgroundSet();
3971 if (tableBGs && tableBGs->GetDirtyRect().Intersects(
3972 normalPositionOverflowRelativeToTable)) {
3973 return true;
3974 }
3975 }
3976
3977 return false;
3978}
3979
3980void nsIFrame::BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
3981 nsIFrame* aChild,
3982 const nsDisplayListSet& aLists) {
3983 // This is the shortcut for frames been handled along the common
3984 // path, the most common one of THE COMMON CASE mentioned later.
3985 MOZ_ASSERT(aChild->Type() != LayoutFrameType::Placeholder)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->Type() != LayoutFrameType::Placeholder)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->Type() != LayoutFrameType::Placeholder)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aChild->Type() != LayoutFrameType::Placeholder"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->Type() != LayoutFrameType::Placeholder"
")"); do { *((volatile int*)__null) = 3985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3986 MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBuilder->GetSelectedFramesOnly() && !aBuilder
->GetIncludeAllOutOfFlows())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aBuilder->GetSelectedFramesOnly
() && !aBuilder->GetIncludeAllOutOfFlows()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
" (" "It should be held for painting to window" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
") (" "It should be held for painting to window" ")"); do { *
((volatile int*)__null) = 3988; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
3987 !aBuilder->GetIncludeAllOutOfFlows(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBuilder->GetSelectedFramesOnly() && !aBuilder
->GetIncludeAllOutOfFlows())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aBuilder->GetSelectedFramesOnly
() && !aBuilder->GetIncludeAllOutOfFlows()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
" (" "It should be held for painting to window" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
") (" "It should be held for painting to window" ")"); do { *
((volatile int*)__null) = 3988; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
3988 "It should be held for painting to window")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aBuilder->GetSelectedFramesOnly() && !aBuilder
->GetIncludeAllOutOfFlows())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aBuilder->GetSelectedFramesOnly
() && !aBuilder->GetIncludeAllOutOfFlows()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
" (" "It should be held for painting to window" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aBuilder->GetSelectedFramesOnly() && !aBuilder->GetIncludeAllOutOfFlows()"
") (" "It should be held for painting to window" ")"); do { *
((volatile int*)__null) = 3988; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
3989 MOZ_ASSERT(aChild->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChild->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aChild->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 3989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST)"
")"); do { *((volatile int*)__null) = 3989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3990
3991 const nsPoint offset = aChild->GetOffsetTo(this);
3992 const nsRect visible = aBuilder->GetVisibleRect() - offset;
3993 const nsRect dirty = aBuilder->GetDirtyRect() - offset;
3994
3995 if (!DescendIntoChild(aBuilder, aChild, visible, dirty)) {
3996 DL_LOGV("Skipped frame %p", aChild)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Skipped frame %p", aChild); } } while (
0)
;
3997 return;
3998 }
3999
4000 // Child cannot be transformed since it is not a stacking context.
4001 nsDisplayListBuilder::AutoBuildingDisplayList buildingForChild(
4002 aBuilder, aChild, visible, dirty, false);
4003
4004 UpdateCurrentHitTestInfo(aBuilder, aChild);
4005
4006 aChild->MarkAbsoluteFramesForDisplayList(aBuilder);
4007 aBuilder->AdjustWindowDraggingRegion(aChild);
4008 aBuilder->Check();
4009 aChild->BuildDisplayList(aBuilder, aLists);
4010 aChild->SetBuiltDisplayList(true);
4011 aBuilder->Check();
4012 aBuilder->DisplayCaret(aChild, aLists.Outlines());
4013}
4014
4015static bool ShouldSkipFrame(nsDisplayListBuilder* aBuilder,
4016 const nsIFrame* aFrame) {
4017 // If painting is restricted to just the background of the top level frame,
4018 // then we have nothing to do here.
4019 if (aBuilder->IsBackgroundOnly()) {
4020 return true;
4021 }
4022 if (aBuilder->IsForGenerateGlyphMask() &&
4023 (!aFrame->IsTextFrame() && aFrame->IsLeaf())) {
4024 return true;
4025 }
4026 // The placeholder frame should have the same content as the OOF frame.
4027 if (aBuilder->GetSelectedFramesOnly() &&
4028 (aFrame->IsLeaf() && !aFrame->IsSelected())) {
4029 return true;
4030 }
4031 static const nsFrameState skipFlags =
4032 (NS_FRAME_TOO_DEEP_IN_FRAME_TREE | NS_FRAME_IS_NONDISPLAY);
4033 if (aFrame->HasAnyStateBits(skipFlags)) {
4034 return true;
4035 }
4036 return aFrame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually;
4037}
4038
4039void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
4040 nsIFrame* aChild,
4041 const nsDisplayListSet& aLists,
4042 DisplayChildFlags aFlags) {
4043 AutoCheckBuilder check(aBuilder);
4044#ifdef DEBUG1
4045 DL_LOGV("BuildDisplayListForChild (%p) <", aChild)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "BuildDisplayListForChild (%p) <", aChild
); } } while (0)
;
4046 ScopeExit e(
4047 [aChild]() { DL_LOGV("> BuildDisplayListForChild (%p)", aChild)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "> BuildDisplayListForChild (%p)", aChild
); } } while (0)
; });
4048#endif
4049
4050 if (ShouldSkipFrame(aBuilder, aChild)) {
4051 return;
4052 }
4053
4054 if (HidesContent()) {
4055 return;
4056 }
4057
4058 nsIFrame* child = aChild;
4059 auto* placeholder = child->IsPlaceholderFrame()
4060 ? static_cast<nsPlaceholderFrame*>(child)
4061 : nullptr;
4062 nsIFrame* childOrOutOfFlow =
4063 placeholder ? placeholder->GetOutOfFlowFrame() : child;
4064
4065 // If we're generating a display list for printing, include Link items for
4066 // frames that correspond to HTML link elements so that we can have active
4067 // links in saved PDF output. Note that the state of "within a link" is
4068 // set on the display-list builder, such that all descendants of the link
4069 // element will generate display-list links.
4070 // TODO: we should be able to optimize this so as to avoid creating links
4071 // for the same destination that entirely overlap each other, which adds
4072 // nothing useful to the final PDF.
4073 Maybe<nsDisplayListBuilder::Linkifier> linkifier;
4074 if (StaticPrefs::print_save_as_pdf_links_enabled() &&
4075 aBuilder->IsForPrinting()) {
4076 linkifier.emplace(aBuilder, childOrOutOfFlow, aLists.Content());
4077 linkifier->MaybeAppendLink(aBuilder, childOrOutOfFlow);
4078 }
4079
4080 nsIFrame* parent = childOrOutOfFlow->GetParent();
4081 const auto* parentDisplay = parent->StyleDisplay();
4082 const auto overflowClipAxes =
4083 parent->ShouldApplyOverflowClipping(parentDisplay);
4084
4085 const bool isPaintingToWindow = aBuilder->IsPaintingToWindow();
4086 const bool doingShortcut =
4087 isPaintingToWindow &&
4088 child->HasAnyStateBits(NS_FRAME_SIMPLE_DISPLAYLIST) &&
4089 // Animations may change the stacking context state.
4090 // ShouldApplyOverflowClipping is affected by the parent style, which does
4091 // not invalidate the NS_FRAME_SIMPLE_DISPLAYLIST bit.
4092 !(overflowClipAxes != PhysicalAxes::None ||
4093 child->MayHaveTransformAnimation() || child->MayHaveOpacityAnimation());
4094
4095 if (aBuilder->IsForPainting()) {
4096 aBuilder->ClearWillChangeBudgetStatus(child);
4097 }
4098
4099 if (StaticPrefs::layout_css_scroll_anchoring_highlight()) {
4100 if (child->FirstContinuation()->IsScrollAnchor()) {
4101 nsRect bounds = child->GetContentRectRelativeToSelf() +
4102 aBuilder->ToReferenceFrame(child);
4103 nsDisplaySolidColor* color = MakeDisplayItem<nsDisplaySolidColor>(
4104 aBuilder, child, bounds, NS_RGBA(255, 0, 255, 64)((nscolor)(((64) << 24) | ((255) << 16) | ((0) <<
8) | (255)))
);
4105 if (color) {
4106 color->SetOverrideZIndex(INT32_MAX(2147483647));
4107 aLists.PositionedDescendants()->AppendToTop(color);
4108 }
4109 }
4110 }
4111
4112 if (doingShortcut) {
4113 BuildDisplayListForSimpleChild(aBuilder, child, aLists);
4114 return;
4115 }
4116
4117 // dirty rect in child-relative coordinates
4118 NS_ASSERTION(aBuilder->GetCurrentFrame() == this, "Wrong coord space!")do { if (!(aBuilder->GetCurrentFrame() == this)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Wrong coord space!", "aBuilder->GetCurrentFrame() == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4118); MOZ_PretendNoReturn(); } } while (0)
;
4119 const nsPoint offset = child->GetOffsetTo(this);
4120 nsRect visible = aBuilder->GetVisibleRect() - offset;
4121 nsRect dirty = aBuilder->GetDirtyRect() - offset;
4122
4123 nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
4124 if (placeholder) {
4125 if (placeholder->HasAnyStateBits(PLACEHOLDER_FOR_TOPLAYER)) {
4126 // If the out-of-flow frame is in the top layer, the viewport frame
4127 // will paint it. Skip it here. Note that, only out-of-flow frames
4128 // with this property should be skipped, because non-HTML elements
4129 // may stop their children from being out-of-flow. Those frames
4130 // should still be handled in the normal in-flow path.
4131 return;
4132 }
4133
4134 child = childOrOutOfFlow;
4135 if (aBuilder->IsForPainting()) {
4136 aBuilder->ClearWillChangeBudgetStatus(child);
4137 }
4138
4139 // If 'child' is a pushed float then it's owned by a block that's not an
4140 // ancestor of the placeholder, and it will be painted by that block and
4141 // should not be painted through the placeholder. Also recheck
4142 // NS_FRAME_TOO_DEEP_IN_FRAME_TREE and NS_FRAME_IS_NONDISPLAY.
4143 static const nsFrameState skipFlags =
4144 (NS_FRAME_IS_PUSHED_FLOAT | NS_FRAME_TOO_DEEP_IN_FRAME_TREE |
4145 NS_FRAME_IS_NONDISPLAY);
4146 if (child->HasAnyStateBits(skipFlags) || nsLayoutUtils::IsPopup(child)) {
4147 return;
4148 }
4149
4150 MOZ_ASSERT(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)"
")"); do { *((volatile int*)__null) = 4150; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4151 savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
4152
4153 if (aBuilder->GetIncludeAllOutOfFlows()) {
4154 visible = child->InkOverflowRect();
4155 dirty = child->InkOverflowRect();
4156 } else if (savedOutOfFlowData) {
4157 visible =
4158 savedOutOfFlowData->GetVisibleRectForFrame(aBuilder, child, &dirty);
4159 } else {
4160 // The out-of-flow frame did not intersect the dirty area. We may still
4161 // need to traverse into it, since it may contain placeholders we need
4162 // to enter to reach other out-of-flow frames that are visible.
4163 visible.SetEmpty();
4164 dirty.SetEmpty();
4165 }
4166 }
4167
4168 NS_ASSERTION(!child->IsPlaceholderFrame(),do { if (!(!child->IsPlaceholderFrame())) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "Should have dealt with placeholders already"
, "!child->IsPlaceholderFrame()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4169); MOZ_PretendNoReturn(); } } while (0)
4169 "Should have dealt with placeholders already")do { if (!(!child->IsPlaceholderFrame())) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "Should have dealt with placeholders already"
, "!child->IsPlaceholderFrame()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4169); MOZ_PretendNoReturn(); } } while (0)
;
4170
4171 if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
4172 DL_LOGV("Skipped frame %p", child)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Verbose)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Verbose, "Skipped frame %p", child); } } while (0
)
;
4173 return;
4174 }
4175
4176 const bool isSVG = child->HasAnyStateBits(NS_FRAME_SVG_LAYOUT);
4177
4178 // This flag is raised if the control flow strays off the common path.
4179 // The common path is the most common one of THE COMMON CASE mentioned later.
4180 bool awayFromCommonPath = !isPaintingToWindow;
4181
4182 // true if this is a real or pseudo stacking context
4183 bool pseudoStackingContext =
4184 aFlags.contains(DisplayChildFlag::ForcePseudoStackingContext);
4185
4186 if (!pseudoStackingContext && !isSVG &&
4187 aFlags.contains(DisplayChildFlag::Inline) &&
4188 !child->IsLineParticipant()) {
4189 // child is a non-inline frame in an inline context, i.e.,
4190 // it acts like inline-block or inline-table. Therefore it is a
4191 // pseudo-stacking-context.
4192 pseudoStackingContext = true;
4193 }
4194
4195 const nsStyleDisplay* ourDisp = StyleDisplay();
4196 // Don't paint our children if the theme object is a leaf.
4197 if (IsThemed(ourDisp) && !PresContext()->Theme()->WidgetIsContainer(
4198 ourDisp->EffectiveAppearance())) {
4199 return;
4200 }
4201
4202 // Since we're now sure that we're adding this frame to the display list
4203 // (which means we're painting it, modulo occlusion), mark it as visible
4204 // within the displayport.
4205 if (isPaintingToWindow && child->TrackingVisibility() &&
4206 child->IsVisibleForPainting()) {
4207 child->PresShell()->EnsureFrameInApproximatelyVisibleList(child);
4208 awayFromCommonPath = true;
4209 }
4210
4211 // Child is composited if it's transformed, partially transparent, or has
4212 // SVG effects or a blend mode..
4213 const nsStyleDisplay* disp = child->StyleDisplay();
4214 const nsStyleEffects* effects = child->StyleEffects();
4215
4216 const bool isPositioned = disp->IsPositionedStyle();
4217 const bool isStackingContext =
4218 aFlags.contains(DisplayChildFlag::ForceStackingContext) ||
4219 child->IsStackingContext(disp, effects);
4220
4221 if (pseudoStackingContext || isStackingContext || isPositioned ||
4222 placeholder || (!isSVG && disp->IsFloating(child)) ||
4223 (isSVG && effects->mClip.IsRect() && IsSVGContentWithCSSClip(child))) {
4224 pseudoStackingContext = true;
4225 awayFromCommonPath = true;
4226 }
4227
4228 NS_ASSERTION(!isStackingContext || pseudoStackingContext,do { if (!(!isStackingContext || pseudoStackingContext)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Stacking contexts must also be pseudo-stacking-contexts"
, "!isStackingContext || pseudoStackingContext", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4229); MOZ_PretendNoReturn(); } } while (0)
4229 "Stacking contexts must also be pseudo-stacking-contexts")do { if (!(!isStackingContext || pseudoStackingContext)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Stacking contexts must also be pseudo-stacking-contexts"
, "!isStackingContext || pseudoStackingContext", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4229); MOZ_PretendNoReturn(); } } while (0)
;
4230
4231 nsDisplayListBuilder::AutoBuildingDisplayList buildingForChild(
4232 aBuilder, child, visible, dirty);
4233
4234 UpdateCurrentHitTestInfo(aBuilder, child);
4235
4236 DisplayListClipState::AutoClipMultiple clipState(aBuilder);
4237 nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
4238
4239 if (savedOutOfFlowData) {
4240 aBuilder->SetBuildingInvisibleItems(false);
4241
4242 clipState.SetClipChainForContainingBlockDescendants(
4243 savedOutOfFlowData->mContainingBlockClipChain);
4244 asrSetter.SetCurrentActiveScrolledRoot(
4245 savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
4246 asrSetter.SetCurrentScrollParentId(savedOutOfFlowData->mScrollParentId);
4247 MOZ_ASSERT(awayFromCommonPath,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(awayFromCommonPath)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(awayFromCommonPath))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("awayFromCommonPath"
" (" "It is impossible when savedOutOfFlowData is true" ")",
"/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "awayFromCommonPath"
") (" "It is impossible when savedOutOfFlowData is true" ")"
); do { *((volatile int*)__null) = 4248; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4248 "It is impossible when savedOutOfFlowData is true")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(awayFromCommonPath)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(awayFromCommonPath))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("awayFromCommonPath"
" (" "It is impossible when savedOutOfFlowData is true" ")",
"/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "awayFromCommonPath"
") (" "It is impossible when savedOutOfFlowData is true" ")"
); do { *((volatile int*)__null) = 4248; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4249 } else if (HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) &&
4250 placeholder) {
4251 NS_ASSERTION(visible.IsEmpty(), "should have empty visible rect")do { if (!(visible.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "should have empty visible rect", "visible.IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4251); MOZ_PretendNoReturn(); } } while (0)
;
4252 // Every item we build from now until we descent into an out of flow that
4253 // does have saved out of flow data should be invisible. This state gets
4254 // restored when AutoBuildingDisplayList gets out of scope.
4255 aBuilder->SetBuildingInvisibleItems(true);
4256
4257 // If we have nested out-of-flow frames and the outer one isn't visible
4258 // then we won't have stored clip data for it. We can just clear the clip
4259 // instead since we know we won't render anything, and the inner out-of-flow
4260 // frame will setup the correct clip for itself.
4261 clipState.SetClipChainForContainingBlockDescendants(nullptr);
4262 }
4263
4264 // Setup clipping for the parent's overflow:clip,
4265 // or overflow:hidden on elements that don't support scrolling (and therefore
4266 // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
4267 // anything directly rendered by the parent, only the rendering of its
4268 // children.
4269 // Don't use overflowClip to restrict the dirty rect, since some of the
4270 // descendants may not be clipped by it. Even if we end up with unnecessary
4271 // display items, they'll be pruned during ComputeVisibility.
4272 //
4273 // FIXME(emilio): Why can't we handle this more similarly to `clip` (on the
4274 // parent, rather than on the children)? Would ClipContentDescendants do what
4275 // we want?
4276 if (overflowClipAxes != PhysicalAxes::None) {
4277 ApplyOverflowClipping(aBuilder, parent, overflowClipAxes, clipState);
4278 awayFromCommonPath = true;
4279 }
4280
4281 nsDisplayList list(aBuilder);
4282 nsDisplayList extraPositionedDescendants(aBuilder);
4283 const ActiveScrolledRoot* wrapListASR;
4284 bool builtContainerItem = false;
4285 if (isStackingContext) {
4286 // True stacking context.
4287 // For stacking contexts, BuildDisplayListForStackingContext handles
4288 // clipping and MarkAbsoluteFramesForDisplayList.
4289 nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
4290 child->BuildDisplayListForStackingContext(aBuilder, &list,
4291 &builtContainerItem);
4292 wrapListASR = contASRTracker.GetContainerASR();
4293 if (!aBuilder->IsReusingStackingContextItems() &&
4294 aBuilder->GetCaretFrame() == child) {
4295 builtContainerItem = false;
4296 }
4297 } else {
4298 Maybe<nsRect> clipPropClip =
4299 child->GetClipPropClipRect(disp, effects, child->GetSize());
4300 if (clipPropClip) {
4301 aBuilder->IntersectVisibleRect(*clipPropClip);
4302 aBuilder->IntersectDirtyRect(*clipPropClip);
4303 clipState.ClipContentDescendants(*clipPropClip +
4304 aBuilder->ToReferenceFrame(child));
4305 awayFromCommonPath = true;
4306 }
4307
4308 child->MarkAbsoluteFramesForDisplayList(aBuilder);
4309 child->SetBuiltDisplayList(true);
4310
4311 // Some SVG frames might change opacity without invalidating the frame, so
4312 // exclude them from the fast-path.
4313 if (!awayFromCommonPath && !child->IsSVGFrame()) {
4314 // The shortcut is available for the child for next time.
4315 child->AddStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
4316 }
4317
4318 if (!pseudoStackingContext) {
4319 // THIS IS THE COMMON CASE.
4320 // Not a pseudo or real stacking context. Do the simple thing and
4321 // return early.
4322 aBuilder->AdjustWindowDraggingRegion(child);
4323 aBuilder->Check();
4324 child->BuildDisplayList(aBuilder, aLists);
4325 aBuilder->Check();
4326 aBuilder->DisplayCaret(child, aLists.Outlines());
4327 return;
4328 }
4329
4330 // A pseudo-stacking context (e.g., a positioned element with z-index auto).
4331 // We allow positioned descendants of the child to escape to our parent
4332 // stacking context's positioned descendant list, because they might be
4333 // z-index:non-auto
4334 nsDisplayListCollection pseudoStack(aBuilder);
4335
4336 aBuilder->AdjustWindowDraggingRegion(child);
4337 nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
4338 aBuilder->Check();
4339 child->BuildDisplayList(aBuilder, pseudoStack);
4340 aBuilder->Check();
4341 if (aBuilder->DisplayCaret(child, pseudoStack.Outlines())) {
4342 builtContainerItem = false;
4343 }
4344 wrapListASR = contASRTracker.GetContainerASR();
4345
4346 list.AppendToTop(pseudoStack.BorderBackground());
4347 list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
4348 list.AppendToTop(pseudoStack.Floats());
4349 list.AppendToTop(pseudoStack.Content());
4350 list.AppendToTop(pseudoStack.Outlines());
4351 extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
4352 }
4353
4354 buildingForChild.RestoreBuildingInvisibleItemsValue();
4355
4356 if (!list.IsEmpty()) {
4357 if (isPositioned || isStackingContext) {
4358 // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
4359 // go in this level.
4360 nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR,
4361 builtContainerItem);
4362 if (isSVG) {
4363 aLists.Content()->AppendToTop(item);
4364 } else {
4365 aLists.PositionedDescendants()->AppendToTop(item);
4366 }
4367 } else if (!isSVG && disp->IsFloating(child)) {
4368 aLists.Floats()->AppendToTop(
4369 WrapInWrapList(aBuilder, child, &list, wrapListASR));
4370 } else {
4371 aLists.Content()->AppendToTop(&list);
4372 }
4373 }
4374 // We delay placing the positioned descendants of positioned frames to here,
4375 // because in the absence of z-index this is the correct order for them.
4376 // This doesn't affect correctness because the positioned descendants list
4377 // is sorted by z-order and content in BuildDisplayListForStackingContext,
4378 // but it means that sort routine needs to do less work.
4379 aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
4380}
4381
4382void nsIFrame::MarkAbsoluteFramesForDisplayList(
4383 nsDisplayListBuilder* aBuilder) {
4384 if (IsAbsoluteContainer()) {
4385 aBuilder->MarkFramesForDisplayList(
4386 this, GetAbsoluteContainingBlock()->GetChildList());
4387 }
4388}
4389
4390nsresult nsIFrame::GetContentForEvent(const WidgetEvent* aEvent,
4391 nsIContent** aContent) {
4392 nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
4393 *aContent = f->GetContent();
4394 NS_IF_ADDREF(*aContent)ns_if_addref(*aContent);
4395 return NS_OK;
4396}
4397
4398void nsIFrame::FireDOMEvent(const nsAString& aDOMEventName,
4399 nsIContent* aContent) {
4400 nsIContent* target = aContent ? aContent : GetContent();
4401
4402 if (target) {
4403 RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
4404 target, aDOMEventName, CanBubble::eYes, ChromeOnlyDispatch::eNo);
4405 DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
4406 NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "AsyncEventDispatcher failed to dispatch"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4406); MOZ_PretendNoReturn(); } } while (0)
;
4407 }
4408}
4409
4410nsresult nsIFrame::HandleEvent(nsPresContext* aPresContext,
4411 WidgetGUIEvent* aEvent,
4412 nsEventStatus* aEventStatus) {
4413 if (aEvent->mMessage == eMouseMove) {
4414 // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
4415 // the implementation becomes simpler.
4416 return HandleDrag(aPresContext, aEvent, aEventStatus);
4417 }
4418
4419 if ((aEvent->mClass == eMouseEventClass &&
4420 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) ||
4421 aEvent->mClass == eTouchEventClass) {
4422 if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eTouchStart) {
4423 HandlePress(aPresContext, aEvent, aEventStatus);
4424 } else if (aEvent->mMessage == eMouseUp || aEvent->mMessage == eTouchEnd) {
4425 HandleRelease(aPresContext, aEvent, aEventStatus);
4426 }
4427 return NS_OK;
4428 }
4429
4430 // When secondary buttion is down, we need to move selection to make users
4431 // possible to paste something at click point quickly.
4432 // When middle button is down, we need to just move selection and focus at
4433 // the clicked point. Note that even if middle click paste is not enabled,
4434 // Chrome moves selection at middle mouse button down. So, we should follow
4435 // the behavior for the compatibility.
4436 if (aEvent->mMessage == eMouseDown) {
4437 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
4438 if (mouseEvent && (mouseEvent->mButton == MouseButton::eSecondary ||
4439 mouseEvent->mButton == MouseButton::eMiddle)) {
4440 if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
4441 return NS_OK;
4442 }
4443 return MoveCaretToEventPoint(aPresContext, mouseEvent, aEventStatus);
4444 }
4445 }
4446
4447 return NS_OK;
4448}
4449
4450nsresult nsIFrame::GetDataForTableSelection(
4451 const nsFrameSelection* aFrameSelection, mozilla::PresShell* aPresShell,
4452 WidgetMouseEvent* aMouseEvent, nsIContent** aParentContent,
4453 int32_t* aContentOffset, TableSelectionMode* aTarget) {
4454 if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent ||
4455 !aContentOffset || !aTarget)
4456 return NS_ERROR_NULL_POINTER;
4457
4458 *aParentContent = nullptr;
4459 *aContentOffset = 0;
4460 *aTarget = TableSelectionMode::None;
4461
4462 int16_t displaySelection = aPresShell->GetSelectionFlags();
4463
4464 bool selectingTableCells = aFrameSelection->IsInTableSelectionMode();
4465
4466 // DISPLAY_ALL means we're in an editor.
4467 // If already in cell selection mode,
4468 // continue selecting with mouse drag or end on mouse up,
4469 // or when using shift key to extend block of cells
4470 // (Mouse down does normal selection unless Ctrl/Cmd is pressed)
4471 bool doTableSelection =
4472 displaySelection == nsISelectionDisplay::DISPLAY_ALL &&
4473 selectingTableCells &&
4474 (aMouseEvent->mMessage == eMouseMove ||
4475 (aMouseEvent->mMessage == eMouseUp &&
4476 aMouseEvent->mButton == MouseButton::ePrimary) ||
4477 aMouseEvent->IsShift());
4478
4479 if (!doTableSelection) {
4480 // In Browser, special 'table selection' key must be pressed for table
4481 // selection or when just Shift is pressed and we're already in table/cell
4482 // selection mode
4483#ifdef XP_MACOSX
4484 doTableSelection = aMouseEvent->IsMeta() ||
4485 (aMouseEvent->IsShift() && selectingTableCells);
4486#else
4487 doTableSelection = aMouseEvent->IsControl() ||
4488 (aMouseEvent->IsShift() && selectingTableCells);
4489#endif
4490 }
4491 if (!doTableSelection) return NS_OK;
4492
4493 // Get the cell frame or table frame (or parent) of the current content node
4494 nsIFrame* frame = this;
4495 bool foundCell = false;
4496 bool foundTable = false;
4497
4498 // Get the limiting node to stop parent frame search
4499 nsIContent* limiter = aFrameSelection->GetLimiter();
4500
4501 // If our content node is an ancestor of the limiting node,
4502 // we should stop the search right now.
4503 if (limiter && limiter->IsInclusiveDescendantOf(GetContent())) return NS_OK;
4504
4505 // We don't initiate row/col selection from here now,
4506 // but we may in future
4507 // bool selectColumn = false;
4508 // bool selectRow = false;
4509
4510 while (frame) {
4511 // Check for a table cell by querying to a known CellFrame interface
4512 nsITableCellLayout* cellElement = do_QueryFrame(frame);
4513 if (cellElement) {
4514 foundCell = true;
4515 // TODO: If we want to use proximity to top or left border
4516 // for row and column selection, this is the place to do it
4517 break;
4518 } else {
4519 // If not a cell, check for table
4520 // This will happen when starting frame is the table or child of a table,
4521 // such as a row (we were inbetween cells or in table border)
4522 nsTableWrapperFrame* tableFrame = do_QueryFrame(frame);
4523 if (tableFrame) {
4524 foundTable = true;
4525 // TODO: How can we select row when along left table edge
4526 // or select column when along top edge?
4527 break;
4528 } else {
4529 frame = frame->GetParent();
4530 // Stop if we have hit the selection's limiting content node
4531 if (frame && frame->GetContent() == limiter) break;
4532 }
4533 }
4534 }
4535 // We aren't in a cell or table
4536 if (!foundCell && !foundTable) return NS_OK;
4537
4538 nsIContent* tableOrCellContent = frame->GetContent();
4539 if (!tableOrCellContent) return NS_ERROR_FAILURE;
4540
4541 nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
4542 if (!parentContent) return NS_ERROR_FAILURE;
4543
4544 const int32_t offset =
4545 parentContent->ComputeIndexOf_Deprecated(tableOrCellContent);
4546 // Not likely?
4547 if (offset < 0) {
4548 return NS_ERROR_FAILURE;
4549 }
4550
4551 // Everything is OK -- set the return values
4552 parentContent.forget(aParentContent);
4553
4554 *aContentOffset = offset;
4555
4556#if 0
4557 if (selectRow)
4558 *aTarget = TableSelectionMode::Row;
4559 else if (selectColumn)
4560 *aTarget = TableSelectionMode::Column;
4561 else
4562#endif
4563 if (foundCell) {
4564 *aTarget = TableSelectionMode::Cell;
4565 } else if (foundTable) {
4566 *aTarget = TableSelectionMode::Table;
4567 }
4568
4569 return NS_OK;
4570}
4571
4572static bool IsEditingHost(const nsIFrame* aFrame) {
4573 nsIContent* content = aFrame->GetContent();
4574 return content && content->IsEditingHost();
4575}
4576
4577static StyleUserSelect UsedUserSelect(const nsIFrame* aFrame) {
4578 if (aFrame->IsGeneratedContentFrame()) {
4579 return StyleUserSelect::None;
4580 }
4581
4582 // Per https://drafts.csswg.org/css-ui-4/#content-selection:
4583 //
4584 // The used value is the same as the computed value, except:
4585 //
4586 // 1 - on editable elements where the used value is always 'contain'
4587 // regardless of the computed value
4588 // 2 - when the computed value is auto, in which case the used value is one
4589 // of the other values...
4590 //
4591 // See https://github.com/w3c/csswg-drafts/issues/3344 to see why we do this
4592 // at used-value time instead of at computed-value time.
4593
4594 if (aFrame->IsTextInputFrame() || IsEditingHost(aFrame)) {
4595 // We don't implement 'contain' itself, but we make 'text' behave as
4596 // 'contain' for contenteditable and <input> / <textarea> elements anyway so
4597 // this is ok.
4598 return StyleUserSelect::Text;
4599 }
4600
4601 auto style = aFrame->Style()->UserSelect();
4602 if (style != StyleUserSelect::Auto) {
4603 return style;
4604 }
4605
4606 auto* parent = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
4607 return parent ? UsedUserSelect(parent) : StyleUserSelect::Text;
4608}
4609
4610bool nsIFrame::IsSelectable(StyleUserSelect* aSelectStyle) const {
4611 auto style = UsedUserSelect(this);
4612 if (aSelectStyle) {
4613 *aSelectStyle = style;
4614 }
4615 return style != StyleUserSelect::None;
4616}
4617
4618bool nsIFrame::ShouldHaveLineIfEmpty() const {
4619 if (Style()->IsPseudoOrAnonBox() &&
4620 Style()->GetPseudoType() != PseudoStyleType::scrolledContent) {
4621 return false;
4622 }
4623 return IsEditingHost(this);
4624}
4625
4626/**
4627 * Handles the Mouse Press Event for the frame
4628 */
4629NS_IMETHODIMPnsresult
4630nsIFrame::HandlePress(nsPresContext* aPresContext, WidgetGUIEvent* aEvent,
4631 nsEventStatus* aEventStatus) {
4632 NS_ENSURE_ARG_POINTER(aEventStatus)do { if ((__builtin_expect(!!(!(aEventStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEventStatus" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4632); return NS_ERROR_INVALID_POINTER; } } while (false)
;
4633 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
4634 return NS_OK;
4635 }
4636
4637 NS_ENSURE_ARG_POINTER(aEvent)do { if ((__builtin_expect(!!(!(aEvent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEvent" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4637); return NS_ERROR_INVALID_POINTER; } } while (false)
;
4638 if (aEvent->mClass == eTouchEventClass) {
4639 return NS_OK;
4640 }
4641
4642 return MoveCaretToEventPoint(aPresContext, aEvent->AsMouseEvent(),
4643 aEventStatus);
4644}
4645
4646nsresult nsIFrame::MoveCaretToEventPoint(nsPresContext* aPresContext,
4647 WidgetMouseEvent* aMouseEvent,
4648 nsEventStatus* aEventStatus) {
4649 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 4649; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4650 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4650); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 4650; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4651 MOZ_ASSERT(aMouseEvent->mMessage == eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent->mMessage == eMouseDown)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aMouseEvent->mMessage == eMouseDown))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMouseEvent->mMessage == eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent->mMessage == eMouseDown"
")"); do { *((volatile int*)__null) = 4651; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4652 MOZ_ASSERT(aEventStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEventStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEventStatus))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aEventStatus", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEventStatus"
")"); do { *((volatile int*)__null) = 4652; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4653 MOZ_ASSERT(nsEventStatus_eConsumeNoDefault != *aEventStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsEventStatus_eConsumeNoDefault != *aEventStatus)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nsEventStatus_eConsumeNoDefault != *aEventStatus))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("nsEventStatus_eConsumeNoDefault != *aEventStatus"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4653); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsEventStatus_eConsumeNoDefault != *aEventStatus"
")"); do { *((volatile int*)__null) = 4653; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4654
4655 mozilla::PresShell* presShell = aPresContext->GetPresShell();
4656 if (!presShell) {
4657 return NS_ERROR_FAILURE;
4658 }
4659
4660 // We often get out of sync state issues with mousedown events that
4661 // get interrupted by alerts/dialogs.
4662 // Check with the ESM to see if we should process this one
4663 if (!aPresContext->EventStateManager()->EventStatusOK(aMouseEvent)) {
4664 return NS_OK;
4665 }
4666
4667 const nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4668 aMouseEvent, RelativeTo{this});
4669
4670 // When not using `alt`, and clicking on a draggable, but non-editable
4671 // element, don't do anything, and let d&d handle the event.
4672 //
4673 // See bug 48876, bug 388659 and bug 55921 for context here.
4674 //
4675 // FIXME(emilio): The .Contains(pt) check looks a bit fishy. When would it be
4676 // false given we're the event target? If it is needed, why not checking the
4677 // actual draggable node rect instead?
4678 if (!aMouseEvent->IsAlt() && GetRectRelativeToSelf().Contains(pt)) {
4679 for (nsIContent* content = mContent; content;
4680 content = content->GetFlattenedTreeParent()) {
4681 if (nsContentUtils::ContentIsDraggable(content) &&
4682 !content->IsEditable()) {
4683 return NS_OK;
4684 }
4685 }
4686 }
4687
4688 // If we are in Navigator and the click is in a draggable node, we don't want
4689 // to start selection because we don't want to interfere with a potential
4690 // drag of said node and steal all its glory.
4691 const bool isEditor =
4692 presShell->GetSelectionFlags() == nsISelectionDisplay::DISPLAY_ALL;
4693
4694 // Don't do something if it's middle button down event.
4695 const bool isPrimaryButtonDown =
4696 aMouseEvent->mButton == MouseButton::ePrimary;
4697
4698 // check whether style allows selection
4699 // if not, don't tell selection the mouse event even occurred.
4700 StyleUserSelect selectStyle;
4701 // check for select: none
4702 if (!IsSelectable(&selectStyle)) {
4703 return NS_OK;
4704 }
4705
4706 if (isPrimaryButtonDown) {
4707 // If the mouse is dragged outside the nearest enclosing scrollable area
4708 // while making a selection, the area will be scrolled. To do this, capture
4709 // the mouse on the nearest scrollable frame. If there isn't a scrollable
4710 // frame, or something else is already capturing the mouse, there's no
4711 // reason to capture.
4712 if (!PresShell::GetCapturingContent()) {
4713 nsIScrollableFrame* scrollFrame =
4714 nsLayoutUtils::GetNearestScrollableFrame(
4715 this, nsLayoutUtils::SCROLLABLE_SAME_DOC |
4716 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4717 if (scrollFrame) {
4718 nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
4719 PresShell::SetCapturingContent(capturingFrame->GetContent(),
4720 CaptureFlags::IgnoreAllowedState);
4721 }
4722 }
4723 }
4724
4725 // XXX This is screwy; it really should use the selection frame, not the
4726 // event frame
4727 const nsFrameSelection* frameselection =
4728 selectStyle == StyleUserSelect::Text ? GetConstFrameSelection()
4729 : presShell->ConstFrameSelection();
4730
4731 if (!frameselection || frameselection->GetDisplaySelection() ==
4732 nsISelectionController::SELECTION_OFF) {
4733 return NS_OK; // nothing to do we cannot affect selection from here
4734 }
4735
4736#ifdef XP_MACOSX
4737 // If Control key is pressed on macOS, it should be treated as right click.
4738 // So, don't change selection.
4739 if (aMouseEvent->IsControl()) {
4740 return NS_OK;
4741 }
4742 const bool control = aMouseEvent->IsMeta();
4743#else
4744 const bool control = aMouseEvent->IsControl();
4745#endif
4746
4747 RefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
4748 if (isPrimaryButtonDown && aMouseEvent->mClickCount > 1) {
4749 // These methods aren't const but can't actually delete anything,
4750 // so no need for AutoWeakFrame.
4751 fc->SetDragState(true);
4752 return HandleMultiplePress(aPresContext, aMouseEvent, aEventStatus,
4753 control);
4754 }
4755
4756 ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
4757
4758 if (!offsets.content) {
4759 return NS_ERROR_FAILURE;
4760 }
4761
4762 const bool isSecondaryButton =
4763 aMouseEvent->mButton == MouseButton::eSecondary;
4764 if (isSecondaryButton &&
4765 !MovingCaretToEventPointAllowedIfSecondaryButtonEvent(
4766 *frameselection, *aMouseEvent, *offsets.content,
4767 // When we collapse selection in nsFrameSelection::TakeFocus,
4768 // we always collapse selection to the start offset. Therefore,
4769 // we can ignore the end offset here. E.g., when an <img> is clicked,
4770 // set the primary offset to after it, but the the secondary offset
4771 // may be before it, see OffsetsForSingleFrame for the detail.
4772 offsets.StartOffset())) {
4773 return NS_OK;
4774 }
4775
4776 if (aMouseEvent->mMessage == eMouseDown &&
4777 aMouseEvent->mButton == MouseButton::eMiddle &&
4778 !offsets.content->IsEditable()) {
4779 // However, some users don't like the Chrome compatible behavior of
4780 // middle mouse click. They want to keep selection after starting
4781 // autoscroll. However, the selection change is important for middle
4782 // mouse past. Therefore, we should allow users to take the traditional
4783 // behavior back by themselves unless middle click paste is enabled or
4784 // autoscrolling is disabled.
4785 if (!Preferences::GetBool("middlemouse.paste", false) &&
4786 Preferences::GetBool("general.autoScroll", false) &&
4787 Preferences::GetBool("general.autoscroll.prevent_to_collapse_selection_"
4788 "by_middle_mouse_down",
4789 false)) {
4790 return NS_OK;
4791 }
4792 }
4793
4794 if (isPrimaryButtonDown) {
4795 // Let Ctrl/Cmd + left mouse down do table selection instead of drag
4796 // initiation.
4797 nsCOMPtr<nsIContent> parentContent;
4798 int32_t contentOffset;
4799 TableSelectionMode target;
4800 nsresult rv = GetDataForTableSelection(
4801 frameselection, presShell, aMouseEvent, getter_AddRefs(parentContent),
4802 &contentOffset, &target);
4803 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && parentContent) {
4804 fc->SetDragState(true);
4805 return fc->HandleTableSelection(parentContent, contentOffset, target,
4806 aMouseEvent);
4807 }
4808 }
4809
4810 fc->SetDelayedCaretData(0);
4811
4812 if (isPrimaryButtonDown) {
4813 // Check if any part of this frame is selected, and if the user clicked
4814 // inside the selected region, and if it's the left button. If so, we delay
4815 // starting a new selection since the user may be trying to drag the
4816 // selected region to some other app.
4817
4818 if (GetContent() && GetContent()->IsMaybeSelected()) {
4819 bool inSelection = false;
4820 UniquePtr<SelectionDetails> details = frameselection->LookUpSelection(
4821 offsets.content, 0, offsets.EndOffset(), false);
4822
4823 //
4824 // If there are any details, check to see if the user clicked
4825 // within any selected region of the frame.
4826 //
4827
4828 for (SelectionDetails* curDetail = details.get(); curDetail;
4829 curDetail = curDetail->mNext.get()) {
4830 //
4831 // If the user clicked inside a selection, then just
4832 // return without doing anything. We will handle placing
4833 // the caret later on when the mouse is released. We ignore
4834 // the spellcheck, find and url formatting selections.
4835 //
4836 if (curDetail->mSelectionType != SelectionType::eSpellCheck &&
4837 curDetail->mSelectionType != SelectionType::eFind &&
4838 curDetail->mSelectionType != SelectionType::eURLSecondary &&
4839 curDetail->mSelectionType != SelectionType::eURLStrikeout &&
4840 curDetail->mSelectionType != SelectionType::eHighlight &&
4841 curDetail->mStart <= offsets.StartOffset() &&
4842 offsets.EndOffset() <= curDetail->mEnd) {
4843 inSelection = true;
4844 }
4845 }
4846
4847 if (inSelection) {
4848 fc->SetDragState(false);
4849 fc->SetDelayedCaretData(aMouseEvent);
4850 return NS_OK;
4851 }
4852 }
4853
4854 fc->SetDragState(true);
4855 }
4856
4857 // Do not touch any nsFrame members after this point without adding
4858 // weakFrame checks.
4859 const nsFrameSelection::FocusMode focusMode = [&]() {
4860 // If "Shift" and "Ctrl" are both pressed, "Shift" is given precedence. This
4861 // mimics the old behaviour.
4862 const bool isShift =
4863 aMouseEvent->IsShift() &&
4864 // If Shift + secondary button press shoud open context menu without a
4865 // contextmenu event, user wants to open context menu like as a
4866 // secondary button press without Shift key.
4867 !(isSecondaryButton &&
4868 StaticPrefs::dom_event_contextmenu_shift_suppresses_event());
4869 if (isShift) {
4870 // If clicked in a link when focused content is editable, we should
4871 // collapse selection in the link for compatibility with Blink.
4872 if (isEditor) {
4873 for (Element* element : mContent->InclusiveAncestorsOfType<Element>()) {
4874 if (element->IsLink()) {
4875 return nsFrameSelection::FocusMode::kCollapseToNewPoint;
4876 }
4877 }
4878 }
4879 return nsFrameSelection::FocusMode::kExtendSelection;
4880 }
4881
4882 if (isPrimaryButtonDown && control) {
4883 return nsFrameSelection::FocusMode::kMultiRangeSelection;
4884 }
4885
4886 return nsFrameSelection::FocusMode::kCollapseToNewPoint;
4887 }();
4888
4889 nsresult rv = fc->HandleClick(
4890 MOZ_KnownLive(offsets.content)(offsets.content) /* bug 1636889 */, offsets.StartOffset(),
4891 offsets.EndOffset(), focusMode, offsets.associate);
4892 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4893 return rv;
4894 }
4895
4896 // We don't handle mouse button up if it's middle button.
4897 if (isPrimaryButtonDown && offsets.offset != offsets.secondaryOffset) {
4898 fc->MaintainSelection();
4899 }
4900
4901 if (isPrimaryButtonDown && isEditor && !aMouseEvent->IsShift() &&
4902 (offsets.EndOffset() - offsets.StartOffset()) == 1) {
4903 // A single node is selected and we aren't extending an existing selection,
4904 // which means the user clicked directly on an object (either
4905 // `user-select: all` or a non-text node without children). Therefore,
4906 // disable selection extension during mouse moves.
4907 // XXX This is a bit hacky; shouldn't editor be able to deal with this?
4908 fc->SetDragState(false);
4909 }
4910
4911 return NS_OK;
4912}
4913
4914bool nsIFrame::MovingCaretToEventPointAllowedIfSecondaryButtonEvent(
4915 const nsFrameSelection& aFrameSelection,
4916 WidgetMouseEvent& aSecondaryButtonEvent,
4917 const nsIContent& aContentAtEventPoint, int32_t aOffsetAtEventPoint) const {
4918 MOZ_ASSERT(aSecondaryButtonEvent.mButton == MouseButton::eSecondary)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSecondaryButtonEvent.mButton == MouseButton::eSecondary
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aSecondaryButtonEvent.mButton == MouseButton::eSecondary
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aSecondaryButtonEvent.mButton == MouseButton::eSecondary", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSecondaryButtonEvent.mButton == MouseButton::eSecondary"
")"); do { *((volatile int*)__null) = 4918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4919
4920 if (NS_WARN_IF(aOffsetAtEventPoint < 0)NS_warn_if_impl(aOffsetAtEventPoint < 0, "aOffsetAtEventPoint < 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4920)
) {
4921 return false;
4922 }
4923
4924 const bool contentIsEditable = aContentAtEventPoint.IsEditable();
4925 const TextControlElement* const contentAsTextControl =
4926 TextControlElement::FromNodeOrNull(
4927 aContentAtEventPoint.IsTextControlElement()
4928 ? &aContentAtEventPoint
4929 : aContentAtEventPoint.GetClosestNativeAnonymousSubtreeRoot());
4930 if (Selection* selection =
4931 aFrameSelection.GetSelection(SelectionType::eNormal)) {
4932 const bool selectionIsCollapsed =
4933 selection->AreNormalAndCrossShadowBoundaryRangesCollapsed();
4934 // If right click in a selection range, we should not collapse
4935 // selection.
4936 if (!selectionIsCollapsed && nsContentUtils::IsPointInSelection(
4937 *selection, aContentAtEventPoint,
4938 static_cast<uint32_t>(aOffsetAtEventPoint),
4939 true /* aAllowCrossShadowBoundary */)) {
4940 return false;
4941 }
4942 const bool wantToPreventMoveCaret =
4943 StaticPrefs::
4944 ui_mouse_right_click_move_caret_stop_if_in_focused_editable_node() &&
4945 selectionIsCollapsed && (contentIsEditable || contentAsTextControl);
4946 const bool wantToPreventCollapseSelection =
4947 StaticPrefs::
4948 ui_mouse_right_click_collapse_selection_stop_if_non_collapsed_selection() &&
4949 !selectionIsCollapsed;
4950 if (wantToPreventMoveCaret || wantToPreventCollapseSelection) {
4951 // If currently selection is limited in an editing host, we should not
4952 // collapse selection nor move caret if the clicked point is in the
4953 // ancestor limiter. Otherwise, this mouse click moves focus from the
4954 // editing host to different one or blur the editing host. In this case,
4955 // we need to update selection because keeping current selection in the
4956 // editing host looks like it's not blurred.
4957 // FIXME: If the active editing host is the document element, editor
4958 // does not set ancestor limiter properly. Fix it in the editor side.
4959 if (nsIContent* ancestorLimiter = selection->GetAncestorLimiter()) {
4960 MOZ_ASSERT(ancestorLimiter->IsEditable())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorLimiter->IsEditable())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ancestorLimiter->IsEditable
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("ancestorLimiter->IsEditable()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4960); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorLimiter->IsEditable()"
")"); do { *((volatile int*)__null) = 4960; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4961 return !aContentAtEventPoint.IsInclusiveDescendantOf(ancestorLimiter);
4962 }
4963 }
4964 // If selection is editable and `stop_if_in_focused_editable_node` pref is
4965 // set to true, user does not want to move caret to right click place if
4966 // clicked in the focused text control element.
4967 if (wantToPreventMoveCaret && contentAsTextControl &&
4968 contentAsTextControl == nsFocusManager::GetFocusedElementStatic()) {
4969 return false;
4970 }
4971 // If currently selection is not limited in an editing host, we should
4972 // collapse selection only when this click moves focus to an editing
4973 // host because we need to update selection in this case.
4974 if (wantToPreventCollapseSelection && !contentIsEditable) {
4975 return false;
4976 }
4977 }
4978
4979 return !StaticPrefs::
4980 ui_mouse_right_click_collapse_selection_stop_if_non_editable_node() ||
4981 // The user does not want to collapse selection into non-editable
4982 // content by a right button click.
4983 contentIsEditable ||
4984 // Treat clicking in a text control as always clicked on editable
4985 // content because we want a hack only for clicking in normal text
4986 // nodes which is outside any editing hosts.
4987 contentAsTextControl;
4988}
4989
4990nsresult nsIFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
4991 const nsPoint& aPoint,
4992 nsSelectionAmount aBeginAmountType,
4993 nsSelectionAmount aEndAmountType,
4994 uint32_t aSelectFlags) {
4995 NS_ENSURE_ARG_POINTER(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 4995); return NS_ERROR_INVALID_POINTER; } } while (false)
;
4996
4997 // No point in selecting if selection is turned off
4998 if (DetermineDisplaySelection() == nsISelectionController::SELECTION_OFF) {
4999 return NS_OK;
5000 }
5001
5002 ContentOffsets offsets = GetContentOffsetsFromPoint(
5003 aPoint, SKIP_HIDDEN | IGNORE_NATIVE_ANONYMOUS_SUBTREE);
5004 if (!offsets.content) {
5005 return NS_ERROR_FAILURE;
5006 }
5007
5008 uint32_t offset;
5009 nsIFrame* frame = SelectionMovementUtils::GetFrameForNodeOffset(
5010 offsets.content, offsets.offset, offsets.associate, &offset);
5011 if (!frame) {
5012 return NS_ERROR_FAILURE;
5013 }
5014 return frame->PeekBackwardAndForward(
5015 aBeginAmountType, aEndAmountType, static_cast<int32_t>(offset),
5016 aBeginAmountType != eSelectWord, aSelectFlags);
5017}
5018
5019/**
5020 * Multiple Mouse Press -- line or paragraph selection -- for the frame.
5021 * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
5022 */
5023NS_IMETHODIMPnsresult
5024nsIFrame::HandleMultiplePress(nsPresContext* aPresContext,
5025 WidgetGUIEvent* aEvent,
5026 nsEventStatus* aEventStatus, bool aControlHeld) {
5027 NS_ENSURE_ARG_POINTER(aEvent)do { if ((__builtin_expect(!!(!(aEvent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEvent" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5027); return NS_ERROR_INVALID_POINTER; } } while (false)
;
5028 NS_ENSURE_ARG_POINTER(aEventStatus)do { if ((__builtin_expect(!!(!(aEventStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEventStatus" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5028); return NS_ERROR_INVALID_POINTER; } } while (false)
;
5029
5030 if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
5031 DetermineDisplaySelection() == nsISelectionController::SELECTION_OFF) {
5032 return NS_OK;
5033 }
5034
5035 // Find out whether we're doing line or paragraph selection.
5036 // If browser.triple_click_selects_paragraph is true, triple-click selects
5037 // paragraph. Otherwise, triple-click selects line, and quadruple-click
5038 // selects paragraph (on platforms that support quadruple-click).
5039 nsSelectionAmount beginAmount, endAmount;
5040 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
5041 if (!mouseEvent) {
5042 return NS_OK;
5043 }
5044
5045 if (mouseEvent->mClickCount == 4) {
5046 beginAmount = endAmount = eSelectParagraph;
5047 } else if (mouseEvent->mClickCount == 3) {
5048 if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
5049 beginAmount = endAmount = eSelectParagraph;
5050 } else {
5051 beginAmount = eSelectBeginLine;
5052 endAmount = eSelectEndLine;
5053 }
5054 } else if (mouseEvent->mClickCount == 2) {
5055 // We only want inline frames; PeekBackwardAndForward dislikes blocks
5056 beginAmount = endAmount = eSelectWord;
5057 } else {
5058 return NS_OK;
5059 }
5060
5061 nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
5062 mouseEvent, RelativeTo{this});
5063 return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
5064 (aControlHeld ? SELECT_ACCUMULATE : 0));
5065}
5066
5067nsresult nsIFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
5068 nsSelectionAmount aAmountForward,
5069 int32_t aStartPos, bool aJumpLines,
5070 uint32_t aSelectFlags) {
5071 nsIFrame* baseFrame = this;
5072 int32_t baseOffset = aStartPos;
5073 nsresult rv;
5074
5075 PeekOffsetOptions peekOffsetOptions{PeekOffsetOption::StopAtScroller};
5076 if (aJumpLines) {
5077 peekOffsetOptions += PeekOffsetOption::JumpLines;
5078 }
5079
5080 if (aAmountBack == eSelectWord) {
5081 // To avoid selecting the previous word when at start of word,
5082 // first move one character forward.
5083 PeekOffsetStruct pos(eSelectCharacter, eDirNext, aStartPos, nsPoint(0, 0),
5084 peekOffsetOptions);
5085 rv = PeekOffset(&pos);
5086 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5087 baseFrame = pos.mResultFrame;
5088 baseOffset = pos.mContentOffset;
5089 }
5090 }
5091
5092 // Search backward for a boundary.
5093 PeekOffsetStruct startpos(aAmountBack, eDirPrevious, baseOffset,
5094 nsPoint(0, 0), peekOffsetOptions);
5095 rv = baseFrame->PeekOffset(&startpos);
5096 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5097 return rv;
5098 }
5099
5100 // If the backward search stayed within the same frame, search forward from
5101 // that position for the end boundary; but if it crossed out to a sibling or
5102 // ancestor, start from the original position.
5103 if (startpos.mResultFrame == baseFrame) {
5104 baseOffset = startpos.mContentOffset;
5105 } else {
5106 baseFrame = this;
5107 baseOffset = aStartPos;
5108 }
5109
5110 PeekOffsetStruct endpos(aAmountForward, eDirNext, baseOffset, nsPoint(0, 0),
5111 peekOffsetOptions);
5112 rv = baseFrame->PeekOffset(&endpos);
5113 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5114 return rv;
5115 }
5116
5117 // Keep frameSelection alive.
5118 RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
5119
5120 const nsFrameSelection::FocusMode focusMode =
5121 (aSelectFlags & SELECT_ACCUMULATE)
5122 ? nsFrameSelection::FocusMode::kMultiRangeSelection
5123 : nsFrameSelection::FocusMode::kCollapseToNewPoint;
5124 rv = frameSelection->HandleClick(
5125 MOZ_KnownLive(startpos.mResultContent)(startpos.mResultContent) /* bug 1636889 */,
5126 startpos.mContentOffset, startpos.mContentOffset, focusMode,
5127 CaretAssociationHint::After);
5128 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5129 return rv;
5130 }
5131
5132 rv = frameSelection->HandleClick(
5133 MOZ_KnownLive(endpos.mResultContent)(endpos.mResultContent) /* bug 1636889 */,
5134 endpos.mContentOffset, endpos.mContentOffset,
5135 nsFrameSelection::FocusMode::kExtendSelection,
5136 CaretAssociationHint::Before);
5137 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5138 return rv;
5139 }
5140 if (aAmountBack == eSelectWord) {
5141 frameSelection->SetClickSelectionType(ClickSelectionType::Double);
5142 } else if (aAmountBack == eSelectParagraph) {
5143 frameSelection->SetClickSelectionType(ClickSelectionType::Triple);
5144 }
5145
5146 // maintain selection
5147 return frameSelection->MaintainSelection(aAmountBack);
5148}
5149
5150NS_IMETHODIMPnsresult nsIFrame::HandleDrag(nsPresContext* aPresContext,
5151 WidgetGUIEvent* aEvent,
5152 nsEventStatus* aEventStatus) {
5153 MOZ_ASSERT(aEvent->mClass == eMouseEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mClass == eMouseEventClass)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aEvent->mClass == eMouseEventClass))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mClass == eMouseEventClass"
" (" "HandleDrag can only handle mouse event" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mClass == eMouseEventClass"
") (" "HandleDrag can only handle mouse event" ")"); do { *(
(volatile int*)__null) = 5154; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
5154 "HandleDrag can only handle mouse event")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mClass == eMouseEventClass)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aEvent->mClass == eMouseEventClass))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mClass == eMouseEventClass"
" (" "HandleDrag can only handle mouse event" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mClass == eMouseEventClass"
") (" "HandleDrag can only handle mouse event" ")"); do { *(
(volatile int*)__null) = 5154; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5155
5156 NS_ENSURE_ARG_POINTER(aEventStatus)do { if ((__builtin_expect(!!(!(aEventStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aEventStatus" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5156); return NS_ERROR_INVALID_POINTER; } } while (false)
;
5157
5158 RefPtr<nsFrameSelection> frameselection = GetFrameSelection();
5159 if (!frameselection) {
5160 return NS_OK;
5161 }
5162
5163 bool mouseDown = frameselection->GetDragState();
5164 if (!mouseDown) {
5165 return NS_OK;
5166 }
5167
5168 nsIFrame* scrollbar =
5169 nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::Scrollbar);
5170 if (!scrollbar) {
5171 // XXX Do we really need to exclude non-selectable content here?
5172 // GetContentOffsetsFromPoint can handle it just fine, although some
5173 // other stuff might not like it.
5174 // NOTE: DetermineDisplaySelection() returns SELECTION_OFF for
5175 // non-selectable frames.
5176 if (DetermineDisplaySelection() == nsISelectionController::SELECTION_OFF) {
5177 return NS_OK;
5178 }
5179 }
5180
5181 frameselection->StopAutoScrollTimer();
5182
5183 // Check if we are dragging in a table cell
5184 nsCOMPtr<nsIContent> parentContent;
5185 int32_t contentOffset;
5186 TableSelectionMode target;
5187 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
5188 mozilla::PresShell* presShell = aPresContext->PresShell();
5189 nsresult result;
5190 result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
5191 getter_AddRefs(parentContent),
5192 &contentOffset, &target);
5193
5194 AutoWeakFrame weakThis = this;
5195 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1))) && parentContent) {
5196 result = frameselection->HandleTableSelection(parentContent, contentOffset,
5197 target, mouseEvent);
5198 if (NS_WARN_IF(NS_FAILED(result))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(result
)), 0))), "NS_FAILED(result)", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5198)
) {
5199 return result;
5200 }
5201 } else {
5202 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
5203 RelativeTo{this});
5204 frameselection->HandleDrag(this, pt);
5205 }
5206
5207 // The frameselection object notifies selection listeners synchronously above
5208 // which might have killed us.
5209 if (!weakThis.IsAlive()) {
5210 return NS_OK;
5211 }
5212
5213 // get the nearest scrollframe
5214 nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetNearestScrollableFrame(
5215 this, nsLayoutUtils::SCROLLABLE_SAME_DOC |
5216 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
5217
5218 if (scrollFrame) {
5219 nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
5220 if (capturingFrame) {
5221 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
5222 mouseEvent, RelativeTo{capturingFrame});
5223 frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
5224 }
5225 }
5226
5227 return NS_OK;
5228}
5229
5230/**
5231 * This static method handles part of the nsIFrame::HandleRelease in a way
5232 * which doesn't rely on the nsFrame object to stay alive.
5233 */
5234MOZ_CAN_RUN_SCRIPT_BOUNDARY static nsresult HandleFrameSelection(
5235 nsFrameSelection* aFrameSelection, nsIFrame::ContentOffsets& aOffsets,
5236 bool aHandleTableSel, int32_t aContentOffsetForTableSel,
5237 TableSelectionMode aTargetForTableSel,
5238 nsIContent* aParentContentForTableSel, WidgetGUIEvent* aEvent,
5239 const nsEventStatus* aEventStatus) {
5240 if (!aFrameSelection) {
5241 return NS_OK;
5242 }
5243
5244 nsresult rv = NS_OK;
5245
5246 if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
5247 if (!aHandleTableSel) {
5248 if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
5249 return NS_ERROR_FAILURE;
5250 }
5251
5252 // We are doing this to simulate what we would have done on HandlePress.
5253 // We didn't do it there to give the user an opportunity to drag
5254 // the text, but since they didn't drag, we want to place the
5255 // caret.
5256 // However, we'll use the mouse position from the release, since:
5257 // * it's easier
5258 // * that's the normal click position to use (although really, in
5259 // the normal case, small movements that don't count as a drag
5260 // can do selection)
5261 aFrameSelection->SetDragState(true);
5262
5263 const nsFrameSelection::FocusMode focusMode =
5264 aFrameSelection->IsShiftDownInDelayedCaretData()
5265 ? nsFrameSelection::FocusMode::kExtendSelection
5266 : nsFrameSelection::FocusMode::kCollapseToNewPoint;
5267 rv = aFrameSelection->HandleClick(
5268 MOZ_KnownLive(aOffsets.content)(aOffsets.content) /* bug 1636889 */,
5269 aOffsets.StartOffset(), aOffsets.EndOffset(), focusMode,
5270 aOffsets.associate);
5271 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5272 return rv;
5273 }
5274 } else if (aParentContentForTableSel) {
5275 aFrameSelection->SetDragState(false);
5276 rv = aFrameSelection->HandleTableSelection(
5277 aParentContentForTableSel, aContentOffsetForTableSel,
5278 aTargetForTableSel, aEvent->AsMouseEvent());
5279 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5280 return rv;
5281 }
5282 }
5283 aFrameSelection->SetDelayedCaretData(0);
5284 }
5285
5286 aFrameSelection->SetDragState(false);
5287 aFrameSelection->StopAutoScrollTimer();
5288
5289 return NS_OK;
5290}
5291
5292NS_IMETHODIMPnsresult nsIFrame::HandleRelease(nsPresContext* aPresContext,
5293 WidgetGUIEvent* aEvent,
5294 nsEventStatus* aEventStatus) {
5295 if (aEvent->mClass != eMouseEventClass) {
5296 return NS_OK;
5297 }
5298
5299 nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
5300
5301 nsCOMPtr<nsIContent> captureContent = PresShell::GetCapturingContent();
5302
5303 bool selectionOff =
5304 (DetermineDisplaySelection() == nsISelectionController::SELECTION_OFF);
5305
5306 RefPtr<nsFrameSelection> frameselection;
5307 ContentOffsets offsets;
5308 nsCOMPtr<nsIContent> parentContent;
5309 int32_t contentOffsetForTableSel = 0;
5310 TableSelectionMode targetForTableSel = TableSelectionMode::None;
5311 bool handleTableSelection = true;
5312
5313 if (!selectionOff) {
5314 frameselection = GetFrameSelection();
5315 if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
5316 // Check if the frameselection recorded the mouse going down.
5317 // If not, the user must have clicked in a part of the selection.
5318 // Place the caret before continuing!
5319
5320 if (frameselection->MouseDownRecorded()) {
5321 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
5322 aEvent, RelativeTo{this});
5323 offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
5324 handleTableSelection = false;
5325 } else {
5326 GetDataForTableSelection(frameselection, PresShell(),
5327 aEvent->AsMouseEvent(),
5328 getter_AddRefs(parentContent),
5329 &contentOffsetForTableSel, &targetForTableSel);
5330 }
5331 }
5332 }
5333
5334 // We might be capturing in some other document and the event just happened to
5335 // trickle down here. Make sure that document's frame selection is notified.
5336 // Note, this may cause the current nsFrame object to be deleted, bug 336592.
5337 RefPtr<nsFrameSelection> frameSelection;
5338 if (activeFrame != this && activeFrame->DetermineDisplaySelection() !=
5339 nsISelectionController::SELECTION_OFF) {
5340 frameSelection = activeFrame->GetFrameSelection();
5341 }
5342
5343 // Also check the selection of the capturing content which might be in a
5344 // different document.
5345 if (!frameSelection && captureContent) {
5346 if (Document* doc = captureContent->GetComposedDoc()) {
5347 mozilla::PresShell* capturingPresShell = doc->GetPresShell();
5348 if (capturingPresShell &&
5349 capturingPresShell != PresContext()->GetPresShell()) {
5350 frameSelection = capturingPresShell->FrameSelection();
5351 }
5352 }
5353 }
5354
5355 if (frameSelection) {
5356 AutoWeakFrame wf(this);
5357 frameSelection->SetDragState(false);
5358 frameSelection->StopAutoScrollTimer();
5359 if (wf.IsAlive()) {
5360 nsIScrollableFrame* scrollFrame =
5361 nsLayoutUtils::GetNearestScrollableFrame(
5362 this, nsLayoutUtils::SCROLLABLE_SAME_DOC |
5363 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
5364 if (scrollFrame) {
5365 // Perform any additional scrolling needed to maintain CSS snap point
5366 // requirements when autoscrolling is over.
5367 scrollFrame->ScrollSnap();
5368 }
5369 }
5370 }
5371
5372 // Do not call any methods of the current object after this point!!!
5373 // The object is perhaps dead!
5374
5375 return selectionOff ? NS_OK
5376 : HandleFrameSelection(
5377 frameselection, offsets, handleTableSelection,
5378 contentOffsetForTableSel, targetForTableSel,
5379 parentContent, aEvent, aEventStatus);
5380}
5381
5382struct MOZ_STACK_CLASS FrameContentRange {
5383 FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd)
5384 : content(aContent), start(aStart), end(aEnd) {}
5385 nsCOMPtr<nsIContent> content;
5386 int32_t start;
5387 int32_t end;
5388};
5389
5390// Retrieve the content offsets of a frame
5391static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
5392 nsIContent* content = aFrame->GetContent();
5393 if (!content) {
5394 NS_WARNING("Frame has no content")NS_DebugBreak(NS_DEBUG_WARNING, "Frame has no content", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsIFrame.cpp"
, 5394)
;
5395 return FrameContentRange(nullptr, -1, -1);
5396 }
5397
5398 LayoutFrameType type = aFrame->Type();
5399 if (type == LayoutFrameType::Text) {
5400 auto [offset, offsetEnd] = aFrame->GetOffsets();
5401 return FrameContentRange(content, offset, offsetEnd);
5402 }
5403
5404 if (type == LayoutFrameType::Br) {
5405 nsIContent* parent = content->GetParent();
5406 const int32_t beginOffset = parent->ComputeIndexOf_Deprecated(content);
5407 return FrameContentRange(parent, beginOffset, beginOffset);
5408 }
5409
5410 while (content->IsRootOfNativeAnonymousSubtree()) {