Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h
Warning:line 816, column 5
1st function call argument is an uninitialized value

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 PersistentBufferProvider.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/gfx/layers -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/layers -resource-dir /usr/lib/llvm-20/lib/clang/20 -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 _GLIBCXX_ASSERTIONS -D DEBUG=1 -D GOOGLE_PROTOBUF_NO_RTTI -D GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER -D MOZ_APP_VERSION=136.0a1 -D D3D_DEBUG_INFO -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/layers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/layers -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/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/canvas -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/cairo/cairo/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/media/libyuv/libyuv/include -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/skia -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia -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/sysprof-6 -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/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../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 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -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-2025-01-20-090804-167946-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp

/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.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#include "PersistentBufferProvider.h"
8
9#include "mozilla/layers/KnowsCompositor.h"
10#include "mozilla/layers/RemoteTextureMap.h"
11#include "mozilla/layers/TextureClient.h"
12#include "mozilla/layers/TextureForwarder.h"
13#include "mozilla/layers/TextureRecorded.h"
14#include "mozilla/gfx/gfxVars.h"
15#include "mozilla/gfx/CanvasManagerChild.h"
16#include "mozilla/gfx/DrawTargetWebgl.h"
17#include "mozilla/gfx/Logging.h"
18#include "mozilla/Maybe.h"
19#include "mozilla/StaticPrefs_layers.h"
20#include "pratom.h"
21#include "gfxPlatform.h"
22
23namespace mozilla {
24
25using namespace gfx;
26
27namespace layers {
28
29PersistentBufferProviderBasic::PersistentBufferProviderBasic(DrawTarget* aDt)
30 : mDrawTarget(aDt) {
31 MOZ_COUNT_CTOR(PersistentBufferProviderBasic)do { static_assert(std::is_class_v<PersistentBufferProviderBasic
>, "Token '" "PersistentBufferProviderBasic" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderBasic
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PersistentBufferProviderBasic"
, sizeof(*this)); } while (0)
;
32}
33
34PersistentBufferProviderBasic::~PersistentBufferProviderBasic() {
35 MOZ_COUNT_DTOR(PersistentBufferProviderBasic)do { static_assert(std::is_class_v<PersistentBufferProviderBasic
>, "Token '" "PersistentBufferProviderBasic" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderBasic
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PersistentBufferProviderBasic"
, sizeof(*this)); } while (0)
;
36 Destroy();
37}
38
39already_AddRefed<gfx::DrawTarget>
40PersistentBufferProviderBasic::BorrowDrawTarget(
41 const gfx::IntRect& aPersistedRect) {
42 MOZ_ASSERT(!mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mSnapshot))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 42); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSnapshot" ")"
); do { *((volatile int*)__null) = 42; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
43 RefPtr<gfx::DrawTarget> dt(mDrawTarget);
44 return dt.forget();
45}
46
47bool PersistentBufferProviderBasic::ReturnDrawTarget(
48 already_AddRefed<gfx::DrawTarget> aDT) {
49 RefPtr<gfx::DrawTarget> dt(aDT);
50 MOZ_ASSERT(mDrawTarget == dt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDrawTarget == dt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDrawTarget == dt))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mDrawTarget == dt"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 50); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDrawTarget == dt"
")"); do { *((volatile int*)__null) = 50; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
51 if (dt) {
52 // Since SkiaGL default to storing drawing command until flush
53 // we have to flush it before present.
54 dt->Flush();
55 }
56 return true;
57}
58
59already_AddRefed<gfx::SourceSurface>
60PersistentBufferProviderBasic::BorrowSnapshot(gfx::DrawTarget* aTarget) {
61 mSnapshot = mDrawTarget->Snapshot();
62 RefPtr<SourceSurface> snapshot = mSnapshot;
63 return snapshot.forget();
64}
65
66void PersistentBufferProviderBasic::ReturnSnapshot(
67 already_AddRefed<gfx::SourceSurface> aSnapshot) {
68 RefPtr<SourceSurface> snapshot = aSnapshot;
69 MOZ_ASSERT(!snapshot || snapshot == mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!snapshot || snapshot == mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!snapshot || snapshot == mSnapshot
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!snapshot || snapshot == mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 69); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!snapshot || snapshot == mSnapshot"
")"); do { *((volatile int*)__null) = 69; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
70 mSnapshot = nullptr;
71}
72
73void PersistentBufferProviderBasic::Destroy() {
74 mSnapshot = nullptr;
75 mDrawTarget = nullptr;
76}
77
78// static
79already_AddRefed<PersistentBufferProviderBasic>
80PersistentBufferProviderBasic::Create(gfx::IntSize aSize,
81 gfx::SurfaceFormat aFormat,
82 gfx::BackendType aBackend) {
83 RefPtr<DrawTarget> dt =
84 gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize,
85 aFormat);
86
87 if (dt) {
88 // This is simply to ensure the DrawTarget gets initialized, and will detect
89 // a device reset, even if we're on the main thread.
90 dt->ClearRect(Rect(0, 0, 0, 0));
91 }
92
93 if (!dt || !dt->IsValid()) {
94 return nullptr;
95 }
96
97 RefPtr<PersistentBufferProviderBasic> provider =
98 new PersistentBufferProviderBasic(dt);
99
100 return provider.forget();
101}
102
103static already_AddRefed<TextureClient> CreateTexture(
104 KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aFormat,
105 gfx::IntSize aSize, bool aWillReadFrequently = false,
106 bool aUseRemoteTexture = false) {
107 TextureAllocationFlags flags = ALLOC_DEFAULT;
108 if (aWillReadFrequently) {
109 flags = TextureAllocationFlags(flags | ALLOC_DO_NOT_ACCELERATE);
110 }
111 if (aUseRemoteTexture) {
112 flags = TextureAllocationFlags(flags | ALLOC_FORCE_REMOTE);
113 }
114 RefPtr<TextureClient> tc = TextureClient::CreateForDrawing(
115 aKnowsCompositor, aFormat, aSize, BackendSelector::Canvas,
116 TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK, flags);
117 return tc.forget();
118}
119
120// static
121already_AddRefed<PersistentBufferProviderAccelerated>
122PersistentBufferProviderAccelerated::Create(gfx::IntSize aSize,
123 gfx::SurfaceFormat aFormat,
124 KnowsCompositor* aKnowsCompositor) {
125 if (!aKnowsCompositor || !aKnowsCompositor->GetTextureForwarder() ||
126 !aKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
127 return nullptr;
128 }
129
130 if (!DrawTargetWebgl::CanCreate(aSize, aFormat)) {
131#ifdef XP_WIN
132 // Direct2D acceleration does not require DrawTargetWebgl, but still
133 // requires PersistentBufferProviderAccelerated.
134 if (!TextureData::IsRemote(aKnowsCompositor, BackendSelector::Canvas,
135 aFormat, aSize)) {
136 return nullptr;
137 }
138#else
139 return nullptr;
140#endif
141 }
142
143 RefPtr<TextureClient> texture = CreateTexture(
144 aKnowsCompositor, aFormat, aSize, false, /* aUseRemoteTexture */ true);
145 if (!texture) {
146 return nullptr;
147 }
148
149 auto* recordedTextureData =
150 texture->GetInternalData()->AsRecordedTextureData();
151 if (!recordedTextureData) {
152 MOZ_ASSERT_UNREACHABLE("unexpected to be called")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 to be called" ")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 152); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected to be called" ")"); do
{ *((volatile int*)__null) = 152; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
153 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine153 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Expected RecordedTextureData";
154 return nullptr;
155 }
156
157 RefPtr<PersistentBufferProviderAccelerated> provider =
158 new PersistentBufferProviderAccelerated(
159 recordedTextureData->mRemoteTextureOwnerId, texture);
160 return provider.forget();
161}
162
163PersistentBufferProviderAccelerated::PersistentBufferProviderAccelerated(
164 RemoteTextureOwnerId aRemoteTextureOwnerId,
165 const RefPtr<TextureClient>& aTexture)
166 : mRemoteTextureOwnerId(aRemoteTextureOwnerId), mTexture(aTexture) {
167 MOZ_COUNT_CTOR(PersistentBufferProviderAccelerated)do { static_assert(std::is_class_v<PersistentBufferProviderAccelerated
>, "Token '" "PersistentBufferProviderAccelerated" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderAccelerated
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PersistentBufferProviderAccelerated"
, sizeof(*this)); } while (0)
;
168}
169
170PersistentBufferProviderAccelerated::~PersistentBufferProviderAccelerated() {
171 MOZ_COUNT_DTOR(PersistentBufferProviderAccelerated)do { static_assert(std::is_class_v<PersistentBufferProviderAccelerated
>, "Token '" "PersistentBufferProviderAccelerated" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderAccelerated
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PersistentBufferProviderAccelerated"
, sizeof(*this)); } while (0)
;
172 Destroy();
173}
174
175void PersistentBufferProviderAccelerated::Destroy() {
176 mSnapshot = nullptr;
177 mDrawTarget = nullptr;
178
179 if (mTexture) {
180 if (mTexture->IsLocked()) {
181 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 181); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")");
do { *((volatile int*)__null) = 181; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
182 mTexture->Unlock();
183 }
184 mTexture = nullptr;
185 }
186}
187
188already_AddRefed<gfx::DrawTarget>
189PersistentBufferProviderAccelerated::BorrowDrawTarget(
190 const gfx::IntRect& aPersistedRect) {
191 if (!mDrawTarget) {
192 if (aPersistedRect.IsEmpty()) {
193 mTexture->GetInternalData()->InvalidateContents();
194 }
195 if (!mTexture->Lock(OpenMode::OPEN_READ_WRITE)) {
196 return nullptr;
197 }
198 mDrawTarget = mTexture->BorrowDrawTarget();
199 if (!mDrawTarget || !mDrawTarget->IsValid()) {
200 mDrawTarget = nullptr;
201 mTexture->Unlock();
202 return nullptr;
203 }
204 }
205 return do_AddRef(mDrawTarget);
206}
207
208bool PersistentBufferProviderAccelerated::ReturnDrawTarget(
209 already_AddRefed<gfx::DrawTarget> aDT) {
210 {
211 RefPtr<gfx::DrawTarget> dt(aDT);
212 MOZ_ASSERT(mDrawTarget == dt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDrawTarget == dt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDrawTarget == dt))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mDrawTarget == dt"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDrawTarget == dt"
")"); do { *((volatile int*)__null) = 212; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
213 if (!mDrawTarget) {
214 return false;
215 }
216 mDrawTarget = nullptr;
217 }
218 mTexture->Unlock();
219 return true;
220}
221
222already_AddRefed<gfx::SourceSurface>
223PersistentBufferProviderAccelerated::BorrowSnapshot(gfx::DrawTarget* aTarget) {
224 if (mDrawTarget) {
225 MOZ_ASSERT(mTexture->IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTexture->IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTexture->IsLocked()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mTexture->IsLocked()"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTexture->IsLocked()"
")"); do { *((volatile int*)__null) = 225; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
226 } else {
227 if (mTexture->IsLocked()) {
228 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 228); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")");
do { *((volatile int*)__null) = 228; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
229 return nullptr;
230 }
231 if (!mTexture->Lock(OpenMode::OPEN_READ)) {
232 return nullptr;
233 }
234 }
235 mSnapshot = mTexture->BorrowSnapshot();
236 return do_AddRef(mSnapshot);
237}
238
239void PersistentBufferProviderAccelerated::ReturnSnapshot(
240 already_AddRefed<gfx::SourceSurface> aSnapshot) {
241 RefPtr<SourceSurface> snapshot = aSnapshot;
242 MOZ_ASSERT(!snapshot || snapshot == mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!snapshot || snapshot == mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!snapshot || snapshot == mSnapshot
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!snapshot || snapshot == mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 242); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!snapshot || snapshot == mSnapshot"
")"); do { *((volatile int*)__null) = 242; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
243 snapshot = nullptr;
244 mTexture->ReturnSnapshot(mSnapshot.forget());
245 if (!mDrawTarget) {
246 mTexture->Unlock();
247 }
248}
249
250Maybe<SurfaceDescriptor> PersistentBufferProviderAccelerated::GetFrontBuffer() {
251 SurfaceDescriptor desc;
252 if (mTexture->GetInternalData()->Serialize(desc)) {
253 return Some(desc);
254 }
255 return Nothing();
256}
257
258bool PersistentBufferProviderAccelerated::RequiresRefresh() const {
259 return mTexture->GetInternalData()->RequiresRefresh();
260}
261
262already_AddRefed<FwdTransactionTracker>
263PersistentBufferProviderAccelerated::UseCompositableForwarder(
264 CompositableForwarder* aForwarder) {
265 return mTexture->GetInternalData()->UseCompositableForwarder(aForwarder);
266}
267
268// static
269already_AddRefed<PersistentBufferProviderShared>
270PersistentBufferProviderShared::Create(gfx::IntSize aSize,
271 gfx::SurfaceFormat aFormat,
272 KnowsCompositor* aKnowsCompositor,
273 bool aWillReadFrequently,
274 const Maybe<uint64_t>& aWindowID) {
275 if (!aKnowsCompositor || !aKnowsCompositor->GetTextureForwarder() ||
276 !aKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
277 return nullptr;
278 }
279
280 if (!StaticPrefs::layers_shared_buffer_provider_enabled()) {
281 return nullptr;
282 }
283
284#ifdef XP_WIN
285 // Bug 1285271 - Disable shared buffer provider on Windows with D2D due to
286 // instability.
287 aWillReadFrequently = true;
288#endif
289
290 RefPtr<TextureClient> texture =
291 CreateTexture(aKnowsCompositor, aFormat, aSize, aWillReadFrequently);
292 if (!texture) {
293 return nullptr;
294 }
295
296 RefPtr<PersistentBufferProviderShared> provider =
297 new PersistentBufferProviderShared(aSize, aFormat, aKnowsCompositor,
298 texture, aWillReadFrequently,
299 aWindowID);
300 return provider.forget();
301}
302
303PersistentBufferProviderShared::PersistentBufferProviderShared(
304 gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
305 KnowsCompositor* aKnowsCompositor, RefPtr<TextureClient>& aTexture,
306 bool aWillReadFrequently, const Maybe<uint64_t>& aWindowID)
307 : mSize(aSize),
308 mFormat(aFormat),
309 mKnowsCompositor(aKnowsCompositor),
310 mFront(Nothing()),
311 mWillReadFrequently(aWillReadFrequently),
312 mWindowID(aWindowID) {
313 MOZ_ASSERT(aKnowsCompositor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKnowsCompositor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aKnowsCompositor))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aKnowsCompositor"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKnowsCompositor"
")"); do { *((volatile int*)__null) = 313; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
314 if (mTextures.append(aTexture)) {
315 mBack = Some<uint32_t>(0);
316 }
317
318 // XXX KnowsCompositor could be used for mMaxAllowedTextures
319 if (gfxVars::UseWebRenderTripleBufferingWin()) {
320 ++mMaxAllowedTextures;
321 }
322
323 MOZ_COUNT_CTOR(PersistentBufferProviderShared)do { static_assert(std::is_class_v<PersistentBufferProviderShared
>, "Token '" "PersistentBufferProviderShared" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderShared
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PersistentBufferProviderShared"
, sizeof(*this)); } while (0)
;
324}
325
326PersistentBufferProviderShared::~PersistentBufferProviderShared() {
327 MOZ_COUNT_DTOR(PersistentBufferProviderShared)do { static_assert(std::is_class_v<PersistentBufferProviderShared
>, "Token '" "PersistentBufferProviderShared" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, PersistentBufferProviderShared
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PersistentBufferProviderShared"
, sizeof(*this)); } while (0)
;
328
329 if (IsActivityTracked()) {
330 if (auto* cm = CanvasManagerChild::Get()) {
331 cm->GetActiveResourceTracker()->RemoveObject(this);
332 } else {
333 MOZ_ASSERT_UNREACHABLE("Tracked but no CanvasManagerChild!")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: "
"Tracked but no CanvasManagerChild!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Tracked but no CanvasManagerChild!"
")"); do { *((volatile int*)__null) = 333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
334 }
335 }
336
337 Destroy();
338}
339
340bool PersistentBufferProviderShared::SetKnowsCompositor(
341 KnowsCompositor* aKnowsCompositor, bool& aOutLostFrontTexture) {
342 MOZ_ASSERT(aKnowsCompositor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKnowsCompositor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aKnowsCompositor))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aKnowsCompositor"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKnowsCompositor"
")"); do { *((volatile int*)__null) = 342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
343 MOZ_ASSERT(!aOutLostFrontTexture)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aOutLostFrontTexture)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aOutLostFrontTexture))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!aOutLostFrontTexture"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aOutLostFrontTexture"
")"); do { *((volatile int*)__null) = 343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
344 if (!aKnowsCompositor) {
345 return false;
346 }
347
348 if (mKnowsCompositor == aKnowsCompositor) {
349 // The forwarder should not change most of the time.
350 return true;
351 }
352
353 if (IsActivityTracked()) {
354 if (auto* cm = CanvasManagerChild::Get()) {
355 cm->GetActiveResourceTracker()->RemoveObject(this);
356 } else {
357 MOZ_ASSERT_UNREACHABLE("Tracked but no CanvasManagerChild!")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: "
"Tracked but no CanvasManagerChild!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Tracked but no CanvasManagerChild!"
")"); do { *((volatile int*)__null) = 357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
358 }
359 }
360
361 if (mKnowsCompositor->GetTextureForwarder() !=
362 aKnowsCompositor->GetTextureForwarder() ||
363 mKnowsCompositor->GetCompositorBackendType() !=
364 aKnowsCompositor->GetCompositorBackendType()) {
365 // We are going to be used with an different and/or incompatible forwarder.
366 // This should be extremely rare. We have to copy the front buffer into a
367 // texture that is compatible with the new forwarder.
368
369 // Grab the current front buffer.
370 RefPtr<TextureClient> prevTexture = GetTexture(mFront);
371
372 // Get rid of everything else
373 Destroy();
374
375 if (prevTexture && !prevTexture->IsValid()) {
376 aOutLostFrontTexture = true;
377 } else if (prevTexture && prevTexture->IsValid()) {
378 RefPtr<TextureClient> newTexture =
379 CreateTexture(aKnowsCompositor, mFormat, mSize, mWillReadFrequently);
380
381 MOZ_ASSERT(newTexture)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newTexture)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newTexture))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("newTexture", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newTexture" ")"
); do { *((volatile int*)__null) = 381; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
382 if (!newTexture) {
383 return false;
384 }
385
386 // If we early-return in one of the following branches, we will
387 // leave the buffer provider in an empty state, since we called
388 // Destroy. Not ideal but at least we won't try to use it with a
389 // an incompatible ipc channel.
390
391 if (!newTexture->Lock(OpenMode::OPEN_WRITE)) {
392 return false;
393 }
394
395 if (!prevTexture->Lock(OpenMode::OPEN_READ)) {
396 newTexture->Unlock();
397 return false;
398 }
399
400 bool success =
401 prevTexture->CopyToTextureClient(newTexture, nullptr, nullptr);
402
403 prevTexture->Unlock();
404 newTexture->Unlock();
405
406 if (!success) {
407 return false;
408 }
409
410 if (!mTextures.append(newTexture)) {
411 return false;
412 }
413 mFront = Some<uint32_t>(mTextures.length() - 1);
414 mBack = mFront;
415 }
416 }
417
418 mKnowsCompositor = aKnowsCompositor;
419
420 return true;
421}
422
423TextureClient* PersistentBufferProviderShared::GetTexture(
424 const Maybe<uint32_t>& aIndex) {
425 if (aIndex.isNothing() || !CheckIndex(aIndex.value())) {
426 return nullptr;
427 }
428 return mTextures[aIndex.value()];
429}
430
431already_AddRefed<gfx::DrawTarget>
432PersistentBufferProviderShared::BorrowDrawTarget(
433 const gfx::IntRect& aPersistedRect) {
434 if (!mKnowsCompositor->GetTextureForwarder() ||
8
Assuming the condition is false
10
Taking false branch
435 !mKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
9
Assuming the condition is false
436 return nullptr;
437 }
438
439 auto* cm = CanvasManagerChild::Get();
440 if (NS_WARN_IF(!cm)NS_warn_if_impl(!cm, "!cm", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 440)
) {
11
Assuming 'cm' is non-null
12
Taking false branch
441 return nullptr;
442 }
443
444 MOZ_ASSERT(!mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mSnapshot))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSnapshot" ")"
); do { *((volatile int*)__null) = 444; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13
Taking false branch
14
Loop condition is false. Exiting loop
445
446 if (IsActivityTracked()) {
15
Taking false branch
447 cm->GetActiveResourceTracker()->MarkUsed(this);
448 } else {
449 cm->GetActiveResourceTracker()->AddObject(this);
450 }
451
452 if (mDrawTarget) {
16
Taking false branch
453 RefPtr<gfx::DrawTarget> dt(mDrawTarget);
454 return dt.forget();
455 }
456
457 auto previousBackBuffer = mBack;
458
459 TextureClient* tex = GetTexture(mBack);
460
461 // First try to reuse the current back buffer. If we can do that it means
462 // we can skip copying its content to the new back buffer.
463 if (tex
16.1
'tex' is null
16.1
'tex' is null
16.1
'tex' is null
16.1
'tex' is null
16.1
'tex' is null
&& tex->IsReadLocked()) {
464 // The back buffer is currently used by the compositor, we can't draw
465 // into it.
466 tex = nullptr;
467 }
468
469 if (!tex
16.2
'tex' is null
16.2
'tex' is null
16.2
'tex' is null
16.2
'tex' is null
16.2
'tex' is null
) {
17
Taking true branch
470 // Try to grab an already allocated texture if any is available.
471 for (uint32_t i = 0; i < mTextures.length(); ++i) {
18
Assuming the condition is true
19
Loop condition is true. Entering loop body
472 if (!mTextures[i]->IsReadLocked()) {
20
Assuming the condition is true
21
Taking true branch
473 mBack = Some(i);
474 tex = mTextures[i];
475 break;
476 }
477 }
478 }
479
480 if (!tex) {
22
Execution continues on line 480
23
Assuming 'tex' is non-null
24
Taking false branch
481 // We have to allocate a new texture.
482 if (mTextures.length() >= mMaxAllowedTextures) {
483 // We should never need to buffer that many textures, something's wrong.
484 // In theory we throttle the main thread when the compositor can't keep
485 // up, so we shoud never get in a situation where we sent 4 textures to
486 // the compositor and the latter has not released any of them. In
487 // practice, though, the throttling mechanism appears to have some issues,
488 // especially when switching between layer managers (during tab-switch).
489 // To make sure we don't get too far ahead of the compositor, we send a
490 // sync ping to the compositor thread...
491 mKnowsCompositor->SyncWithCompositor(mWindowID);
492 // ...and try again.
493 for (uint32_t i = 0; i < mTextures.length(); ++i) {
494 if (!mTextures[i]->IsReadLocked()) {
495 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Managed to allocate after flush.";
496 mBack = Some(i);
497 tex = mTextures[i];
498 break;
499 }
500 }
501
502 if (!tex) {
503 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Unexpected BufferProvider over-production.";
504 // It would be pretty bad to keep piling textures up at this point so we
505 // call NotifyInactive to remove some of our textures.
506 NotifyInactive();
507 // Give up now. The caller can fall-back to a non-shared buffer
508 // provider.
509 return nullptr;
510 }
511 }
512
513 RefPtr<TextureClient> newTexture =
514 CreateTexture(mKnowsCompositor, mFormat, mSize, mWillReadFrequently);
515
516 MOZ_ASSERT(newTexture)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newTexture)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newTexture))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("newTexture", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newTexture" ")"
); do { *((volatile int*)__null) = 516; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
517 if (newTexture) {
518 if (mTextures.append(newTexture)) {
519 tex = newTexture;
520 mBack = Some<uint32_t>(mTextures.length() - 1);
521 }
522 }
523 }
524
525 if (!tex
24.1
'tex' is non-null
24.1
'tex' is non-null
24.1
'tex' is non-null
24.1
'tex' is non-null
24.1
'tex' is non-null
) {
25
Taking false branch
526 return nullptr;
527 }
528
529 if (mPermanentBackBuffer) {
26
Taking false branch
530 // If we have a permanent back buffer lock the selected one and switch to
531 // the permanent one before borrowing the DrawTarget. We will copy back into
532 // the selected one when ReturnDrawTarget is called, before we make it the
533 // new front buffer.
534 if (!tex->Lock(OpenMode::OPEN_WRITE)) {
535 return nullptr;
536 }
537 tex = mPermanentBackBuffer;
538 } else {
539 // Copy from the previous back buffer if required.
540 Maybe<TextureClientAutoLock> autoReadLock;
27
Calling defaulted default constructor for 'Maybe<mozilla::layers::TextureClientAutoLock>'
38
Returning from default constructor for 'Maybe<mozilla::layers::TextureClientAutoLock>'
541 TextureClient* previous = nullptr;
542 if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) {
543 if (tex->HasSynchronization()) {
544 // We are about to read lock a texture that is in use by the compositor
545 // and has synchronization. To prevent possible future contention we
546 // switch to using a permanent back buffer.
547 mPermanentBackBuffer = CreateTexture(mKnowsCompositor, mFormat, mSize,
548 mWillReadFrequently);
549 if (!mPermanentBackBuffer) {
550 return nullptr;
551 }
552 if (!tex->Lock(OpenMode::OPEN_WRITE)) {
553 return nullptr;
554 }
555 tex = mPermanentBackBuffer;
556 }
557
558 previous = GetTexture(previousBackBuffer);
559 if (previous) {
560 autoReadLock.emplace(previous, OpenMode::OPEN_READ);
561 }
562 }
563
564 if (!tex->Lock(OpenMode::OPEN_READ_WRITE)) {
39
Assuming the condition is false
565 return nullptr;
566 }
567
568 if (autoReadLock.isSome() && autoReadLock->Succeeded() && previous) {
569 DebugOnly<bool> success =
570 previous->CopyToTextureClient(tex, &aPersistedRect, nullptr);
571 MOZ_ASSERT(success)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(success)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(success))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("success", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 571); AnnotateMozCrashReason("MOZ_ASSERT" "(" "success" ")"
); do { *((volatile int*)__null) = 571; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
572 }
573 }
40
Calling implicit destructor for 'Maybe<mozilla::layers::TextureClientAutoLock>'
41
Calling '~MaybeStorage'
574
575 mDrawTarget = tex->BorrowDrawTarget();
576 if (mDrawTarget) {
577 // This is simply to ensure the DrawTarget gets initialized, and will detect
578 // a device reset, even if we're on the main thread.
579 mDrawTarget->ClearRect(Rect(0, 0, 0, 0));
580
581 if (!mDrawTarget->IsValid()) {
582 mDrawTarget = nullptr;
583 }
584 }
585
586 RefPtr<gfx::DrawTarget> dt(mDrawTarget);
587 return dt.forget();
588}
589
590bool PersistentBufferProviderShared::ReturnDrawTarget(
591 already_AddRefed<gfx::DrawTarget> aDT) {
592 RefPtr<gfx::DrawTarget> dt(aDT);
593 MOZ_ASSERT(mDrawTarget == dt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDrawTarget == dt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDrawTarget == dt))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mDrawTarget == dt"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 593); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDrawTarget == dt"
")"); do { *((volatile int*)__null) = 593; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
594 // Can't change the current front buffer while its snapshot is borrowed!
595 MOZ_ASSERT(!mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mSnapshot))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSnapshot" ")"
); do { *((volatile int*)__null) = 595; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
596
597 TextureClient* back = GetTexture(mBack);
598 MOZ_ASSERT(back)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(back))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("back", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 598); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back" ")"); do
{ *((volatile int*)__null) = 598; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
599
600 mDrawTarget = nullptr;
601 dt = nullptr;
602
603 // If we have a permanent back buffer we have actually been drawing to that,
604 // so now we must copy to the shared one.
605 if (mPermanentBackBuffer && back) {
606 DebugOnly<bool> success =
607 mPermanentBackBuffer->CopyToTextureClient(back, nullptr, nullptr);
608 MOZ_ASSERT(success)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(success)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(success))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("success", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 608); AnnotateMozCrashReason("MOZ_ASSERT" "(" "success" ")"
); do { *((volatile int*)__null) = 608; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
609
610 // Let our permanent back buffer know that we have finished drawing.
611 mPermanentBackBuffer->EndDraw();
612 }
613
614 if (back) {
615 back->Unlock();
616 mFront = mBack;
617 }
618
619 return !!back;
620}
621
622TextureClient* PersistentBufferProviderShared::GetTextureClient() {
623 // Can't access the front buffer while drawing.
624 MOZ_ASSERT(!mDrawTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDrawTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDrawTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDrawTarget", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 624); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDrawTarget"
")"); do { *((volatile int*)__null) = 624; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Taking false branch
2
Loop condition is false. Exiting loop
625 TextureClient* texture = GetTexture(mFront);
626 if (!texture) {
3
Assuming 'texture' is non-null
4
Taking false branch
627 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
628 << "PersistentBufferProviderShared: front buffer unavailable";
629 return nullptr;
630 }
631
632 // Sometimes, for example on tab switch, we re-forward our texture. So if we
633 // are and it is still read locked, then borrow and return our DrawTarget to
634 // force it to be copied to a texture that we will safely read lock.
635 if (texture->IsReadLocked()) {
5
Assuming the condition is true
6
Taking true branch
636 RefPtr<DrawTarget> dt =
637 BorrowDrawTarget(IntRect(0, 0, mSize.width, mSize.height));
7
Calling 'PersistentBufferProviderShared::BorrowDrawTarget'
638
639 // If we failed to borrow a DrawTarget then all our textures must be read
640 // locked or we failed to create one, so we'll just return the current front
641 // buffer even though that might lead to contention.
642 if (dt) {
643 ReturnDrawTarget(dt.forget());
644 texture = GetTexture(mFront);
645 if (!texture) {
646 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
647 << "PersistentBufferProviderShared: front buffer unavailable";
648 return nullptr;
649 }
650 }
651 } else {
652 // If it isn't read locked then make sure it is set as updated, so that we
653 // will always read lock even if we've forwarded the texture before.
654 texture->SetUpdated();
655 }
656
657 return texture;
658}
659
660already_AddRefed<gfx::SourceSurface>
661PersistentBufferProviderShared::BorrowSnapshot(gfx::DrawTarget* aTarget) {
662 // If we have a permanent back buffer we can always use that to snapshot.
663 if (mPermanentBackBuffer) {
664 mSnapshot = mPermanentBackBuffer->BorrowSnapshot();
665 return do_AddRef(mSnapshot);
666 }
667
668 if (mDrawTarget) {
669 auto back = GetTexture(mBack);
670 if (NS_WARN_IF(!back)NS_warn_if_impl(!back, "!back", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 670)
|| NS_WARN_IF(!back->IsLocked())NS_warn_if_impl(!back->IsLocked(), "!back->IsLocked()",
"/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 670)
) {
671 return nullptr;
672 }
673 mSnapshot = back->BorrowSnapshot();
674 return do_AddRef(mSnapshot);
675 }
676
677 auto front = GetTexture(mFront);
678 if (NS_WARN_IF(!front)NS_warn_if_impl(!front, "!front", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 678)
|| NS_WARN_IF(front->IsLocked())NS_warn_if_impl(front->IsLocked(), "front->IsLocked()",
"/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 678)
) {
679 return nullptr;
680 }
681
682 if (front->IsReadLocked() && front->HasSynchronization()) {
683 // We are about to read lock a texture that is in use by the compositor and
684 // has synchronization. To prevent possible future contention we switch to
685 // using a permanent back buffer.
686 mPermanentBackBuffer =
687 CreateTexture(mKnowsCompositor, mFormat, mSize, mWillReadFrequently);
688 if (!mPermanentBackBuffer ||
689 !mPermanentBackBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
690 return nullptr;
691 }
692
693 if (!front->Lock(OpenMode::OPEN_READ)) {
694 return nullptr;
695 }
696
697 DebugOnly<bool> success =
698 front->CopyToTextureClient(mPermanentBackBuffer, nullptr, nullptr);
699 MOZ_ASSERT(success)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(success)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(success))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("success", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "success" ")"
); do { *((volatile int*)__null) = 699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
700 front->Unlock();
701 mSnapshot = mPermanentBackBuffer->BorrowSnapshot();
702 return do_AddRef(mSnapshot);
703 }
704
705 if (!front->Lock(OpenMode::OPEN_READ)) {
706 return nullptr;
707 }
708
709 mSnapshot = front->BorrowSnapshot();
710
711 return do_AddRef(mSnapshot);
712}
713
714void PersistentBufferProviderShared::ReturnSnapshot(
715 already_AddRefed<gfx::SourceSurface> aSnapshot) {
716 RefPtr<SourceSurface> snapshot = aSnapshot;
717 MOZ_ASSERT(!snapshot || snapshot == mSnapshot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!snapshot || snapshot == mSnapshot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!snapshot || snapshot == mSnapshot
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!snapshot || snapshot == mSnapshot", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 717); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!snapshot || snapshot == mSnapshot"
")"); do { *((volatile int*)__null) = 717; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
718
719 mSnapshot = nullptr;
720 snapshot = nullptr;
721
722 if (mDrawTarget || mPermanentBackBuffer) {
723 return;
724 }
725
726 auto front = GetTexture(mFront);
727 if (front) {
728 front->Unlock();
729 }
730}
731
732void PersistentBufferProviderShared::NotifyInactive() {
733 ClearCachedResources();
734}
735
736void PersistentBufferProviderShared::ClearCachedResources() {
737 RefPtr<TextureClient> front = GetTexture(mFront);
738 RefPtr<TextureClient> back = GetTexture(mBack);
739
740 // Clear all textures (except the front and back ones that we just kept).
741 mTextures.clear();
742 mPermanentBackBuffer = nullptr;
743
744 if (back) {
745 if (mTextures.append(back)) {
746 mBack = Some<uint32_t>(0);
747 }
748 if (front == back) {
749 mFront = mBack;
750 }
751 }
752
753 if (front && front != back) {
754 if (mTextures.append(front)) {
755 mFront = Some<uint32_t>(mTextures.length() - 1);
756 }
757 }
758}
759
760void PersistentBufferProviderShared::Destroy() {
761 mSnapshot = nullptr;
762 mDrawTarget = nullptr;
763
764 if (mPermanentBackBuffer) {
765 mPermanentBackBuffer->Unlock();
766 mPermanentBackBuffer = nullptr;
767 }
768
769 for (auto& texture : mTextures) {
770 if (texture && texture->IsLocked()) {
771 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/PersistentBufferProvider.cpp"
, 771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")");
do { *((volatile int*)__null) = 771; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
772 texture->Unlock();
773 }
774 }
775
776 mTextures.clear();
777}
778
779} // namespace layers
780} // namespace mozilla

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h

1/* -*- Mode: C++; tab-width: 2; 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/* A class for optional values and in-place lazy construction. */
8
9#ifndef mozilla_Maybe_h
10#define mozilla_Maybe_h
11
12#include <functional>
13#include <new> // for placement new
14#include <ostream>
15#include <type_traits>
16#include <utility>
17
18#include "mozilla/Alignment.h"
19#include "mozilla/Assertions.h"
20#include "mozilla/Attributes.h"
21#include "mozilla/MaybeStorageBase.h"
22#include "mozilla/MemoryChecking.h"
23#include "mozilla/OperatorNewExtensions.h"
24#include "mozilla/Poison.h"
25#include "mozilla/ThreadSafety.h"
26
27class nsCycleCollectionTraversalCallback;
28
29template <typename T>
30inline void CycleCollectionNoteChild(
31 nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName,
32 uint32_t aFlags);
33
34namespace mozilla {
35
36struct Nothing {};
37
38inline constexpr bool operator==(const Nothing&, const Nothing&) {
39 return true;
40}
41
42template <class T>
43class Maybe;
44
45namespace detail {
46
47// You would think that poisoning Maybe instances could just be a call
48// to mozWritePoison. Unfortunately, using a simple call to
49// mozWritePoison generates poor code on MSVC for small structures. The
50// generated code contains (always not-taken) branches and does a bunch
51// of setup for `rep stos{l,q}`, even though we know at compile time
52// exactly how many words we're poisoning. Instead, we're going to
53// force MSVC to generate the code we want via recursive templates.
54
55// Write the given poisonValue into p at offset*sizeof(uintptr_t).
56template <size_t offset>
57inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) {
58 memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue,
59 sizeof(poisonValue));
60}
61
62template <size_t Offset, size_t NOffsets>
63struct InlinePoisoner {
64 static void poison(void* p, const uintptr_t poisonValue) {
65 WritePoisonAtOffset<Offset>(p, poisonValue);
66 InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue);
67 }
68};
69
70template <size_t N>
71struct InlinePoisoner<N, N> {
72 static void poison(void*, const uintptr_t) {
73 // All done!
74 }
75};
76
77// We can't generate inline code for large structures, though, because we'll
78// blow out recursive template instantiation limits, and the code would be
79// bloated to boot. So provide a fallback to the out-of-line poisoner.
80template <size_t ObjectSize>
81struct OutOfLinePoisoner {
82 static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) {
83 mozWritePoison(p, ObjectSize);
84 }
85};
86
87template <typename T>
88inline void PoisonObject(T* p) {
89 const uintptr_t POISON = mozPoisonValue();
90 std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)),
91 InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
92 OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON);
93}
94
95template <typename T>
96struct MaybePoisoner {
97 static const size_t N = sizeof(T);
98
99 static void poison(void* aPtr) {
100#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
101 if (N >= sizeof(uintptr_t)) {
102 PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr));
103 }
104#endif
105 MOZ_MAKE_MEM_UNDEFINED(aPtr, N)do { } while (0);
106 }
107};
108
109template <typename T,
110 bool TriviallyDestructibleAndCopyable =
111 IsTriviallyDestructibleAndCopyable<T>,
112 bool Copyable = std::is_copy_constructible_v<T>,
113 bool Movable = std::is_move_constructible_v<T>>
114class Maybe_CopyMove_Enabler;
115
116#define MOZ_MAYBE_COPY_OPS() \
117 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \
118 if (downcast(aOther).isSome()) { \
119 downcast(*this).emplace(*downcast(aOther)); \
120 } \
121 } \
122 \
123 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \
124 return downcast(*this).template operator= <T>(downcast(aOther)); \
125 }
126
127#define MOZ_MAYBE_MOVE_OPS() \
128 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \
129 if (downcast(aOther).isSome()) { \
130 downcast(*this).emplace(std::move(*downcast(aOther))); \
131 downcast(aOther).reset(); \
132 } \
133 } \
134 \
135 constexpr Maybe_CopyMove_Enabler& operator=( \
136 Maybe_CopyMove_Enabler&& aOther) { \
137 downcast(*this).template operator= <T>(std::move(downcast(aOther))); \
138 \
139 return *this; \
140 }
141
142#define MOZ_MAYBE_DOWNCAST() \
143 static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
144 return static_cast<Maybe<T>&>(aObj); \
145 } \
146 static constexpr const Maybe<T>& downcast( \
147 const Maybe_CopyMove_Enabler& aObj) { \
148 return static_cast<const Maybe<T>&>(aObj); \
149 }
150
151template <typename T>
152class Maybe_CopyMove_Enabler<T, true, true, true> {
153 public:
154 Maybe_CopyMove_Enabler() = default;
155
156 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
157 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
158 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
159 downcast(aOther).reset();
160 }
161 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
162 downcast(aOther).reset();
163 return *this;
164 }
165
166 private:
167 MOZ_MAYBE_DOWNCAST()
168};
169
170template <typename T>
171class Maybe_CopyMove_Enabler<T, true, false, true> {
172 public:
173 Maybe_CopyMove_Enabler() = default;
174
175 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
176 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
177 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
178 downcast(aOther).reset();
179 }
180 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
181 downcast(aOther).reset();
182 return *this;
183 }
184
185 private:
186 MOZ_MAYBE_DOWNCAST()
187};
188
189template <typename T>
190class Maybe_CopyMove_Enabler<T, false, true, true> {
191 public:
192 Maybe_CopyMove_Enabler() = default;
193
194 MOZ_MAYBE_COPY_OPS()
195 MOZ_MAYBE_MOVE_OPS()
196
197 private:
198 MOZ_MAYBE_DOWNCAST()
199};
200
201template <typename T>
202class Maybe_CopyMove_Enabler<T, false, false, true> {
203 public:
204 Maybe_CopyMove_Enabler() = default;
205
206 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
207 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
208 MOZ_MAYBE_MOVE_OPS()
209
210 private:
211 MOZ_MAYBE_DOWNCAST()
212};
213
214template <typename T>
215class Maybe_CopyMove_Enabler<T, false, true, false> {
216 public:
217 Maybe_CopyMove_Enabler() = default;
218
219 MOZ_MAYBE_COPY_OPS()
220 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
221 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
222
223 private:
224 MOZ_MAYBE_DOWNCAST()
225};
226
227template <typename T, bool TriviallyDestructibleAndCopyable>
228class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false,
229 false> {
230 public:
231 Maybe_CopyMove_Enabler() = default;
232
233 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
234 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
235 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
236 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
237};
238
239#undef MOZ_MAYBE_COPY_OPS
240#undef MOZ_MAYBE_MOVE_OPS
241#undef MOZ_MAYBE_DOWNCAST
242
243template <typename T, bool TriviallyDestructibleAndCopyable =
244 IsTriviallyDestructibleAndCopyable<T>>
245struct MaybeStorage;
246
247template <typename T>
248struct MaybeStorage<T, false> : MaybeStorageBase<T> {
249 protected:
250 char mIsSome = false; // not bool -- guarantees minimal space consumption
251
252 constexpr MaybeStorage() = default;
29
Calling defaulted default constructor for 'MaybeStorageBase<mozilla::layers::TextureClientAutoLock, false>'
34
Returning from default constructor for 'MaybeStorageBase<mozilla::layers::TextureClientAutoLock, false>'
35
Returning without writing to 'this->mStorage.val.mChecked'
253 explicit MaybeStorage(const T& aVal)
254 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
255 explicit MaybeStorage(T&& aVal)
256 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
257
258 template <typename... Args>
259 explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
260 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
261 mIsSome{true} {}
262
263 public:
264 // Copy and move operations are no-ops, since copying is moving is implemented
265 // by Maybe_CopyMove_Enabler.
266
267 MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {}
268 MaybeStorage& operator=(const MaybeStorage&) { return *this; }
269 MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {}
270 MaybeStorage& operator=(MaybeStorage&&) { return *this; }
271
272 ~MaybeStorage() {
273 if (mIsSome
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
) {
42
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
43
Calling implicit destructor for 'MaybeStorageBase<mozilla::layers::TextureClientAutoLock, false>'
44
Calling '~Union'
277};
278
279template <typename T>
280struct MaybeStorage<T, true> : MaybeStorageBase<T> {
281 protected:
282 char mIsSome = false; // not bool -- guarantees minimal space consumption
283
284 constexpr MaybeStorage() = default;
285 constexpr explicit MaybeStorage(const T& aVal)
286 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
287 constexpr explicit MaybeStorage(T&& aVal)
288 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
289
290 template <typename... Args>
291 constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
292 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
293 mIsSome{true} {}
294};
295
296template <typename T>
297struct IsMaybeImpl : std::false_type {};
298
299template <typename T>
300struct IsMaybeImpl<Maybe<T>> : std::true_type {};
301
302template <typename T>
303using IsMaybe = IsMaybeImpl<std::decay_t<T>>;
304
305} // namespace detail
306
307template <typename T, typename U = typename std::remove_cv<
308 typename std::remove_reference<T>::type>::type>
309constexpr Maybe<U> Some(T&& aValue);
310
311/*
312 * Maybe is a container class which contains either zero or one elements. It
313 * serves two roles. It can represent values which are *semantically* optional,
314 * augmenting a type with an explicit 'Nothing' value. In this role, it provides
315 * methods that make it easy to work with values that may be missing, along with
316 * equality and comparison operators so that Maybe values can be stored in
317 * containers. Maybe values can be constructed conveniently in expressions using
318 * type inference, as follows:
319 *
320 * void doSomething(Maybe<Foo> aFoo) {
321 * if (aFoo) // Make sure that aFoo contains a value...
322 * aFoo->takeAction(); // and then use |aFoo->| to access it.
323 * } // |*aFoo| also works!
324 *
325 * doSomething(Nothing()); // Passes a Maybe<Foo> containing no value.
326 * doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
327 *
328 * You'll note that it's important to check whether a Maybe contains a value
329 * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
330 * can avoid these checks, and sometimes write more readable code, using
331 * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
332 * in the Maybe and provide a default for the 'Nothing' case. You can also use
333 * |apply()| to call a function only if the Maybe holds a value, and |map()| to
334 * transform the value in the Maybe, returning another Maybe with a possibly
335 * different type.
336 *
337 * Maybe's other role is to support lazily constructing objects without using
338 * dynamic storage. A Maybe directly contains storage for a value, but it's
339 * empty by default. |emplace()|, as mentioned above, can be used to construct a
340 * value in Maybe's storage. The value a Maybe contains can be destroyed by
341 * calling |reset()|; this will happen automatically if a Maybe is destroyed
342 * while holding a value.
343 *
344 * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
345 * value meaning 'Nothing' and any other value meaning 'Some'. You can convert
346 * from such a pointer to a Maybe value using 'ToMaybe()'.
347 *
348 * Maybe is inspired by similar types in the standard library of many other
349 * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
350 * very similar to std::optional, which was proposed for C++14 and originated in
351 * Boost. The most important differences between Maybe and std::optional are:
352 *
353 * - std::optional<T> may be compared with T. We deliberately forbid that.
354 * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
355 * lacks corresponding methods for |refOr()| and |ptrOr()|.
356 * - std::optional lacks |map()| and |apply()|, making it less suitable for
357 * functional-style code.
358 * - std::optional lacks many convenience functions that Maybe has. Most
359 * unfortunately, it lacks equivalents of the type-inferred constructor
360 * functions |Some()| and |Nothing()|.
361 */
362template <class T>
363class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
364 : private detail::MaybeStorage<T>,
365 public detail::Maybe_CopyMove_Enabler<T> {
366 template <typename, bool, bool, bool>
367 friend class detail::Maybe_CopyMove_Enabler;
368
369 template <typename U, typename V>
370 friend constexpr Maybe<V> Some(U&& aValue);
371
372 struct SomeGuard {};
373
374 template <typename U>
375 constexpr Maybe(U&& aValue, SomeGuard)
376 : detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
377
378 using detail::MaybeStorage<T>::mIsSome;
379 using detail::MaybeStorage<T>::mStorage;
380
381 void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
382
383 public:
384 using ValueType = T;
385
386 MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
28
Calling defaulted default constructor for 'MaybeStorage<mozilla::layers::TextureClientAutoLock, false>'
36
Returning from default constructor for 'MaybeStorage<mozilla::layers::TextureClientAutoLock, false>'
37
Returning without writing to 'this->mStorage.val.mChecked'
387
388 MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
389
390 template <typename... Args>
391 constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
392 : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
393
394 /**
395 * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
396 * a const U&.
397 */
398 template <typename U,
399 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
400 MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
401 if (aOther.isSome()) {
402 emplace(*aOther);
403 }
404 }
405
406 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
407 bool> = true>
408 explicit Maybe(const Maybe<U>& aOther) = delete;
409
410 /**
411 * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from
412 * a U&&.
413 */
414 template <typename U,
415 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
416 MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
417 if (aOther.isSome()) {
418 emplace(std::move(*aOther));
419 aOther.reset();
420 }
421 }
422 template <typename U,
423 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
424 explicit Maybe(Maybe<U>&& aOther) = delete;
425
426 template <typename U,
427 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
428 Maybe& operator=(const Maybe<U>& aOther) {
429 if (aOther.isSome()) {
430 if (mIsSome) {
431 ref() = aOther.ref();
432 } else {
433 emplace(*aOther);
434 }
435 } else {
436 reset();
437 }
438 return *this;
439 }
440
441 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
442 bool> = true>
443 Maybe& operator=(const Maybe<U>& aOther) = delete;
444
445 template <typename U,
446 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
447 Maybe& operator=(Maybe<U>&& aOther) {
448 if (aOther.isSome()) {
449 if (mIsSome) {
450 ref() = std::move(aOther.ref());
451 } else {
452 emplace(std::move(*aOther));
453 }
454 aOther.reset();
455 } else {
456 reset();
457 }
458
459 return *this;
460 }
461
462 template <typename U,
463 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
464 Maybe& operator=(Maybe<U>&& aOther) = delete;
465
466 constexpr Maybe& operator=(Nothing) {
467 reset();
468 return *this;
469 }
470
471 /* Methods that check whether this Maybe contains a value */
472 constexpr explicit operator bool() const { return isSome(); }
473 constexpr bool isSome() const { return mIsSome; }
474 constexpr bool isNothing() const { return !mIsSome; }
475
476 /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
477 */
478 constexpr T value() const&;
479 constexpr T value() &&;
480 constexpr T value() const&&;
481
482 /**
483 * Move the contents of this Maybe<T> out of internal storage and return it
484 * without calling the destructor. The internal storage is also reset to
485 * avoid multiple calls. Unsafe unless |isSome()|.
486 */
487 constexpr T extract() {
488 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 488); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
489 T v = std::move(mStorage.val);
490 reset();
491 return v;
492 }
493
494 /**
495 * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T>
496 * and leaving |Nothing()| in its place.
497 */
498 Maybe<T> take() { return std::exchange(*this, Nothing()); }
499
500 /*
501 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
502 * the default value provided.
503 *
504 * Note: If the value passed to aDefault is not the result of a trivial
505 * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|,
506 * use |valueOrFrom| instead, e.g.
507 * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures
508 * that the expensive expression is only evaluated when its result will
509 * actually be used.
510 */
511 template <typename V>
512 constexpr T valueOr(V&& aDefault) const {
513 if (isSome()) {
514 return ref();
515 }
516 return std::forward<V>(aDefault);
517 }
518
519 /*
520 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
521 * the value returned from the function or functor provided.
522 */
523 template <typename F>
524 constexpr T valueOrFrom(F&& aFunc) const {
525 if (isSome()) {
526 return ref();
527 }
528 return aFunc();
529 }
530
531 /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|.
532 */
533 T* ptr();
534 constexpr const T* ptr() const;
535
536 /*
537 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
538 * returns the default value provided.
539 */
540 T* ptrOr(T* aDefault) {
541 if (isSome()) {
542 return ptr();
543 }
544 return aDefault;
545 }
546
547 constexpr const T* ptrOr(const T* aDefault) const {
548 if (isSome()) {
549 return ptr();
550 }
551 return aDefault;
552 }
553
554 /*
555 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
556 * returns the value returned from the function or functor provided.
557 */
558 template <typename F>
559 T* ptrOrFrom(F&& aFunc) {
560 if (isSome()) {
561 return ptr();
562 }
563 return aFunc();
564 }
565
566 template <typename F>
567 const T* ptrOrFrom(F&& aFunc) const {
568 if (isSome()) {
569 return ptr();
570 }
571 return aFunc();
572 }
573
574 constexpr T* operator->();
575 constexpr const T* operator->() const;
576
577 /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
578 constexpr T& ref() &;
579 constexpr const T& ref() const&;
580 constexpr T&& ref() &&;
581 constexpr const T&& ref() const&&;
582
583 /*
584 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
585 * the default value provided.
586 */
587 constexpr T& refOr(T& aDefault) {
588 if (isSome()) {
589 return ref();
590 }
591 return aDefault;
592 }
593
594 constexpr const T& refOr(const T& aDefault) const {
595 if (isSome()) {
596 return ref();
597 }
598 return aDefault;
599 }
600
601 /*
602 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
603 * value returned from the function or functor provided.
604 */
605 template <typename F>
606 constexpr T& refOrFrom(F&& aFunc) {
607 if (isSome()) {
608 return ref();
609 }
610 return aFunc();
611 }
612
613 template <typename F>
614 constexpr const T& refOrFrom(F&& aFunc) const {
615 if (isSome()) {
616 return ref();
617 }
618 return aFunc();
619 }
620
621 constexpr T& operator*() &;
622 constexpr const T& operator*() const&;
623 constexpr T&& operator*() &&;
624 constexpr const T&& operator*() const&&;
625
626 /* If |isSome()|, runs the provided function or functor on the contents of
627 * this Maybe. */
628 template <typename Func>
629 constexpr Maybe& apply(Func&& aFunc) & {
630 if (isSome()) {
631 std::forward<Func>(aFunc)(ref());
632 }
633 return *this;
634 }
635
636 template <typename Func>
637 constexpr const Maybe& apply(Func&& aFunc) const& {
638 if (isSome()) {
639 std::forward<Func>(aFunc)(ref());
640 }
641 return *this;
642 }
643
644 template <typename Func>
645 constexpr Maybe& apply(Func&& aFunc) && {
646 if (isSome()) {
647 std::forward<Func>(aFunc)(extract());
648 }
649 return *this;
650 }
651
652 template <typename Func>
653 constexpr Maybe& apply(Func&& aFunc) const&& {
654 if (isSome()) {
655 std::forward<Func>(aFunc)(extract());
656 }
657 return *this;
658 }
659
660 /*
661 * If |isSome()|, runs the provided function and returns the result wrapped
662 * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same
663 * value type as what the provided function would have returned.
664 */
665 template <typename Func>
666 constexpr auto map(Func&& aFunc) & {
667 if (isSome()) {
668 return Some(std::forward<Func>(aFunc)(ref()));
669 }
670 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
671 }
672
673 template <typename Func>
674 constexpr auto map(Func&& aFunc) const& {
675 if (isSome()) {
676 return Some(std::forward<Func>(aFunc)(ref()));
677 }
678 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
679 }
680
681 template <typename Func>
682 constexpr auto map(Func&& aFunc) && {
683 if (isSome()) {
684 return Some(std::forward<Func>(aFunc)(extract()));
685 }
686 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
687 }
688
689 template <typename Func>
690 constexpr auto map(Func&& aFunc) const&& {
691 if (isSome()) {
692 return Some(std::forward<Func>(aFunc)(extract()));
693 }
694 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
695 }
696
697 /*
698 * If |isSome()|, runs the provided function or functor on the contents of
699 * this Maybe and returns the result. Note that the provided function or
700 * functor must return a Maybe<U> of any type U.
701 * If |isNothing()|, returns an empty Maybe value with the same type as what
702 * the provided function would have returned.
703 */
704 template <typename Func>
705 constexpr auto andThen(Func&& aFunc) & {
706 static_assert(std::is_invocable_v<Func, T&>);
707 using U = std::invoke_result_t<Func, T&>;
708 static_assert(detail::IsMaybe<U>::value);
709 if (isSome()) {
710 return std::invoke(std::forward<Func>(aFunc), ref());
711 }
712 return std::remove_cv_t<std::remove_reference_t<U>>{};
713 }
714
715 template <typename Func>
716 constexpr auto andThen(Func&& aFunc) const& {
717 static_assert(std::is_invocable_v<Func, const T&>);
718 using U = std::invoke_result_t<Func, const T&>;
719 static_assert(detail::IsMaybe<U>::value);
720 if (isSome()) {
721 return std::invoke(std::forward<Func>(aFunc), ref());
722 }
723 return std::remove_cv_t<std::remove_reference_t<U>>{};
724 }
725
726 template <typename Func>
727 constexpr auto andThen(Func&& aFunc) && {
728 static_assert(std::is_invocable_v<Func, T&&>);
729 using U = std::invoke_result_t<Func, T&&>;
730 static_assert(detail::IsMaybe<U>::value);
731 if (isSome()) {
732 return std::invoke(std::forward<Func>(aFunc), extract());
733 }
734 return std::remove_cv_t<std::remove_reference_t<U>>{};
735 }
736
737 template <typename Func>
738 constexpr auto andThen(Func&& aFunc) const&& {
739 static_assert(std::is_invocable_v<Func, const T&&>);
740 using U = std::invoke_result_t<Func, const T&&>;
741 static_assert(detail::IsMaybe<U>::value);
742 if (isSome()) {
743 return std::invoke(std::forward<Func>(aFunc), extract());
744 }
745 return std::remove_cv_t<std::remove_reference_t<U>>{};
746 }
747
748 /*
749 * If |isNothing()|, runs the provided function or functor and returns its
750 * result. If |isSome()|, returns the contained value wrapped in a Maybe.
751 */
752 template <typename Func>
753 constexpr Maybe orElse(Func&& aFunc) & {
754 static_assert(std::is_invocable_v<Func>);
755 using U = std::invoke_result_t<Func>;
756 static_assert(
757 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
758 if (isSome()) {
759 return *this;
760 }
761 return std::invoke(std::forward<Func>(aFunc));
762 }
763
764 template <typename Func>
765 constexpr Maybe orElse(Func&& aFunc) const& {
766 static_assert(std::is_invocable_v<Func>);
767 using U = std::invoke_result_t<Func>;
768 static_assert(
769 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
770 if (isSome()) {
771 return *this;
772 }
773 return std::invoke(std::forward<Func>(aFunc));
774 }
775
776 template <typename Func>
777 constexpr Maybe orElse(Func&& aFunc) && {
778 static_assert(std::is_invocable_v<Func>);
779 using U = std::invoke_result_t<Func>;
780 static_assert(
781 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
782 if (isSome()) {
783 return std::move(*this);
784 }
785 return std::invoke(std::forward<Func>(aFunc));
786 }
787
788 template <typename Func>
789 constexpr Maybe orElse(Func&& aFunc) const&& {
790 static_assert(std::is_invocable_v<Func>);
791 using U = std::invoke_result_t<Func>;
792 static_assert(
793 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
794 if (isSome()) {
795 return std::move(*this);
796 }
797 return std::invoke(std::forward<Func>(aFunc));
798 }
799
800 /* If |isSome()|, empties this Maybe and destroys its contents. */
801 constexpr void reset() {
802 if (isSome()) {
803 if constexpr (!std::is_trivially_destructible_v<T>) {
804 /*
805 * Static analyzer gets confused if we have Maybe<MutexAutoLock>,
806 * so we suppress thread-safety warnings here
807 */
808 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
809 ref().T::~T();
810 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
811 poisonData();
812 }
813 mIsSome = false;
814 }
815 }
816
817 /*
818 * Constructs a T value in-place in this empty Maybe<T>'s storage. The
819 * arguments to |emplace()| are the parameters to T's constructor.
820 */
821 template <typename... Args>
822 constexpr void emplace(Args&&... aArgs);
823
824 template <typename U>
825 constexpr std::enable_if_t<std::is_same_v<T, U> &&
826 std::is_copy_constructible_v<U> &&
827 !std::is_move_constructible_v<U>>
828 emplace(U&& aArgs) {
829 emplace(aArgs);
830 }
831
832 friend std::ostream& operator<<(std::ostream& aStream,
833 const Maybe<T>& aMaybe) {
834 if (aMaybe) {
835 aStream << aMaybe.ref();
836 } else {
837 aStream << "<Nothing>";
838 }
839 return aStream;
840 }
841};
842
843template <typename T>
844class Maybe<T&> {
845 public:
846 constexpr Maybe() = default;
847 constexpr MOZ_IMPLICIT Maybe(Nothing) {}
848
849 void emplace(T& aRef) { mValue = &aRef; }
850
851 /* Methods that check whether this Maybe contains a value */
852 constexpr explicit operator bool() const { return isSome(); }
853 constexpr bool isSome() const { return mValue; }
854 constexpr bool isNothing() const { return !mValue; }
855
856 T& ref() const {
857 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 857); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
858 return *mValue;
859 }
860
861 T* operator->() const { return &ref(); }
862 T& operator*() const { return ref(); }
863
864 // Deliberately not defining value and ptr accessors, as these may be
865 // confusing on a reference-typed Maybe.
866
867 // XXX Should we define refOr?
868
869 void reset() { mValue = nullptr; }
870
871 template <typename Func>
872 const Maybe& apply(Func&& aFunc) const {
873 if (isSome()) {
874 std::forward<Func>(aFunc)(ref());
875 }
876 return *this;
877 }
878
879 template <typename Func>
880 auto map(Func&& aFunc) const {
881 Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
882 if (isSome()) {
883 val.emplace(std::forward<Func>(aFunc)(ref()));
884 }
885 return val;
886 }
887
888 template <typename Func>
889 constexpr auto andThen(Func&& aFunc) const {
890 static_assert(std::is_invocable_v<Func, T&>);
891 using U = std::invoke_result_t<Func, T&>;
892 static_assert(detail::IsMaybe<U>::value);
893 if (isSome()) {
894 return std::invoke(std::forward<Func>(aFunc), ref());
895 }
896 return std::remove_cv_t<std::remove_reference_t<U>>{};
897 }
898
899 template <typename Func>
900 constexpr Maybe orElse(Func&& aFunc) const {
901 static_assert(std::is_invocable_v<Func>);
902 using U = std::invoke_result_t<Func>;
903 static_assert(
904 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
905 if (isSome()) {
906 return *this;
907 }
908 return std::invoke(std::forward<Func>(aFunc));
909 }
910
911 bool refEquals(const Maybe<T&>& aOther) const {
912 return mValue == aOther.mValue;
913 }
914
915 bool refEquals(const T& aOther) const { return mValue == &aOther; }
916
917 private:
918 T* mValue = nullptr;
919};
920
921template <typename T>
922constexpr T Maybe<T>::value() const& {
923 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 923); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
924 return ref();
925}
926
927template <typename T>
928constexpr T Maybe<T>::value() && {
929 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 929); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
930 return std::move(ref());
931}
932
933template <typename T>
934constexpr T Maybe<T>::value() const&& {
935 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 935); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 935; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
936 return std::move(ref());
937}
938
939template <typename T>
940T* Maybe<T>::ptr() {
941 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 941); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
942 return &ref();
943}
944
945template <typename T>
946constexpr const T* Maybe<T>::ptr() const {
947 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 947); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
948 return &ref();
949}
950
951template <typename T>
952constexpr T* Maybe<T>::operator->() {
953 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 953); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
954 return ptr();
955}
956
957template <typename T>
958constexpr const T* Maybe<T>::operator->() const {
959 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 959); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
960 return ptr();
961}
962
963template <typename T>
964constexpr T& Maybe<T>::ref() & {
965 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 965); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 return mStorage.val;
967}
968
969template <typename T>
970constexpr const T& Maybe<T>::ref() const& {
971 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 971); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 971; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
972 return mStorage.val;
973}
974
975template <typename T>
976constexpr T&& Maybe<T>::ref() && {
977 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 977); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 977; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
978 return std::move(mStorage.val);
979}
980
981template <typename T>
982constexpr const T&& Maybe<T>::ref() const&& {
983 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 983); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
984 return std::move(mStorage.val);
985}
986
987template <typename T>
988constexpr T& Maybe<T>::operator*() & {
989 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 989); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
990 return ref();
991}
992
993template <typename T>
994constexpr const T& Maybe<T>::operator*() const& {
995 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 995); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
996 return ref();
997}
998
999template <typename T>
1000constexpr T&& Maybe<T>::operator*() && {
1001 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1001); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1002 return std::move(ref());
1003}
1004
1005template <typename T>
1006constexpr const T&& Maybe<T>::operator*() const&& {
1007 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1007); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1007; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1008 return std::move(ref());
1009}
1010
1011template <typename T>
1012template <typename... Args>
1013constexpr void Maybe<T>::emplace(Args&&... aArgs) {
1014 MOZ_RELEASE_ASSERT(!isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1014); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!isSome()"
")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015 ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
1016 mIsSome = true;
1017}
1018
1019/*
1020 * Some() creates a Maybe<T> value containing the provided T value. If T has a
1021 * move constructor, it's used to make this as efficient as possible.
1022 *
1023 * Some() selects the type of Maybe it returns by removing any const, volatile,
1024 * or reference qualifiers from the type of the value you pass to it. This gives
1025 * it more intuitive behavior when used in expressions, but it also means that
1026 * if you need to construct a Maybe value that holds a const, volatile, or
1027 * reference value, you need to use emplace() instead.
1028 */
1029template <typename T, typename U>
1030constexpr Maybe<U> Some(T&& aValue) {
1031 return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
1032}
1033
1034template <typename T>
1035constexpr Maybe<T&> SomeRef(T& aValue) {
1036 Maybe<T&> value;
1037 value.emplace(aValue);
1038 return value;
1039}
1040
1041template <typename T>
1042constexpr Maybe<T&> ToMaybeRef(T* const aPtr) {
1043 return aPtr ? SomeRef(*aPtr) : Nothing{};
1044}
1045
1046template <typename T>
1047Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) {
1048 if (aPtr) {
1049 return Some(*aPtr);
1050 }
1051 return Nothing();
1052}
1053
1054/*
1055 * Two Maybe<T> values are equal if
1056 * - both are Nothing, or
1057 * - both are Some, and the values they contain are equal.
1058 */
1059template <typename T>
1060constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1061 static_assert(!std::is_reference_v<T>,
1062 "operator== is not defined for Maybe<T&>, compare values or "
1063 "addresses explicitly instead");
1064 if (aLHS.isNothing() != aRHS.isNothing()) {
1065 return false;
1066 }
1067 return aLHS.isNothing() || *aLHS == *aRHS;
1068}
1069
1070template <typename T>
1071constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1072 return !(aLHS == aRHS);
1073}
1074
1075/*
1076 * We support comparison to Nothing to allow reasonable expressions like:
1077 * if (maybeValue == Nothing()) { ... }
1078 */
1079template <typename T>
1080constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
1081 return aLHS.isNothing();
1082}
1083
1084template <typename T>
1085constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
1086 return !(aLHS == aRHS);
1087}
1088
1089template <typename T>
1090constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
1091 return aRHS.isNothing();
1092}
1093
1094template <typename T>
1095constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
1096 return !(aLHS == aRHS);
1097}
1098
1099/*
1100 * Maybe<T> values are ordered in the same way T values are ordered, except that
1101 * Nothing comes before anything else.
1102 */
1103template <typename T>
1104constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1105 if (aLHS.isNothing()) {
1106 return aRHS.isSome();
1107 }
1108 if (aRHS.isNothing()) {
1109 return false;
1110 }
1111 return *aLHS < *aRHS;
1112}
1113
1114template <typename T>
1115constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1116 return !(aLHS < aRHS || aLHS == aRHS);
1117}
1118
1119template <typename T>
1120constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1121 return aLHS < aRHS || aLHS == aRHS;
1122}
1123
1124template <typename T>
1125constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1126 return !(aLHS < aRHS);
1127}
1128
1129template <typename T>
1130inline void ImplCycleCollectionTraverse(
1131 nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField,
1132 const char* aName, uint32_t aFlags = 0) {
1133 if (aField) {
1134 ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags);
1135 }
1136}
1137
1138template <typename T>
1139inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) {
1140 if (aField) {
1141 ImplCycleCollectionUnlink(aField.ref());
1142 }
1143}
1144
1145} // namespace mozilla
1146
1147#endif /* mozilla_Maybe_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MaybeStorageBase.h

1/* -*- Mode: C++; tab-width: 2; 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/* Internal storage class used e.g. by Maybe and Result. This file doesn't
8 * contain any public declarations. */
9
10#ifndef mfbt_MaybeStorageBase_h
11#define mfbt_MaybeStorageBase_h
12
13#include <type_traits>
14#include <utility>
15
16namespace mozilla::detail {
17
18template <typename T>
19constexpr bool IsTriviallyDestructibleAndCopyable =
20 std::is_trivially_destructible_v<T> &&
21 (std::is_trivially_copy_constructible_v<T> ||
22 !std::is_copy_constructible_v<T>);
23
24template <typename T, bool TriviallyDestructibleAndCopyable =
25 IsTriviallyDestructibleAndCopyable<T>>
26struct MaybeStorageBase;
27
28template <typename T>
29struct MaybeStorageBase<T, false> {
30 protected:
31 using NonConstT = std::remove_const_t<T>;
32
33 union Union {
34 Union() {}
31
Returning without writing to 'this->val.mChecked'
35 explicit Union(const T& aVal) : val{aVal} {}
36 template <typename U,
37 typename = std::enable_if_t<std::is_move_constructible_v<U>>>
38 explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
39 template <typename... Args>
40 explicit Union(std::in_place_t, Args&&... aArgs)
41 : val{std::forward<Args>(aArgs)...} {}
42
43 ~Union() {}
45
Calling '~TextureClientAutoLock'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 constexpr MaybeStorageBase() = default;
30
Calling default constructor for 'Union'
32
Returning from default constructor for 'Union'
33
Returning without writing to 'this->mStorage.val.mChecked'
50 explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
51 explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
52 template <typename... Args>
53 explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
54 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
55
56 const T* addr() const { return &mStorage.val; }
57 T* addr() { return &mStorage.val; }
58};
59
60template <typename T>
61struct MaybeStorageBase<T, true> {
62 protected:
63 using NonConstT = std::remove_const_t<T>;
64
65 union Union {
66 constexpr Union() : empty() {}
67 constexpr explicit Union(const T& aVal) : val{aVal} {}
68 constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
69 template <typename... Args>
70 constexpr explicit Union(std::in_place_t, Args&&... aArgs)
71 : val{std::forward<Args>(aArgs)...} {}
72
73 NonConstT val;
74 char empty;
75 } mStorage;
76
77 public:
78 constexpr MaybeStorageBase() = default;
79 constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
80 constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
81
82 template <typename... Args>
83 constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
84 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
85
86 constexpr const T* addr() const { return &mStorage.val; }
87 constexpr T* addr() { return &mStorage.val; }
88};
89
90} // namespace mozilla::detail
91
92#endif

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h

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#ifndef nsINode_h___
8#define nsINode_h___
9
10#include "mozilla/DoublyLinkedList.h"
11#include "mozilla/Likely.h"
12#include "mozilla/UniquePtr.h"
13#include "nsCOMPtr.h" // for member, local
14#include "nsGkAtoms.h" // for nsGkAtoms::baseURIProperty
15#include "mozilla/dom/NodeInfo.h" // member (in nsCOMPtr)
16#include "nsIWeakReference.h"
17#include "nsIMutationObserver.h"
18#include "nsNodeInfoManager.h" // for use in NodePrincipal()
19#include "nsPropertyTable.h" // for typedefs
20#include "mozilla/ErrorResult.h"
21#include "mozilla/LinkedList.h"
22#include "mozilla/MemoryReporting.h"
23#include "mozilla/dom/EventTarget.h" // for base class
24#include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext
25#include "mozilla/dom/DOMString.h"
26#include "mozilla/dom/BindingDeclarations.h"
27#include "mozilla/dom/NodeBinding.h"
28#include "nsTHashtable.h"
29#include <iosfwd>
30
31// Including 'windows.h' will #define GetClassInfo to something else.
32#ifdef XP_WIN
33# ifdef GetClassInfo
34# undef GetClassInfo
35# endif
36#endif
37
38class AttrArray;
39class nsAttrChildContentList;
40template <typename T>
41class nsCOMArray;
42class nsDOMAttributeMap;
43class nsGenericHTMLElement;
44class nsIAnimationObserver;
45class nsIContent;
46class nsIContentSecurityPolicy;
47class nsIFrame;
48class nsIFormControl;
49class nsIHTMLCollection;
50class nsMultiMutationObserver;
51class nsINode;
52class nsINodeList;
53class nsIPrincipal;
54class nsIURI;
55class nsNodeSupportsWeakRefTearoff;
56class nsDOMMutationObserver;
57class nsRange;
58class nsWindowSizes;
59
60namespace mozilla {
61class EventListenerManager;
62struct StyleSelectorList;
63template <typename T>
64class Maybe;
65class PresShell;
66class TextEditor;
67namespace dom {
68/**
69 * @return true if aChar is what the WHATWG defines as a 'ascii whitespace'.
70 * https://infra.spec.whatwg.org/#ascii-whitespace
71 */
72inline bool IsSpaceCharacter(char16_t aChar) {
73 return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' ||
74 aChar == '\f';
75}
76inline bool IsSpaceCharacter(char aChar) {
77 return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' ||
78 aChar == '\f';
79}
80class AbstractRange;
81class AccessibleNode;
82template <typename T>
83class AncestorsOfTypeIterator;
84struct BoxQuadOptions;
85struct ConvertCoordinateOptions;
86class DocGroup;
87class Document;
88class DocumentFragment;
89class DocumentOrShadowRoot;
90class DOMPoint;
91class DOMQuad;
92class DOMRectReadOnly;
93class Element;
94class EventHandlerNonNull;
95template <typename T>
96class FlatTreeAncestorsOfTypeIterator;
97template <typename T>
98class InclusiveAncestorsOfTypeIterator;
99template <typename T>
100class InclusiveFlatTreeAncestorsOfTypeIterator;
101class LinkStyle;
102class MutationObservers;
103template <typename T>
104class Optional;
105class OwningNodeOrString;
106class SelectionNodeCache;
107template <typename>
108class Sequence;
109class ShadowRoot;
110class SVGUseElement;
111class Text;
112class TextOrElementOrDocument;
113struct DOMPointInit;
114struct GetRootNodeOptions;
115enum class CallerType : uint32_t;
116} // namespace dom
117} // namespace mozilla
118
119#define NODE_FLAG_BIT(n_)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (n_)))
\
120 (nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_)))
121
122enum : uint32_t {
123 // This bit will be set if the node has a listener manager.
124 NODE_HAS_LISTENERMANAGER = NODE_FLAG_BIT(0)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (0)))
,
125
126 // Whether this node has had any properties set on it
127 NODE_HAS_PROPERTIES = NODE_FLAG_BIT(1)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (1)))
,
128
129 // Whether the node has some ancestor, possibly itself, that is native
130 // anonymous. This includes ancestors crossing XBL scopes, in cases when an
131 // XBL binding is attached to an element which has a native anonymous
132 // ancestor. This flag is set-once: once a node has it, it must not be
133 // removed.
134 // NOTE: Should only be used on nsIContent nodes
135 NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = NODE_FLAG_BIT(2)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (2)))
,
136
137 // Whether this node is the root of a native anonymous (from the perspective
138 // of its parent) subtree. This flag is set-once: once a node has it, it
139 // must not be removed.
140 // NOTE: Should only be used on nsIContent nodes
141 NODE_IS_NATIVE_ANONYMOUS_ROOT = NODE_FLAG_BIT(3)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (3)))
,
142
143 NODE_IS_EDITABLE = NODE_FLAG_BIT(4)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (4)))
,
144
145 // Whether the node participates in a shadow tree.
146 NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(5)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (5)))
,
147
148 // This node needs to go through frame construction to get a frame (or
149 // undisplayed entry).
150 NODE_NEEDS_FRAME = NODE_FLAG_BIT(6)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (6)))
,
151
152 // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
153 // This should be set on every node on the flattened tree path between the
154 // node(s) with NODE_NEEDS_FRAME and the root content.
155 NODE_DESCENDANTS_NEED_FRAMES = NODE_FLAG_BIT(7)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (7)))
,
156
157 // Set if the node has the accesskey attribute set.
158 NODE_HAS_ACCESSKEY = NODE_FLAG_BIT(8)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (8)))
,
159
160 NODE_HAS_BEEN_IN_UA_WIDGET = NODE_FLAG_BIT(9)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (9)))
,
161
162 // Set if the node has a nonce value and a header delivered CSP.
163 NODE_HAS_NONCE_AND_HEADER_CSP = NODE_FLAG_BIT(10)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (10)))
,
164
165 NODE_KEEPS_DOMARENA = NODE_FLAG_BIT(11)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (11)))
,
166
167 NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(12)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (12)))
,
168
169 NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT = NODE_FLAG_BIT(13)(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED
+ (13)))
,
170
171 // Remaining bits are node type specific.
172 NODE_TYPE_SPECIFIC_BITS_OFFSET = 14
173};
174
175// Flags for selectors that persist to the DOM node.
176enum class NodeSelectorFlags : uint32_t {
177 // Node has an :empty or :-moz-only-whitespace selector
178 HasEmptySelector = 1 << 0,
179
180 /// A child of the node has a selector such that any insertion,
181 /// removal, or appending of children requires restyling the parent, if the
182 /// parent is an element. If the parent is the shadow root, the child's
183 /// siblings are restyled.
184 HasSlowSelector = 1 << 1,
185
186 /// A child of the node has a :first-child, :-moz-first-node,
187 /// :only-child, :last-child or :-moz-last-node selector.
188 HasEdgeChildSelector = 1 << 2,
189
190 /// A child of the node has a selector such that any insertion or
191 /// removal of children requires restyling later siblings of that
192 /// element. Additionally (in this manner it is stronger than
193 /// NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
194 /// other content tree changes (e.g., the child changes to or from
195 /// matching :empty due to a grandchild insertion or removal), the
196 /// child's later siblings must also be restyled.
197 HasSlowSelectorLaterSiblings = 1 << 3,
198
199 /// HasSlowSelector* was set by the presence of :nth (But not of).
200 HasSlowSelectorNth = 1 << 4,
201
202 /// A child of this node might be matched by :nth-child(.. of <selector>) or
203 /// :nth-last-child(.. of <selector>). If a DOM mutation may have caused the
204 /// selector to either match or no longer match that child, the child's
205 /// siblings are restyled.
206 HasSlowSelectorNthOf = 1 << 5,
207
208 /// All instances of :nth flags.
209 HasSlowSelectorNthAll = HasSlowSelectorNthOf | HasSlowSelectorNth,
210
211 /// Set of selector flags that may trigger a restyle on DOM append, with
212 /// restyle on siblings or a single parent (And perhaps their subtrees).
213 AllSimpleRestyleFlagsForAppend = HasEmptySelector | HasSlowSelector |
214 HasEdgeChildSelector | HasSlowSelectorNthAll,
215
216 /// Set of selector flags that may trigger a restyle as a result of any
217 /// DOM mutation.
218 AllSimpleRestyleFlags =
219 AllSimpleRestyleFlagsForAppend | HasSlowSelectorLaterSiblings,
220
221 // This node was evaluated as an anchor for a relative selector.
222 RelativeSelectorAnchor = 1 << 6,
223
224 // This node was evaluated as an anchor for a relative selector, and that
225 // relative selector was not the subject of the overall selector.
226 RelativeSelectorAnchorNonSubject = 1 << 7,
227
228 // This node's sibling(s) performed a relative selector search to this node.
229 RelativeSelectorSearchDirectionSibling = 1 << 8,
230
231 // This node's ancestor(s) performed a relative selector search to this node.
232 RelativeSelectorSearchDirectionAncestor = 1 << 9,
233
234 // This node's sibling(s) and ancestor(s), and/or this node's ancestor's
235 // sibling(s) performed a relative selector search to this node.
236 RelativeSelectorSearchDirectionAncestorSibling =
237 RelativeSelectorSearchDirectionSibling |
238 RelativeSelectorSearchDirectionAncestor,
239};
240
241MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(NodeSelectorFlags)inline constexpr mozilla::CastableTypedEnumResult<NodeSelectorFlags
> operator |( NodeSelectorFlags a, NodeSelectorFlags b) { typedef
mozilla::CastableTypedEnumResult<NodeSelectorFlags> Result
; typedef mozilla::detail::UnsignedIntegerTypeForEnum<NodeSelectorFlags
>::Type U; return Result(NodeSelectorFlags(U(a) | U(b))); }
inline NodeSelectorFlags& operator |=(NodeSelectorFlags &
a, NodeSelectorFlags b) { return a = a | b; } inline constexpr
mozilla::CastableTypedEnumResult<NodeSelectorFlags> operator
&( NodeSelectorFlags a, NodeSelectorFlags b) { typedef mozilla
::CastableTypedEnumResult<NodeSelectorFlags> Result; typedef
mozilla::detail::UnsignedIntegerTypeForEnum<NodeSelectorFlags
>::Type U; return Result(NodeSelectorFlags(U(a) & U(b)
)); } inline NodeSelectorFlags& operator &=(NodeSelectorFlags
& a, NodeSelectorFlags b) { return a = a & b; } inline
constexpr mozilla::CastableTypedEnumResult<NodeSelectorFlags
> operator ^( NodeSelectorFlags a, NodeSelectorFlags b) { typedef
mozilla::CastableTypedEnumResult<NodeSelectorFlags> Result
; typedef mozilla::detail::UnsignedIntegerTypeForEnum<NodeSelectorFlags
>::Type U; return Result(NodeSelectorFlags(U(a) ^ U(b))); }
inline NodeSelectorFlags& operator ^=(NodeSelectorFlags &
a, NodeSelectorFlags b) { return a = a ^ b; } inline constexpr
mozilla::CastableTypedEnumResult<NodeSelectorFlags> operator
~(NodeSelectorFlags a) { typedef mozilla::CastableTypedEnumResult
<NodeSelectorFlags> Result; typedef mozilla::detail::UnsignedIntegerTypeForEnum
<NodeSelectorFlags>::Type U; return Result(NodeSelectorFlags
(~(U(a)))); }
;
242
243enum class BatchRemovalOrder {
244 FrontToBack,
245 BackToFront,
246};
247
248struct BatchRemovalState {
249 bool mIsFirst = true;
250};
251
252// Make sure we have space for our bits
253#define ASSERT_NODE_FLAGS_SPACE(n)static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= sizeof
(nsWrapperCache::FlagsType) * 8, "Not enough space for our bits"
)
\
254 static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= \
255 sizeof(nsWrapperCache::FlagsType) * 8, \
256 "Not enough space for our bits")
257ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET)static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (NODE_TYPE_SPECIFIC_BITS_OFFSET
) <= sizeof(nsWrapperCache::FlagsType) * 8, "Not enough space for our bits"
)
;
258
259/**
260 * Class used to detect unexpected mutations. To use the class create an
261 * nsMutationGuard on the stack before unexpected mutations could occur.
262 * You can then at any time call Mutated to check if any unexpected mutations
263 * have occurred.
264 */
265class nsMutationGuard {
266 public:
267 nsMutationGuard() { mStartingGeneration = sGeneration; }
268
269 /**
270 * Returns true if any unexpected mutations have occurred. You can pass in
271 * an 8-bit ignore count to ignore a number of expected mutations.
272 *
273 * We don't need to care about overflow because subtraction of uint64_t's is
274 * finding the difference between two elements of the group Z < 2^64. Once
275 * we know the difference between two elements we only need to check that is
276 * less than the given number of mutations to know less than that many
277 * mutations occured. Assuming constant 1ns mutations it would take 584
278 * years for sGeneration to fully wrap around so we can ignore a guard living
279 * through a full wrap around.
280 */
281 bool Mutated(uint8_t aIgnoreCount) {
282 return (sGeneration - mStartingGeneration) > aIgnoreCount;
283 }
284
285 // This function should be called whenever a mutation that we want to keep
286 // track of happen. For now this is only done when children are added or
287 // removed, but we might do it for attribute changes too in the future.
288 static void DidMutate() { sGeneration++; }
289
290 private:
291 // This is the value sGeneration had when the guard was constructed.
292 uint64_t mStartingGeneration;
293
294 // This value is incremented on every mutation, for the life of the process.
295 static uint64_t sGeneration;
296};
297
298/**
299 * A class that implements nsIWeakReference
300 */
301class nsNodeWeakReference final : public nsIWeakReference {
302 public:
303 explicit nsNodeWeakReference(nsINode* aNode);
304
305 // nsISupports
306 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
307
308 // nsIWeakReference
309 NS_DECL_NSIWEAKREFERENCEvirtual nsresult QueryReferentFromScript(const nsIID & uuid
, void * * result) override; virtual size_t SizeOfOnlyThis(mozilla
::MallocSizeOf aMallocSizeOf) override;
310
311 void NoticeNodeDestruction() { mObject = nullptr; }
312
313 private:
314 ~nsNodeWeakReference();
315};
316
317// This should be used for any nsINode sub-class that has fields of its own
318// that it needs to measure; any sub-class that doesn't use it will inherit
319// AddSizeOfExcludingThis from its super-class. AddSizeOfIncludingThis() need
320// not be defined, it is inherited from nsINode.
321#define NS_DECL_ADDSIZEOFEXCLUDINGTHISvirtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes
, size_t* aNodeSize) const override;
\
322 virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes, \
323 size_t* aNodeSize) const override;
324
325// IID for the nsINode interface
326// Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
327#define NS_INODE_IID{0x70ba4547, 0x7699, 0x44fc, {0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1
, 0xf9, 0x0a}}
\
328 {0x70ba4547, 0x7699, 0x44fc, {0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a}}
329
330/**
331 * An internal interface that abstracts some DOMNode-related parts that both
332 * nsIContent and Document share. An instance of this interface has a list
333 * of nsIContent children and provides access to them.
334 */
335class nsINode : public mozilla::dom::EventTarget {
336#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
337 void AssertInvariantsOnNodeInfoChange();
338#endif
339 public:
340 using BoxQuadOptions = mozilla::dom::BoxQuadOptions;
341 using ConvertCoordinateOptions = mozilla::dom::ConvertCoordinateOptions;
342 using DocGroup = mozilla::dom::DocGroup;
343 using Document = mozilla::dom::Document;
344 using DOMPoint = mozilla::dom::DOMPoint;
345 using DOMPointInit = mozilla::dom::DOMPointInit;
346 using DOMQuad = mozilla::dom::DOMQuad;
347 using DOMRectReadOnly = mozilla::dom::DOMRectReadOnly;
348 using OwningNodeOrString = mozilla::dom::OwningNodeOrString;
349 using TextOrElementOrDocument = mozilla::dom::TextOrElementOrDocument;
350 using CallerType = mozilla::dom::CallerType;
351 using ErrorResult = mozilla::ErrorResult;
352
353 // XXXbz Maybe we should codegen a class holding these constants and
354 // inherit from it...
355 static const auto ELEMENT_NODE = mozilla::dom::Node_Binding::ELEMENT_NODE;
356 static const auto ATTRIBUTE_NODE = mozilla::dom::Node_Binding::ATTRIBUTE_NODE;
357 static const auto TEXT_NODE = mozilla::dom::Node_Binding::TEXT_NODE;
358 static const auto CDATA_SECTION_NODE =
359 mozilla::dom::Node_Binding::CDATA_SECTION_NODE;
360 static const auto ENTITY_REFERENCE_NODE =
361 mozilla::dom::Node_Binding::ENTITY_REFERENCE_NODE;
362 static const auto ENTITY_NODE = mozilla::dom::Node_Binding::ENTITY_NODE;
363 static const auto PROCESSING_INSTRUCTION_NODE =
364 mozilla::dom::Node_Binding::PROCESSING_INSTRUCTION_NODE;
365 static const auto COMMENT_NODE = mozilla::dom::Node_Binding::COMMENT_NODE;
366 static const auto DOCUMENT_NODE = mozilla::dom::Node_Binding::DOCUMENT_NODE;
367 static const auto DOCUMENT_TYPE_NODE =
368 mozilla::dom::Node_Binding::DOCUMENT_TYPE_NODE;
369 static const auto DOCUMENT_FRAGMENT_NODE =
370 mozilla::dom::Node_Binding::DOCUMENT_FRAGMENT_NODE;
371 static const auto NOTATION_NODE = mozilla::dom::Node_Binding::NOTATION_NODE;
372 static const auto MAX_NODE_TYPE = NOTATION_NODE;
373
374 void* operator new(size_t aSize, nsNodeInfoManager* aManager);
375 void* operator new(size_t aSize) = delete;
376 void operator delete(void* aPtr);
377
378 template <class T>
379 using Sequence = mozilla::dom::Sequence<T>;
380
381 NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)template <typename T, typename U> struct COMTypeInfo;
382
383 // The |aNodeSize| outparam on this function is where the actual node size
384 // value is put. It gets added to the appropriate value within |aSizes| by
385 // AddSizeOfNodeTree().
386 //
387 // Among the sub-classes that inherit (directly or indirectly) from nsINode,
388 // measurement of the following members may be added later if DMD finds it is
389 // worthwhile:
390 // - nsGenericHTMLElement: mForm, mFieldSet
391 // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539)
392 // - HTMLBodyElement: mContentStyleRule
393 // - HTMLDataListElement: mOptions
394 // - HTMLFieldSetElement: mElements, mDependentElements, mFirstLegend
395 // - HTMLFormElement: many!
396 // - HTMLFrameSetElement: mRowSpecs, mColSpecs
397 // - HTMLInputElement: mInputData, mFiles, mFileList, mStaticDocfileList
398 // - nsHTMLMapElement: mAreas
399 // - HTMLMediaElement: many!
400 // - nsHTMLOutputElement: mDefaultValue, mTokenList
401 // - nsHTMLRowElement: mCells
402 // - nsHTMLSelectElement: mOptions, mRestoreState
403 // - nsHTMLTableElement: mTBodies, mRows, mTableInheritedAttributes
404 // - nsHTMLTableSectionElement: mRows
405 // - nsHTMLTextAreaElement: mControllers, mState
406 //
407 // The following members don't need to be measured:
408 // - nsIContent: mPrimaryFrame, because it's non-owning and measured elsewhere
409 //
410 virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes,
411 size_t* aNodeSize) const;
412
413 // SizeOfIncludingThis doesn't need to be overridden by sub-classes because
414 // sub-classes of nsINode are guaranteed to be laid out in memory in such a
415 // way that |this| points to the start of the allocated object, even in
416 // methods of nsINode's sub-classes, so aSizes.mState.mMallocSizeOf(this) is
417 // always safe to call no matter which object it was invoked on.
418 void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const;
419
420 friend class nsNodeWeakReference;
421 friend class nsNodeSupportsWeakRefTearoff;
422 friend class AttrArray;
423
424#ifdef MOZILLA_INTERNAL_API1
425 explicit nsINode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
426#endif
427
428 virtual ~nsINode();
429
430 bool IsContainerNode() const {
431 return IsElement() || IsDocument() || IsDocumentFragment();
432 }
433
434 /**
435 * Returns true if the node is a HTMLTemplate element.
436 */
437 bool IsTemplateElement() const { return IsHTMLElement(nsGkAtoms::_template); }
438
439 bool IsSlotable() const { return IsElement() || IsText(); }
440
441 /**
442 * Returns true if this is a document node.
443 */
444 bool IsDocument() const {
445 // One less pointer-chase than checking NodeType().
446 return !GetParentNode() && IsInUncomposedDoc();
447 }
448
449 /**
450 * Return this node as a document. Asserts IsDocument().
451 *
452 * This is defined inline in Document.h.
453 */
454 inline Document* AsDocument();
455 inline const Document* AsDocument() const;
456
457 /**
458 * Returns true if this is a document fragment node.
459 */
460 bool IsDocumentFragment() const {
461 return NodeType() == DOCUMENT_FRAGMENT_NODE;
462 }
463
464 virtual bool IsHTMLFormControlElement() const { return false; }
465
466 /**
467 * https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant
468 *
469 * @param aNode must not be nullptr.
470 */
471 bool IsInclusiveDescendantOf(const nsINode* aNode) const;
472
473 /**
474 * https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant
475 *
476 * @param aNode must not be nullptr.
477 */
478 bool IsShadowIncludingInclusiveDescendantOf(const nsINode* aNode) const;
479
480 /**
481 * Returns true if the given node is this node or one of its descendants
482 * in the "flat tree."
483 *
484 * @param aNode must not be nullptr.
485 */
486 bool IsInclusiveFlatTreeDescendantOf(const nsINode* aNode) const;
487
488 /**
489 * Return this node as a document fragment. Asserts IsDocumentFragment().
490 *
491 * This is defined inline in DocumentFragment.h.
492 */
493 inline mozilla::dom::DocumentFragment* AsDocumentFragment();
494 inline const mozilla::dom::DocumentFragment* AsDocumentFragment() const;
495
496 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*> aGivenProto) final;
497
498 /**
499 * Hook for constructing JS::ubi::Concrete specializations for memory
500 * reporting. Specializations are defined in NodeUbiReporting.h.
501 */
502 virtual void ConstructUbiNode(void* storage) = 0;
503
504 /**
505 * returns true if we are in priviliged code or
506 * layout.css.getBoxQuads.enabled == true.
507 */
508 static bool HasBoxQuadsSupport(JSContext* aCx, JSObject* /* unused */);
509
510 protected:
511 /**
512 * WrapNode is called from WrapObject to actually wrap this node, WrapObject
513 * does some additional checks and fix-up that's common to all nodes. WrapNode
514 * should just call the DOM binding's Wrap function.
515 *
516 * aGivenProto is the prototype to use (or null if the default one should be
517 * used) and should just be passed directly on to the DOM binding's Wrap
518 * function.
519 */
520 virtual JSObject* WrapNode(JSContext* aCx,
521 JS::Handle<JSObject*> aGivenProto) = 0;
522
523 public:
524 mozilla::dom::ParentObject GetParentObject()
525 const; // Implemented in Document.h
526
527 /**
528 * Returns the first child of a node or the first child of
529 * a template element's content if the provided node is a
530 * template element.
531 */
532 nsIContent* GetFirstChildOfTemplateOrNode();
533
534 /**
535 * Return the scope chain parent for this node, for use in things
536 * like event handler compilation. Returning null means to use the
537 * global object as the scope chain parent.
538 */
539 virtual nsINode* GetScopeChainParent() const;
540
541 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetParentFlexElement();
542
543 /**
544 * Returns the nearest inclusive open popover for a given node, see
545 * https://html.spec.whatwg.org/multipage/popover.html#nearest-inclusive-open-popover
546 */
547 mozilla::dom::Element* GetNearestInclusiveOpenPopover() const;
548
549 /**
550 * https://html.spec.whatwg.org/multipage/popover.html#nearest-inclusive-target-popover-for-invoker
551 */
552 mozilla::dom::Element* GetNearestInclusiveTargetPopoverForInvoker() const;
553
554 nsGenericHTMLElement* GetEffectiveInvokeTargetElement() const;
555
556 /**
557 * https://html.spec.whatwg.org/multipage/popover.html#popover-target-element
558 */
559 nsGenericHTMLElement* GetEffectivePopoverTargetElement() const;
560
561 /**
562 * https://html.spec.whatwg.org/multipage/popover.html#topmost-clicked-popover
563 */
564 mozilla::dom::Element* GetTopmostClickedPopover() const;
565
566 bool IsNode() const final { return true; }
567
568 NS_IMPL_FROMEVENTTARGET_HELPER(nsINode, IsNode())template <typename T> static auto FromEventTarget( T&
aEventTarget) -> decltype(static_cast< nsINode*>(&
aEventTarget)) { return aEventTarget.IsNode() ? static_cast<
nsINode*>(&aEventTarget) : nullptr; } template <typename
T> static nsINode* FromEventTarget( T* aEventTarget) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(aEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 568); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEventTarget"
")"); do { *((volatile int*)__null) = 568; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); return FromEventTarget
(*aEventTarget); } template <typename T> static nsINode
* FromEventTargetOrNull( T* aEventTarget) { return aEventTarget
? FromEventTarget(*aEventTarget) : nullptr; } template <typename
T> static auto FromEventTarget(const T& aEventTarget)
-> decltype(static_cast<const nsINode*>(&aEventTarget
)) { return aEventTarget.IsNode() ? static_cast<const nsINode
*>(&aEventTarget) : nullptr; } template <typename T
> static const nsINode* FromEventTarget(const T* aEventTarget
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(aEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 568); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEventTarget"
")"); do { *((volatile int*)__null) = 568; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); return FromEventTarget
(*aEventTarget); } template <typename T> static const nsINode
* FromEventTargetOrNull(const T* aEventTarget) { return aEventTarget
? FromEventTarget(*aEventTarget) : nullptr; } template <typename
T> static nsINode* FromEventTarget(T&& aEventTarget
) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!!aEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!!aEventTarget))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!!aEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 568); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!!aEventTarget"
")"); do { *((volatile int*)__null) = 568; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); return aEventTarget
->IsNode() ? static_cast<nsINode*>(static_cast<EventTarget
*>(aEventTarget)) : nullptr; } template <typename T>
static nsINode* FromEventTargetOrNull(T&& aEventTarget
) { return aEventTarget ? FromEventTarget(aEventTarget) : nullptr
; }
569
570 /**
571 * Return whether the node is an Element node. Faster than using `NodeType()`.
572 */
573 bool IsElement() const { return GetBoolFlag(NodeIsElement); }
574
575 virtual bool IsTextControlElement() const { return false; }
576 virtual bool IsGenericHTMLFormControlElementWithState() const {
577 return false;
578 }
579
580 // Returns non-null if this element subclasses `LinkStyle`.
581 virtual const mozilla::dom::LinkStyle* AsLinkStyle() const { return nullptr; }
582 mozilla::dom::LinkStyle* AsLinkStyle() {
583 return const_cast<mozilla::dom::LinkStyle*>(
584 static_cast<const nsINode*>(this)->AsLinkStyle());
585 }
586
587 /**
588 * Return this node as an Element. Should only be used for nodes
589 * for which IsElement() is true. This is defined inline in Element.h.
590 */
591 inline mozilla::dom::Element* AsElement();
592 inline const mozilla::dom::Element* AsElement() const;
593
594 /**
595 * Return whether the node is an nsStyledElement instance or not.
596 */
597 virtual bool IsStyledElement() const { return false; }
598
599 /**
600 * Return this node as nsIContent. Should only be used for nodes for which
601 * IsContent() is true.
602 *
603 * The assertion in nsIContent's constructor makes this safe.
604 */
605 nsIContent* AsContent() {
606 MOZ_ASSERT(IsContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsContent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsContent()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsContent()"
")"); do { *((volatile int*)__null) = 606; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
607 return reinterpret_cast<nsIContent*>(this);
608 }
609 const nsIContent* AsContent() const {
610 MOZ_ASSERT(IsContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsContent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsContent()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsContent()"
")"); do { *((volatile int*)__null) = 610; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
611 return reinterpret_cast<const nsIContent*>(this);
612 }
613
614 /*
615 * Return whether the node is a Text node (which might be an actual
616 * textnode, or might be a CDATA section).
617 */
618 bool IsText() const {
619 uint32_t nodeType = NodeType();
620 return nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE;
621 }
622
623 /**
624 * Return this node as Text if it is one, otherwise null. This is defined
625 * inline in Text.h.
626 */
627 inline mozilla::dom::Text* GetAsText();
628 inline const mozilla::dom::Text* GetAsText() const;
629
630 /**
631 * Return this node as Text. Asserts IsText(). This is defined inline in
632 * Text.h.
633 */
634 inline mozilla::dom::Text* AsText();
635 inline const mozilla::dom::Text* AsText() const;
636
637 /**
638 * Return this node if the instance type inherits nsIFormControl, or an
639 * nsIFormControl instance which ia associated with this node. Otherwise,
640 * returns nullptr.
641 */
642 [[nodiscard]] virtual nsIFormControl* GetAsFormControl() { return nullptr; }
643 [[nodiscard]] virtual const nsIFormControl* GetAsFormControl() const {
644 return nullptr;
645 }
646
647 /*
648 * Return whether the node is a ProcessingInstruction node.
649 */
650 bool IsProcessingInstruction() const {
651 return NodeType() == PROCESSING_INSTRUCTION_NODE;
652 }
653
654 /*
655 * Return whether the node is a CharacterData node (text, cdata,
656 * comment, processing instruction)
657 */
658 bool IsCharacterData() const {
659 uint32_t nodeType = NodeType();
660 return nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE ||
661 nodeType == PROCESSING_INSTRUCTION_NODE || nodeType == COMMENT_NODE;
662 }
663
664 /**
665 * Return whether the node is a Comment node.
666 */
667 bool IsComment() const { return NodeType() == COMMENT_NODE; }
668
669 /**
670 * Return whether the node is an Attr node.
671 */
672 bool IsAttr() const { return NodeType() == ATTRIBUTE_NODE; }
673
674 /**
675 * Return if this node has any children.
676 */
677 bool HasChildren() const { return !!mFirstChild; }
678
679 /**
680 * Get the number of children
681 * @return the number of children
682 */
683 uint32_t GetChildCount() const { return mChildCount; }
684
685 /**
686 * NOTE: this function is going to be removed soon (hopefully!) Don't use it
687 * in new code.
688 *
689 * Get a child by index
690 * @param aIndex the index of the child to get
691 * @return the child, or null if index out of bounds
692 */
693 nsIContent* GetChildAt_Deprecated(uint32_t aIndex) const;
694
695 /**
696 * Get the index of a child within this content.
697 *
698 * @param aPossibleChild the child to get the index of.
699 * @return the index of the child, or Nothing if not a child. Be aware that
700 * anonymous children (e.g. a <div> child of an <input> element) will
701 * result in Nothing.
702 *
703 * If the return value is Some, then calling GetChildAt_Deprecated() with
704 * that value will return aPossibleChild.
705 */
706 mozilla::Maybe<uint32_t> ComputeIndexOf(const nsINode* aPossibleChild) const;
707
708 /**
709 * Get the index of a child within this content's flat tree children.
710 *
711 * @param aPossibleChild the child to get the index of.
712 * @return the index of the child, or Nothing if not a child. Be aware that
713 * anonymous children (e.g. a <div> child of an <input> element) will
714 * result in Nothing.
715 */
716 mozilla::Maybe<uint32_t> ComputeFlatTreeIndexOf(
717 const nsINode* aPossibleChild) const;
718
719 /**
720 * Get the index of this within parent node (ComputeIndexInParentNode) or
721 * parent content (nsIContent) node (ComputeIndexInParentContent).
722 *
723 * @return the index of this node in the parent, or Nothing there is no
724 * parent (content) node or the parent does not have this node anymore
725 * (e.g., being removed from the parent). Be aware that anonymous
726 * children (e.g. a <div> child of an <input> element) will result in
727 * Nothing.
728 *
729 * If the return value is Some, then calling GetChildAt_Deprecated() with
730 * that value will return this.
731 */
732 mozilla::Maybe<uint32_t> ComputeIndexInParentNode() const;
733 mozilla::Maybe<uint32_t> ComputeIndexInParentContent() const;
734
735 /**
736 * Get the index of a child within this content.
737 *
738 * @param aPossibleChild the child to get the index of.
739 * @return the index of the child, or -1 if not a child. Be aware that
740 * anonymous children (e.g. a <div> child of an <input> element) will
741 * result in -1.
742 *
743 * If the return value is not -1, then calling GetChildAt_Deprecated() with
744 * that value will return aPossibleChild.
745 */
746 int32_t ComputeIndexOf_Deprecated(const nsINode* aPossibleChild) const;
747
748 /**
749 * Returns the "node document" of this node.
750 *
751 * https://dom.spec.whatwg.org/#concept-node-document
752 *
753 * Note that in the case that this node is a document node this method
754 * will return |this|. That is different to the Node.ownerDocument DOM
755 * attribute (implemented by nsINode::GetOwnerDocument) which is specified to
756 * be null in that case:
757 *
758 * https://dom.spec.whatwg.org/#dom-node-ownerdocument
759 *
760 * For all other cases OwnerDoc and GetOwnerDocument behave identically.
761 */
762 Document* OwnerDoc() const MOZ_NONNULL_RETURN__attribute__((returns_nonnull)) {
763 return mNodeInfo->GetDocument();
764 }
765
766 /**
767 * Return the "owner document" of this node as an nsINode*. Implemented
768 * in Document.h.
769 */
770 inline nsINode* OwnerDocAsNode() const MOZ_NONNULL_RETURN__attribute__((returns_nonnull));
771
772 /**
773 * Returns true if the content has an ancestor that is a document.
774 *
775 * @return whether this content is in a document tree
776 */
777 bool IsInUncomposedDoc() const { return GetBoolFlag(IsInDocument); }
778
779 /**
780 * Get the document that this content is currently in, if any. This will be
781 * null if the content has no ancestor that is a document.
782 *
783 * @return the current document
784 */
785
786 Document* GetUncomposedDoc() const {
787 return IsInUncomposedDoc() ? OwnerDoc() : nullptr;
788 }
789
790 /**
791 * Returns true if we're connected, and thus GetComposedDoc() would return a
792 * non-null value.
793 */
794 bool IsInComposedDoc() const { return GetBoolFlag(IsConnected); }
795
796 /**
797 * This method returns the owner document if the node is connected to it
798 * (as defined in the DOM spec), otherwise it returns null.
799 * In other words, returns non-null even in the case the node is in
800 * Shadow DOM, if there is a possibly shadow boundary crossing path from
801 * the node to its owner document.
802 */
803 Document* GetComposedDoc() const {
804 return IsInComposedDoc() ? OwnerDoc() : nullptr;
805 }
806
807 /**
808 * Returns OwnerDoc() if the node is in uncomposed document and ShadowRoot if
809 * the node is in Shadow DOM.
810 */
811 mozilla::dom::DocumentOrShadowRoot* GetContainingDocumentOrShadowRoot() const;
812
813 /**
814 * Returns OwnerDoc() if the node is in uncomposed document and ShadowRoot if
815 * the node is in Shadow DOM and is in composed document.
816 */
817 mozilla::dom::DocumentOrShadowRoot* GetUncomposedDocOrConnectedShadowRoot()
818 const;
819
820 /**
821 * To be called when reference count of the node drops to zero.
822 */
823 void LastRelease();
824
825 /**
826 * The values returned by this function are the ones defined for
827 * Node.nodeType
828 */
829 uint16_t NodeType() const { return mNodeInfo->NodeType(); }
830 const nsString& NodeName() const { return mNodeInfo->NodeName(); }
831 const nsString& LocalName() const { return mNodeInfo->LocalName(); }
832
833 /**
834 * Get the NodeInfo for this element
835 * @return the nodes node info
836 */
837 inline mozilla::dom::NodeInfo* NodeInfo() const { return mNodeInfo; }
838
839 /**
840 * Called when we have been adopted, and the information of the
841 * node has been changed.
842 *
843 * The new document can be reached via OwnerDoc().
844 *
845 * If you override this method,
846 * please call up to the parent NodeInfoChanged.
847 *
848 * If you change this, change also the similar method in Link.
849 */
850 virtual void NodeInfoChanged(Document* aOldDoc) {
851#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
852 AssertInvariantsOnNodeInfoChange();
853#endif
854 }
855
856 inline bool IsInNamespace(int32_t aNamespace) const {
857 return mNodeInfo->NamespaceID() == aNamespace;
858 }
859
860 /**
861 * Returns the DocGroup of the "node document" of this node.
862 */
863 DocGroup* GetDocGroup() const;
864
865 /**
866 * Print a debugger friendly descriptor of this element. This will describe
867 * the position of this element in the document.
868 */
869 friend std::ostream& operator<<(std::ostream& aStream, const nsINode& aNode);
870
871 protected:
872 // These 2 methods are useful for the recursive templates IsHTMLElement,
873 // IsSVGElement, etc.
874 inline bool IsNodeInternal() const { return false; }
875
876 template <typename First, typename... Args>
877 inline bool IsNodeInternal(First aFirst, Args... aArgs) const {
878 return mNodeInfo->Equals(aFirst) || IsNodeInternal(aArgs...);
879 }
880
881 public:
882 inline bool IsHTMLElement() const {
883 return IsElement() && IsInNamespace(kNameSpaceID_XHTML3);
884 }
885
886 inline bool IsHTMLElement(const nsAtom* aTag) const {
887 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_XHTML3);
888 }
889
890 template <typename First, typename... Args>
891 inline bool IsAnyOfHTMLElements(First aFirst, Args... aArgs) const {
892 return IsHTMLElement() && IsNodeInternal(aFirst, aArgs...);
893 }
894
895 inline bool IsSVGElement() const {
896 return IsElement() && IsInNamespace(kNameSpaceID_SVG9);
897 }
898
899 inline bool IsSVGElement(const nsAtom* aTag) const {
900 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_SVG9);
901 }
902
903 template <typename First, typename... Args>
904 inline bool IsAnyOfSVGElements(First aFirst, Args... aArgs) const {
905 return IsSVGElement() && IsNodeInternal(aFirst, aArgs...);
906 }
907
908 virtual bool IsSVGAnimationElement() const { return false; }
909 virtual bool IsSVGComponentTransferFunctionElement() const { return false; }
910 virtual bool IsSVGFilterPrimitiveElement() const { return false; }
911 virtual bool IsSVGFilterPrimitiveChildElement() const { return false; }
912 virtual bool IsSVGGeometryElement() const { return false; }
913 virtual bool IsSVGGraphicsElement() const { return false; }
914
915 inline bool IsXULElement() const {
916 return IsElement() && IsInNamespace(kNameSpaceID_XUL8);
917 }
918
919 inline bool IsXULElement(const nsAtom* aTag) const {
920 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_XUL8);
921 }
922
923 template <typename First, typename... Args>
924 inline bool IsAnyOfXULElements(First aFirst, Args... aArgs) const {
925 return IsXULElement() && IsNodeInternal(aFirst, aArgs...);
926 }
927
928 inline bool IsMathMLElement() const {
929 return IsElement() && IsInNamespace(kNameSpaceID_MathML6);
930 }
931
932 inline bool IsMathMLElement(const nsAtom* aTag) const {
933 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_MathML6);
934 }
935
936 template <typename First, typename... Args>
937 inline bool IsAnyOfMathMLElements(First aFirst, Args... aArgs) const {
938 return IsMathMLElement() && IsNodeInternal(aFirst, aArgs...);
939 }
940
941 bool IsShadowRoot() const {
942 const bool isShadowRoot = IsInShadowTree() && !GetParentNode();
943 MOZ_ASSERT_IF(isShadowRoot, IsDocumentFragment())do { if (isShadowRoot) { do { static_assert( mozilla::detail::
AssertionConditionType<decltype(IsDocumentFragment())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsDocumentFragment()))), 0))) { do { } while (false)
; MOZ_ReportAssertionFailure("IsDocumentFragment()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 943); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsDocumentFragment()"
")"); do { *((volatile int*)__null) = 943; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
944 return isShadowRoot;
945 }
946
947 bool IsHTMLHeadingElement() const {
948 return IsAnyOfHTMLElements(nsGkAtoms::h1, nsGkAtoms::h2, nsGkAtoms::h3,
949 nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6);
950 }
951
952 /**
953 * Check whether the conditional processing attributes other than
954 * systemLanguage "return true" if they apply to and are specified
955 * on the given SVG element. Returns true if this element should be
956 * rendered, false if it should not.
957 */
958 virtual bool PassesConditionalProcessingTests() const { return true; }
959
960 /**
961 * Insert a content node before another or at the end.
962 * This method handles calling BindToTree on the child appropriately.
963 *
964 * @param aKid the content to insert
965 * @param aBeforeThis an existing node. Use nullptr if you want to
966 * add aKid at the end.
967 * @param aNotify whether to notify the document (current document for
968 * nsIContent, and |this| for Document) that the insert has occurred
969 * @param aRv The error, if any.
970 * Throw NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have
971 * more than one element node as a child of a document. Doing this
972 * will also assert -- you shouldn't be doing it! Check with
973 * Document::GetRootElement() first if you're not sure. Apart from
974 * this one constraint, this doesn't do any checking on whether aKid is
975 * a valid child of |this|.
976 * Throw NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
977 */
978 virtual void InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
979 bool aNotify, mozilla::ErrorResult& aRv);
980
981 /**
982 * Append a content node to the end of the child list. This method handles
983 * calling BindToTree on the child appropriately.
984 *
985 * @param aKid the content to append
986 * @param aNotify whether to notify the document (current document for
987 * nsIContent, and |this| for Document) that the append has occurred
988 * @param aRv The error, if any.
989 * Throw NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have
990 * more than one element node as a child of a document. Doing this
991 * will also assert -- you shouldn't be doing it! Check with
992 * Document::GetRootElement() first if you're not sure. Apart from
993 * this one constraint, this doesn't do any checking on whether aKid is
994 * a valid child of |this|.
995 * Throw NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
996 */
997 void AppendChildTo(nsIContent* aKid, bool aNotify,
998 mozilla::ErrorResult& aRv) {
999 InsertChildBefore(aKid, nullptr, aNotify, aRv);
1000 }
1001
1002 template <BatchRemovalOrder aOrder = BatchRemovalOrder::FrontToBack>
1003 void RemoveAllChildren(bool aNotify) {
1004 if (!HasChildren()) {
1005 return;
1006 }
1007 BatchRemovalState state{};
1008 do {
1009 nsIContent* nodeToRemove = aOrder == BatchRemovalOrder::FrontToBack
1010 ? GetFirstChild()
1011 : GetLastChild();
1012 RemoveChildNode(nodeToRemove, aNotify, &state);
1013 state.mIsFirst = false;
1014 } while (HasChildren());
1015 }
1016
1017 /**
1018 * Remove a child from this node. This method handles calling UnbindFromTree
1019 * on the child appropriately.
1020 *
1021 * @param aKid the content to remove
1022 * @param aNotify whether to notify the document (current document for
1023 * nsIContent, and |this| for Document) that the remove has occurred
1024 * @param BatchRemovalState The current state of our batch removal.
1025 */
1026 virtual void RemoveChildNode(nsIContent* aKid, bool aNotify,
1027 const BatchRemovalState* = nullptr);
1028
1029 /**
1030 * Get a property associated with this node.
1031 *
1032 * @param aPropertyName name of property to get.
1033 * @param aStatus out parameter for storing resulting status.
1034 * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
1035 * is not set.
1036 * @return the property. Null if the property is not set
1037 * (though a null return value does not imply the
1038 * property was not set, i.e. it can be set to null).
1039 */
1040 void* GetProperty(const nsAtom* aPropertyName,
1041 nsresult* aStatus = nullptr) const;
1042
1043 /**
1044 * Set a property to be associated with this node. This will overwrite an
1045 * existing value if one exists. The existing value is destroyed using the
1046 * destructor function given when that value was set.
1047 *
1048 * @param aPropertyName name of property to set.
1049 * @param aValue new value of property.
1050 * @param aDtor destructor function to be used when this property
1051 * is destroyed.
1052 * @param aTransfer if true the property will not be deleted when the
1053 * ownerDocument of the node changes, if false it
1054 * will be deleted.
1055 *
1056 * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
1057 * was already set
1058 * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
1059 */
1060 nsresult SetProperty(nsAtom* aPropertyName, void* aValue,
1061 NSPropertyDtorFunc aDtor = nullptr,
1062 bool aTransfer = false);
1063
1064 /**
1065 * A generic destructor for property values allocated with new.
1066 */
1067 template <class T>
1068 static void DeleteProperty(void*, nsAtom*, void* aPropertyValue, void*) {
1069 delete static_cast<T*>(aPropertyValue);
1070 }
1071
1072 /**
1073 * Removes a property associated with this node. The value is destroyed using
1074 * the destruction function given when that value was set.
1075 *
1076 * @param aPropertyName name of property to destroy.
1077 */
1078 void RemoveProperty(const nsAtom* aPropertyName);
1079
1080 /**
1081 * Take a property associated with this node. The value will not be destroyed
1082 * but rather returned. It is the caller's responsibility to destroy the value
1083 * after that point.
1084 *
1085 * @param aPropertyName name of property to unset.
1086 * @param aStatus out parameter for storing resulting status.
1087 * Set to NS_PROPTABLE_PROP_NOT_THERE if the property
1088 * is not set.
1089 * @return the property. Null if the property is not set
1090 * (though a null return value does not imply the
1091 * property was not set, i.e. it can be set to null).
1092 */
1093 void* TakeProperty(const nsAtom* aPropertyName, nsresult* aStatus = nullptr);
1094
1095 bool HasProperties() const { return HasFlag(NODE_HAS_PROPERTIES); }
1096
1097 /**
1098 * Return the principal of this node. This is guaranteed to never be a null
1099 * pointer.
1100 */
1101 nsIPrincipal* NodePrincipal() const {
1102 return mNodeInfo->NodeInfoManager()->DocumentPrincipal();
1103 }
1104
1105 /**
1106 * Return the CSP of this node's document, if any.
1107 */
1108 nsIContentSecurityPolicy* GetCsp() const;
1109
1110 /**
1111 * Get the parent nsIContent for this node.
1112 * @return the parent, or null if no parent or the parent is not an nsIContent
1113 */
1114 nsIContent* GetParent() const {
1115 return MOZ_LIKELY(GetBoolFlag(ParentIsContent))(__builtin_expect(!!(GetBoolFlag(ParentIsContent)), 1)) ? mParent->AsContent()
1116 : nullptr;
1117 }
1118
1119 /**
1120 * Get the parent nsINode for this node. This can be either an nsIContent, a
1121 * Document or an Attr.
1122 * @return the parent node
1123 */
1124 nsINode* GetParentNode() const { return mParent; }
1125
1126 private:
1127 nsIContent* DoGetShadowHost() const;
1128
1129 public:
1130 nsINode* GetParentOrShadowHostNode() const {
1131 if (MOZ_LIKELY(mParent)(__builtin_expect(!!(mParent), 1))) {
1132 return mParent;
1133 }
1134 // We could put this in nsIContentInlines.h or such to avoid this
1135 // reinterpret_cast, but it doesn't seem worth it.
1136 return IsInShadowTree() ? reinterpret_cast<nsINode*>(DoGetShadowHost())
1137 : nullptr;
1138 }
1139
1140 enum FlattenedParentType { eNormal, eForStyle, eForSelection };
1141
1142 /**
1143 * Returns the node that is the parent of this node in the flattened
1144 * tree. This differs from the normal parent if the node is filtered
1145 * into an insertion point, or if the node is a direct child of a
1146 * shadow root.
1147 *
1148 * @return the flattened tree parent
1149 */
1150 inline nsINode* GetFlattenedTreeParentNode() const;
1151
1152 nsINode* GetFlattenedTreeParentNodeNonInline() const;
1153
1154 /**
1155 * Like GetFlattenedTreeParentNode, but returns the document for any native
1156 * anonymous content that was generated for ancestor frames of the document
1157 * element's primary frame, such as scrollbar elements created by the root
1158 * scroll frame.
1159 */
1160 inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
1161
1162 /**
1163 * Similar to GetFlattenedTreeParentNode, it does two things differently
1164 * 1. For contents that are not in the flattened tree, use its
1165 * parent rather than nullptr.
1166 * 2. For contents that are slotted into a UA shadow tree, use its
1167 * parent rather than the slot element.
1168 */
1169 inline nsIContent* GetFlattenedTreeParentNodeForSelection() const;
1170
1171 inline mozilla::dom::Element* GetFlattenedTreeParentElement() const;
1172 inline mozilla::dom::Element* GetFlattenedTreeParentElementForStyle() const;
1173
1174 /**
1175 * Get the parent nsINode for this node if it is an Element.
1176 *
1177 * Defined inline in Element.h
1178 *
1179 * @return the parent node
1180 */
1181 inline mozilla::dom::Element* GetParentElement() const;
1182
1183 /**
1184 * Get the parent Element of this node, traversing over a ShadowRoot
1185 * to its host if necessary.
1186 */
1187 mozilla::dom::Element* GetParentElementCrossingShadowRoot() const;
1188
1189 /**
1190 * Get closest element node for the node. Meaning that if the node is an
1191 * element node, returns itself. Otherwise, returns parent element or null.
1192 */
1193 inline mozilla::dom::Element* GetAsElementOrParentElement() const;
1194
1195 /**
1196 * Get inclusive ancestor element in the flattened tree.
1197 */
1198 inline mozilla::dom::Element* GetInclusiveFlattenedTreeAncestorElement()
1199 const;
1200
1201 /**
1202 * Get the root of the subtree this node belongs to. This never returns
1203 * null. It may return 'this' (e.g. for document nodes, and nodes that
1204 * are the roots of disconnected subtrees).
1205 */
1206 nsINode* SubtreeRoot() const;
1207
1208 /*
1209 * Get context object's shadow-including root if options's composed is true,
1210 * and context object's root otherwise.
1211 */
1212 nsINode* GetRootNode(const mozilla::dom::GetRootNodeOptions& aOptions);
1213
1214 virtual mozilla::EventListenerManager* GetExistingListenerManager()
1215 const override;
1216 virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
1217
1218 mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
1219 GetDebuggerNotificationType() const override;
1220
1221 bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
1222
1223 virtual bool IsApzAware() const override;
1224
1225 virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
1226 virtual nsIGlobalObject* GetOwnerGlobal() const override;
1227
1228 using mozilla::dom::EventTarget::DispatchEvent;
1229 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
1230 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool DispatchEvent(
1231 mozilla::dom::Event& aEvent, mozilla::dom::CallerType aCallerType,
1232 mozilla::ErrorResult& aRv) override;
1233
1234 MOZ_CAN_RUN_SCRIPT
1235 nsresult PostHandleEvent(mozilla::EventChainPostVisitor& aVisitor) override;
1236
1237 /**
1238 * Adds a mutation observer to be notified when this node, or any of its
1239 * descendants, are modified. The node will hold a weak reference to the
1240 * observer, which means that it is the responsibility of the observer to
1241 * remove itself in case it dies before the node. If an observer is added
1242 * while observers are being notified, it may also be notified. In general,
1243 * adding observers while inside a notification is not a good idea. An
1244 * observer that is already observing the node must not be added without
1245 * being removed first.
1246 *
1247 * For mutation observers that implement nsIAnimationObserver, use
1248 * AddAnimationObserver instead.
1249 */
1250 void AddMutationObserver(nsIMutationObserver* aMutationObserver) {
1251 nsSlots* s = Slots();
1252 if (aMutationObserver) {
1253 NS_ASSERTION(!s->mMutationObservers.contains(aMutationObserver),do { if (!(!s->mMutationObservers.contains(aMutationObserver
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Observer already in the list"
, "!s->mMutationObservers.contains(aMutationObserver)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1254); MOZ_PretendNoReturn(); } } while (0)
1254 "Observer already in the list")do { if (!(!s->mMutationObservers.contains(aMutationObserver
))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Observer already in the list"
, "!s->mMutationObservers.contains(aMutationObserver)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1254); MOZ_PretendNoReturn(); } } while (0)
;
1255
1256 s->mMutationObservers.pushBack(aMutationObserver);
1257 }
1258 }
1259
1260 void AddMutationObserver(nsMultiMutationObserver* aMultiMutationObserver);
1261
1262 /**
1263 * Same as above, but only adds the observer if its not observing
1264 * the node already.
1265 *
1266 * For mutation observers that implement nsIAnimationObserver, use
1267 * AddAnimationObserverUnlessExists instead.
1268 */
1269 void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver) {
1270 nsSlots* s = Slots();
1271 if (aMutationObserver &&
1272 !s->mMutationObservers.contains(aMutationObserver)) {
1273 s->mMutationObservers.pushBack(aMutationObserver);
1274 }
1275 }
1276
1277 void AddMutationObserverUnlessExists(
1278 nsMultiMutationObserver* aMultiMutationObserver);
1279 /**
1280 * Same as AddMutationObserver, but for nsIAnimationObservers. This
1281 * additionally records on the document that animation observers have
1282 * been registered, which is used to determine whether notifications
1283 * must be fired when animations are added, removed or changed.
1284 */
1285 void AddAnimationObserver(nsIAnimationObserver* aAnimationObserver);
1286
1287 /**
1288 * Same as above, but only adds the observer if its not observing
1289 * the node already.
1290 */
1291 void AddAnimationObserverUnlessExists(
1292 nsIAnimationObserver* aAnimationObserver);
1293
1294 /**
1295 * Removes a mutation observer.
1296 */
1297 void RemoveMutationObserver(nsIMutationObserver* aMutationObserver) {
1298 nsSlots* s = GetExistingSlots();
1299 if (s) {
1300 s->mMutationObservers.remove(aMutationObserver);
1301 }
1302 }
1303
1304 void RemoveMutationObserver(nsMultiMutationObserver* aMultiMutationObserver);
1305
1306 mozilla::SafeDoublyLinkedList<nsIMutationObserver>* GetMutationObservers();
1307
1308 /**
1309 * Helper methods to access ancestor node(s) of type T.
1310 * The implementations of the methods are in mozilla/dom/AncestorIterator.h.
1311 */
1312 template <typename T>
1313 inline mozilla::dom::AncestorsOfTypeIterator<T> AncestorsOfType() const;
1314
1315 template <typename T>
1316 inline mozilla::dom::InclusiveAncestorsOfTypeIterator<T>
1317 InclusiveAncestorsOfType() const;
1318
1319 template <typename T>
1320 inline mozilla::dom::FlatTreeAncestorsOfTypeIterator<T>
1321 FlatTreeAncestorsOfType() const;
1322
1323 template <typename T>
1324 inline mozilla::dom::InclusiveFlatTreeAncestorsOfTypeIterator<T>
1325 InclusiveFlatTreeAncestorsOfType() const;
1326
1327 template <typename T>
1328 T* FirstAncestorOfType() const;
1329
1330 private:
1331 /**
1332 * Walks aNode, its attributes and, if aDeep is true, its descendant nodes.
1333 * If aClone is true the nodes will be cloned. If aNewNodeInfoManager is
1334 * not null, it is used to create new nodeinfos for the nodes. Also reparents
1335 * the XPConnect wrappers for the nodes into aReparentScope if non-null.
1336 *
1337 * @param aNode Node to adopt/clone.
1338 * @param aClone If true the node will be cloned and the cloned node will
1339 * be returned.
1340 * @param aDeep If true the function will be called recursively on
1341 * descendants of the node
1342 * @param aNewNodeInfoManager The nodeinfo manager to use to create new
1343 * nodeinfos for aNode and its attributes and
1344 * descendants. May be null if the nodeinfos
1345 * shouldn't be changed.
1346 * @param aReparentScope Scope into which wrappers should be reparented, or
1347 * null if no reparenting should be done.
1348 * @param aParent If aClone is true the cloned node will be appended to
1349 * aParent's children. May be null. If not null then aNode
1350 * must be an nsIContent.
1351 * @param aError The error, if any.
1352 *
1353 * @return If aClone is true then the cloned node will be returned,
1354 * unless an error occurred. In error conditions, null
1355 * will be returned.
1356 */
1357 static already_AddRefed<nsINode> CloneAndAdopt(
1358 nsINode* aNode, bool aClone, bool aDeep,
1359 nsNodeInfoManager* aNewNodeInfoManager,
1360 JS::Handle<JSObject*> aReparentScope, nsINode* aParent,
1361 mozilla::ErrorResult& aError);
1362
1363 public:
1364 /**
1365 * Walks the node, its attributes and descendant nodes. If aNewNodeInfoManager
1366 * is not null, it is used to create new nodeinfos for the nodes. Also
1367 * reparents the XPConnect wrappers for the nodes into aReparentScope if
1368 * non-null.
1369 *
1370 * @param aNewNodeInfoManager The nodeinfo manager to use to create new
1371 * nodeinfos for the node and its attributes and
1372 * descendants. May be null if the nodeinfos
1373 * shouldn't be changed.
1374 * @param aReparentScope New scope for the wrappers, or null if no reparenting
1375 * should be done.
1376 * @param aError The error, if any.
1377 */
1378 void Adopt(nsNodeInfoManager* aNewNodeInfoManager,
1379 JS::Handle<JSObject*> aReparentScope,
1380 mozilla::ErrorResult& aError);
1381
1382 /**
1383 * Clones the node, its attributes and, if aDeep is true, its descendant nodes
1384 * If aNewNodeInfoManager is not null, it is used to create new nodeinfos for
1385 * the clones.
1386 *
1387 * @param aDeep If true the function will be called recursively on
1388 * descendants of the node
1389 * @param aNewNodeInfoManager The nodeinfo manager to use to create new
1390 * nodeinfos for the node and its attributes and
1391 * descendants. May be null if the nodeinfos
1392 * shouldn't be changed.
1393 * @param aError The error, if any.
1394 *
1395 * @return The newly created node. Null in error conditions.
1396 */
1397 already_AddRefed<nsINode> Clone(bool aDeep,
1398 nsNodeInfoManager* aNewNodeInfoManager,
1399 mozilla::ErrorResult& aError);
1400
1401 /**
1402 * Clones this node. This needs to be overriden by all node classes. aNodeInfo
1403 * should be identical to this node's nodeInfo, except for the document which
1404 * may be different. When cloning an element, all attributes of the element
1405 * will be cloned. The children of the node will not be cloned.
1406 *
1407 * @param aNodeInfo the nodeinfo to use for the clone
1408 * @param aResult the clone
1409 */
1410 virtual nsresult Clone(mozilla::dom::NodeInfo*, nsINode** aResult) const = 0;
1411
1412 // A callback that gets called when we are forcefully unbound from a node (due
1413 // to the node going away). You shouldn't take a strong ref to the node from
1414 // the callback.
1415 using UnbindCallback = void (*)(nsISupports*, nsINode*);
1416 // We should keep alive these objects.
1417 struct BoundObject {
1418 nsCOMPtr<nsISupports> mObject;
1419 UnbindCallback mDtor = nullptr;
1420
1421 BoundObject(nsISupports* aObject, UnbindCallback aDtor)
1422 : mObject(aObject), mDtor(aDtor) {}
1423
1424 bool operator==(nsISupports* aOther) const {
1425 return mObject.get() == aOther;
1426 }
1427 };
1428
1429 // This class can be extended by subclasses that wish to store more
1430 // information in the slots.
1431 class nsSlots {
1432 public:
1433 nsSlots();
1434
1435 // If needed we could remove the vtable pointer this dtor causes by
1436 // putting a DestroySlots function on nsINode
1437 virtual ~nsSlots();
1438
1439 virtual void Traverse(nsCycleCollectionTraversalCallback&);
1440 virtual void Unlink(nsINode&);
1441
1442 /**
1443 * A list of mutation observers
1444 */
1445 mozilla::SafeDoublyLinkedList<nsIMutationObserver> mMutationObservers;
1446
1447 /**
1448 * An object implementing NodeList for this content (childNodes)
1449 * @see NodeList
1450 * @see nsGenericHTMLElement::GetChildNodes
1451 */
1452 RefPtr<nsAttrChildContentList> mChildNodes;
1453
1454 /**
1455 * Weak reference to this node. This is cleared by the destructor of
1456 * nsNodeWeakReference.
1457 */
1458 nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference;
1459
1460 /** A list of objects that we should keep alive. See Bind/UnbindObject. */
1461 nsTArray<BoundObject> mBoundObjects;
1462
1463 /**
1464 * A set of ranges which are in the selection and which have this node as
1465 * their endpoints' closest common inclusive ancestor
1466 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor). This is
1467 * a UniquePtr instead of just a LinkedList, because that prevents us from
1468 * pushing DOMSlots up to the next allocation bucket size, at the cost of
1469 * some complexity.
1470 */
1471 mozilla::UniquePtr<mozilla::LinkedList<mozilla::dom::AbstractRange>>
1472 mClosestCommonInclusiveAncestorRanges;
1473 };
1474
1475 /**
1476 * Functions for managing flags and slots
1477 */
1478#ifdef DEBUG1
1479 nsSlots* DebugGetSlots() { return Slots(); }
1480#endif
1481
1482 void SetFlags(FlagsType aFlagsToSet) {
1483 NS_ASSERTION(do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1484 !(aFlagsToSet &do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1485 (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1486 NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME |do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1487 NODE_HAS_BEEN_IN_UA_WIDGET)) ||do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1488 IsContent(),do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
1489 "Flag only permitted on nsIContent nodes")do { if (!(!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT
| NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Flag only permitted on nsIContent nodes"
, "!(aFlagsToSet & (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | NODE_HAS_BEEN_IN_UA_WIDGET)) || IsContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1489); MOZ_PretendNoReturn(); } } while (0)
;
1490 nsWrapperCache::SetFlags(aFlagsToSet);
1491 }
1492
1493 void UnsetFlags(FlagsType aFlagsToUnset) {
1494 NS_ASSERTION(!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET |do { if (!(!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET |
NODE_IS_NATIVE_ANONYMOUS_ROOT)))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Trying to unset write-only flags", "!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET | NODE_IS_NATIVE_ANONYMOUS_ROOT))"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1496); MOZ_PretendNoReturn(); } } while (0)
1495 NODE_IS_NATIVE_ANONYMOUS_ROOT)),do { if (!(!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET |
NODE_IS_NATIVE_ANONYMOUS_ROOT)))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Trying to unset write-only flags", "!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET | NODE_IS_NATIVE_ANONYMOUS_ROOT))"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1496); MOZ_PretendNoReturn(); } } while (0)
1496 "Trying to unset write-only flags")do { if (!(!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET |
NODE_IS_NATIVE_ANONYMOUS_ROOT)))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Trying to unset write-only flags", "!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET | NODE_IS_NATIVE_ANONYMOUS_ROOT))"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1496); MOZ_PretendNoReturn(); } } while (0)
;
1497 nsWrapperCache::UnsetFlags(aFlagsToUnset);
1498 }
1499
1500 void SetEditableFlag(bool aEditable) {
1501 if (aEditable) {
1502 SetFlags(NODE_IS_EDITABLE);
1503 } else {
1504 UnsetFlags(NODE_IS_EDITABLE);
1505 }
1506 }
1507
1508 inline bool IsEditable() const;
1509
1510 /**
1511 * Check if this node is an editing host. For avoiding confusion, this always
1512 * returns false if the node is in the design mode document.
1513 */
1514 inline bool IsEditingHost() const;
1515
1516 /**
1517 * Check if this node is in design mode or not. When this returns true and:
1518 * - if this is a Document node, it's the design mode root.
1519 * - if this is a content node, it's connected, it's not in a shadow tree
1520 * (except shadow tree for UI widget and native anonymous subtree) and its
1521 * uncomposed document is in design mode.
1522 * Note that returning true does NOT mean the node or its children is
1523 * editable. E.g., when this node is in a shadow tree of a UA widget and its
1524 * host is in design mode.
1525 */
1526 inline bool IsInDesignMode() const;
1527
1528 /**
1529 * Returns true if |this| or any of its ancestors is native anonymous.
1530 */
1531 bool IsInNativeAnonymousSubtree() const {
1532 return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
1533 }
1534
1535 /**
1536 * If |this| or any ancestor is native anonymous, return the root of the
1537 * native anonymous subtree. Note that in case of nested native anonymous
1538 * content, this returns the innermost root, not the outermost.
1539 */
1540 nsIContent* GetClosestNativeAnonymousSubtreeRoot() const {
1541 if (!IsInNativeAnonymousSubtree()) {
1542 MOZ_ASSERT(!HasBeenInUAWidget(), "UA widget implies anonymous")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HasBeenInUAWidget())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!HasBeenInUAWidget()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!HasBeenInUAWidget()"
" (" "UA widget implies anonymous" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1542); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HasBeenInUAWidget()"
") (" "UA widget implies anonymous" ")"); do { *((volatile int
*)__null) = 1542; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1543 return nullptr;
1544 }
1545 MOZ_ASSERT(IsContent(), "How did non-content end up in NAC?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsContent()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsContent()" " ("
"How did non-content end up in NAC?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1545); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsContent()"
") (" "How did non-content end up in NAC?" ")"); do { *((volatile
int*)__null) = 1545; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1546 if (HasBeenInUAWidget()) {
1547 // reinterpret_cast because in this header we don't know ShadowRoot is an
1548 // nsIContent. ShadowRoot constructor asserts this is correct.
1549 return reinterpret_cast<nsIContent*>(GetContainingShadow());
1550 }
1551 for (const nsINode* node = this; node; node = node->GetParentNode()) {
1552 if (node->IsRootOfNativeAnonymousSubtree()) {
1553 return const_cast<nsINode*>(node)->AsContent();
1554 }
1555 }
1556 // FIXME(emilio): This should not happen, usually, but editor removes nodes
1557 // in native anonymous subtrees, and we don't clean nodes from the current
1558 // event content stack from ContentRemoved, so it can actually happen, see
1559 // bug 1510208.
1560 NS_WARNING("GetClosestNativeAnonymousSubtreeRoot on disconnected NAC!")NS_DebugBreak(NS_DEBUG_WARNING, "GetClosestNativeAnonymousSubtreeRoot on disconnected NAC!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1560)
;
1561 return nullptr;
1562 }
1563
1564 /**
1565 * If |this| or any ancestor is native anonymous, return the parent of the
1566 * native anonymous subtree. Note that in case of nested native anonymous
1567 * content, this returns the parent or host of the innermost root, not the
1568 * outermost.
1569 */
1570 nsIContent* GetClosestNativeAnonymousSubtreeRootParentOrHost() const {
1571 // We could put this in nsIContentInlines.h or such to avoid this
1572 // reinterpret_cast, but it doesn't seem worth it.
1573 const auto* root = reinterpret_cast<const nsINode*>(
1574 GetClosestNativeAnonymousSubtreeRoot());
1575 if (!root) {
1576 return nullptr;
1577 }
1578 if (nsIContent* parent = root->GetParent()) {
1579 return parent;
1580 }
1581 if (MOZ_UNLIKELY(root->IsInShadowTree())(__builtin_expect(!!(root->IsInShadowTree()), 0))) {
1582 return root->DoGetShadowHost();
1583 }
1584 return nullptr;
1585 }
1586
1587 /**
1588 * Gets the root of the node tree for this content if it is in a shadow tree.
1589 */
1590 mozilla::dom::ShadowRoot* GetContainingShadow() const;
1591 /**
1592 * Gets the shadow host if this content is in a shadow tree. That is, the host
1593 * of |GetContainingShadow|, if its not null.
1594 *
1595 * @return The shadow host, if this is in shadow tree, or null.
1596 */
1597 mozilla::dom::Element* GetContainingShadowHost() const;
1598
1599 bool IsInSVGUseShadowTree() const {
1600 return !!GetContainingSVGUseShadowHost();
1601 }
1602
1603 mozilla::dom::SVGUseElement* GetContainingSVGUseShadowHost() const {
1604 if (!IsInShadowTree()) {
1605 return nullptr;
1606 }
1607 return DoGetContainingSVGUseShadowHost();
1608 }
1609
1610 // Whether this node has ever been part of a UA widget shadow tree.
1611 bool HasBeenInUAWidget() const { return HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET); }
1612
1613 // True for native anonymous content and for content in UA widgets.
1614 // Only nsIContent can fulfill this condition.
1615 bool ChromeOnlyAccess() const { return IsInNativeAnonymousSubtree(); }
1616
1617 // Whether we're chrome-only for event targeting. UA widgets can use regular
1618 // shadow DOM retargeting for these.
1619 bool ChromeOnlyAccessForEvents() const {
1620 return ChromeOnlyAccess() && !HasBeenInUAWidget();
1621 }
1622
1623 const nsIContent* GetChromeOnlyAccessSubtreeRootParent() const {
1624 return GetClosestNativeAnonymousSubtreeRootParentOrHost();
1625 }
1626
1627 bool IsInShadowTree() const { return HasFlag(NODE_IS_IN_SHADOW_TREE); }
1628
1629 /**
1630 * Get whether this node is C++-generated anonymous content
1631 * @see nsIAnonymousContentCreator
1632 * @return whether this content is anonymous
1633 */
1634 bool IsRootOfNativeAnonymousSubtree() const {
1635 NS_ASSERTION(do { if (!(!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Some flags seem to be missing!"
, "!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1637); MOZ_PretendNoReturn(); } } while (0)
1636 !HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree(),do { if (!(!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Some flags seem to be missing!"
, "!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1637); MOZ_PretendNoReturn(); } } while (0)
1637 "Some flags seem to be missing!")do { if (!(!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Some flags seem to be missing!"
, "!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1637); MOZ_PretendNoReturn(); } } while (0)
;
1638 return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT);
1639 }
1640
1641 // Whether this node is the root of a ChromeOnlyAccess DOM subtree.
1642 bool IsRootOfChromeAccessOnlySubtree() const {
1643 return IsRootOfNativeAnonymousSubtree();
1644 }
1645
1646 /** Whether this is the container of a ::before pseudo-element. */
1647 bool IsGeneratedContentContainerForBefore() const {
1648 return IsRootOfNativeAnonymousSubtree() &&
1649 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore;
1650 }
1651
1652 /** Whether this is the container of an ::after pseudo-element. */
1653 bool IsGeneratedContentContainerForAfter() const {
1654 return IsRootOfNativeAnonymousSubtree() &&
1655 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter;
1656 }
1657
1658 /** Whether this is the container of a ::marker pseudo-element. */
1659 bool IsGeneratedContentContainerForMarker() const {
1660 return IsRootOfNativeAnonymousSubtree() &&
1661 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker;
1662 }
1663
1664 /**
1665 * Returns true if |this| node is the closest common inclusive ancestor
1666 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the
1667 * start/end nodes of a Range in a Selection or a descendant of such a common
1668 * ancestor. This node is definitely not selected when |false| is returned,
1669 * but it may or may not be selected when |true| is returned.
1670 */
1671 bool IsMaybeSelected() const {
1672 return IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() ||
1673 IsClosestCommonInclusiveAncestorForRangeInSelection();
1674 }
1675
1676 /**
1677 * Return true if any part of (this, aStartOffset) .. (this, aEndOffset)
1678 * overlaps any nsRange in
1679 * GetClosestCommonInclusiveAncestorForRangeInSelection ranges (i.e.
1680 * where this is a descendant of a range's common inclusive ancestor node).
1681 * If a nsRange starts in (this, aEndOffset) or if it ends in
1682 * (this, aStartOffset) then it is non-overlapping and the result is false
1683 * for that nsRange. Collapsed ranges always counts as non-overlapping.
1684 *
1685 * @param aStartOffset has to be less or equal to aEndOffset.
1686 * @param aCache A cache which contains all fully selected nodes for each
1687 * selection. If present, this provides a fast path to check if
1688 * a node is fully selected.
1689 */
1690 bool IsSelected(uint32_t aStartOffset, uint32_t aEndOffset,
1691 mozilla::dom::SelectionNodeCache* aCache = nullptr) const;
1692
1693#ifdef DEBUG1
1694 void AssertIsRootElementSlow(bool) const;
1695#endif
1696
1697 /** Returns whether we're the root element of our document. */
1698 bool IsRootElement() const {
1699 // This should be faster than pointer-chasing in the common cases.
1700 const bool isRoot = !GetParent() && IsInUncomposedDoc() && IsElement();
1701#ifdef DEBUG1
1702 AssertIsRootElementSlow(isRoot);
1703#endif
1704 return isRoot;
1705 }
1706
1707 /**
1708 * Get the root element of the text editor associated with this node or the
1709 * root element of the text editor of the ancestor 'TextControlElement' if
1710 * this is in its native anonymous subtree. I.e., this returns anonymous
1711 * `<div>` element of a `TextEditor`. Note that this can be used only for
1712 * getting root content of `<input>` or `<textarea>`. I.e., this method
1713 * doesn't support HTML editors. Note that this may create a `TextEditor`
1714 * instance, and it means that the `TextEditor` may modify its native
1715 * anonymous subtree and may run selection listeners.
1716 */
1717 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetAnonymousRootElementOfTextEditor(
1718 mozilla::TextEditor** aTextEditor = nullptr);
1719
1720 /**
1721 * Get the nearest selection root, ie. the node that will be selected if the
1722 * user does "Select All" while the focus is in this node. Note that if this
1723 * node is not in an editor, the result comes from the nsFrameSelection that
1724 * is related to aPresShell, so the result might not be the ancestor of this
1725 * node. Be aware that if this node and the computed selection limiter are
1726 * not in same subtree, this returns the root content of the closeset subtree.
1727 */
1728 MOZ_CAN_RUN_SCRIPT nsIContent* GetSelectionRootContent(
1729 mozilla::PresShell* aPresShell, bool aAllowCrossShadowBoundary = false);
1730
1731 bool HasScheduledSelectionChangeEvent() {
1732 return HasFlag(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
1733 }
1734
1735 void SetHasScheduledSelectionChangeEvent() {
1736 SetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
1737 }
1738
1739 void ClearHasScheduledSelectionChangeEvent() {
1740 UnsetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
1741 }
1742
1743 nsINodeList* ChildNodes();
1744
1745 nsIContent* GetFirstChild() const { return mFirstChild; }
1746
1747 nsIContent* GetLastChild() const;
1748
1749 /**
1750 * Implementation is in Document.h, because it needs to cast from
1751 * Document* to nsINode*.
1752 */
1753 Document* GetOwnerDocument() const;
1754
1755 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
1756 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Normalize();
1757
1758 /**
1759 * Get the base URI for any relative URIs within this piece of
1760 * content. Generally, this is the document's base URI, but certain
1761 * content carries a local base for backward compatibility.
1762 *
1763 * @return the base URI. May return null.
1764 */
1765 virtual nsIURI* GetBaseURI(bool aTryUseXHRDocBaseURI = false) const = 0;
1766 nsIURI* GetBaseURIObject() const;
1767
1768 /**
1769 * Return true if the node may be apz aware. There are two cases. One is that
1770 * the node is apz aware (such as HTMLInputElement with number type). The
1771 * other is that the node has apz aware listeners. This is a non-virtual
1772 * function which calls IsNodeApzAwareInternal only when the MayBeApzAware is
1773 * set. We check the details in IsNodeApzAwareInternal which may be overriden
1774 * by child classes
1775 */
1776 bool IsNodeApzAware() const {
1777 return NodeMayBeApzAware() ? IsNodeApzAwareInternal() : false;
1778 }
1779
1780 /**
1781 * Override this function and set the flag MayBeApzAware in case the node has
1782 * to let APZC be aware of it. It's used when the node may handle the apz
1783 * aware events and may do preventDefault to stop APZC to do default actions.
1784 *
1785 * For example, instead of scrolling page by APZ, we handle mouse wheel event
1786 * in HTMLInputElement with number type as increasing / decreasing its value.
1787 */
1788 virtual bool IsNodeApzAwareInternal() const;
1789
1790 void GetTextContent(nsAString& aTextContent, mozilla::OOMReporter& aError) {
1791 GetTextContentInternal(aTextContent, aError);
1792 }
1793 void SetTextContent(const nsAString& aTextContent,
1794 nsIPrincipal* aSubjectPrincipal,
1795 mozilla::ErrorResult& aError) {
1796 SetTextContentInternal(aTextContent, aSubjectPrincipal, aError);
1797 }
1798 void SetTextContent(const nsAString& aTextContent,
1799 mozilla::ErrorResult& aError) {
1800 SetTextContentInternal(aTextContent, nullptr, aError);
1801 }
1802
1803 mozilla::dom::Element* QuerySelector(const nsACString& aSelector,
1804 mozilla::ErrorResult& aResult);
1805 already_AddRefed<nsINodeList> QuerySelectorAll(const nsACString& aSelector,
1806 mozilla::ErrorResult& aResult);
1807
1808 protected:
1809 // Document and ShadowRoot override this with its own (faster) version.
1810 // This should really only be called for elements and document fragments.
1811 mozilla::dom::Element* GetElementById(const nsAString& aId);
1812
1813 void AppendChildToChildList(nsIContent* aKid);
1814 void InsertChildToChildList(nsIContent* aKid, nsIContent* aNextSibling);
1815 void DisconnectChild(nsIContent* aKid);
1816
1817 public:
1818 void LookupPrefix(const nsAString& aNamespace, nsAString& aResult);
1819 bool IsDefaultNamespace(const nsAString& aNamespaceURI) {
1820 nsAutoString defaultNamespace;
1821 LookupNamespaceURI(u""_ns, defaultNamespace);
1822 return aNamespaceURI.Equals(defaultNamespace);
1823 }
1824 void LookupNamespaceURI(const nsAString& aNamespacePrefix,
1825 nsAString& aNamespaceURI);
1826
1827 nsIContent* GetNextSibling() const { return mNextSibling; }
1828 nsIContent* GetPreviousSibling() const;
1829
1830 /**
1831 * Return true if the node is being removed from the parent, it means that
1832 * the node still knows the container which it's disconnected from, but the
1833 * node has already been removed from the child node chain of the container.
1834 * I.e., Return true between a call of DisconnectChild of the parent and
1835 * a call of UnbindFromTree of the node.
1836 */
1837 bool IsBeingRemoved() const {
1838 return mParent && !mNextSibling && !mPreviousOrLastSibling;
1839 }
1840
1841 /**
1842 * Get the next node in the pre-order tree traversal of the DOM. If
1843 * aRoot is non-null, then it must be an ancestor of |this|
1844 * (possibly equal to |this|) and only nodes that are descendants of
1845 * aRoot, not including aRoot itself, will be returned. Returns
1846 * null if there are no more nodes to traverse.
1847 */
1848 nsIContent* GetNextNode(const nsINode* aRoot = nullptr) const {
1849 return GetNextNodeImpl(aRoot, false);
1850 }
1851
1852 /**
1853 * Get the next node in the pre-order tree traversal of the DOM but ignoring
1854 * the children of this node. If aRoot is non-null, then it must be an
1855 * ancestor of |this| (possibly equal to |this|) and only nodes that are
1856 * descendants of aRoot, not including aRoot itself, will be returned.
1857 * Returns null if there are no more nodes to traverse.
1858 */
1859 nsIContent* GetNextNonChildNode(const nsINode* aRoot = nullptr) const {
1860 return GetNextNodeImpl(aRoot, true);
1861 }
1862
1863 /**
1864 * Returns true if 'this' is either document or element or
1865 * document fragment and aOther is a descendant in the same
1866 * anonymous tree.
1867 */
1868 bool Contains(const nsINode* aOther) const;
1869
1870 bool UnoptimizableCCNode() const;
1871
1872 /**
1873 * Fire a DOMNodeRemoved mutation event for all children of this node
1874 * TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
1875 */
1876 MOZ_CAN_RUN_SCRIPT_BOUNDARY void FireNodeRemovedForChildren();
1877
1878 void QueueDevtoolsAnonymousEvent(bool aIsRemove);
1879
1880 private:
1881 mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const;
1882
1883 nsIContent* GetNextNodeImpl(const nsINode* aRoot,
1884 const bool aSkipChildren) const {
1885#ifdef DEBUG1
1886 if (aRoot) {
1887 // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead.
1888 const nsINode* cur = this;
1889 for (; cur; cur = cur->GetParentNode())
1890 if (cur == aRoot) break;
1891 NS_ASSERTION(cur, "aRoot not an ancestor of |this|?")do { if (!(cur)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "aRoot not an ancestor of |this|?"
, "cur", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1891); MOZ_PretendNoReturn(); } } while (0)
;
1892 }
1893#endif
1894 if (!aSkipChildren) {
1895 nsIContent* kid = GetFirstChild();
1896 if (kid) {
1897 return kid;
1898 }
1899 }
1900 if (this == aRoot) {
1901 return nullptr;
1902 }
1903 const nsINode* cur = this;
1904 while (1) {
1905 nsIContent* next = cur->GetNextSibling();
1906 if (next) {
1907 return next;
1908 }
1909 nsINode* parent = cur->GetParentNode();
1910 if (parent == aRoot) {
1911 return nullptr;
1912 }
1913 cur = parent;
1914 }
1915 MOZ_ASSERT_UNREACHABLE("How did we get here?")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: "
"How did we get here?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "How did we get here?" ")"); do {
*((volatile int*)__null) = 1915; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1916 }
1917
1918 public:
1919 /**
1920 * Get the previous nsIContent in the pre-order tree traversal of the DOM. If
1921 * aRoot is non-null, then it must be an ancestor of |this|
1922 * (possibly equal to |this|) and only nsIContents that are descendants of
1923 * aRoot, including aRoot itself, will be returned. Returns
1924 * null if there are no more nsIContents to traverse.
1925 */
1926 nsIContent* GetPrevNode(const nsINode* aRoot = nullptr) const {
1927#ifdef DEBUG1
1928 if (aRoot) {
1929 // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead.
1930 const nsINode* cur = this;
1931 for (; cur; cur = cur->GetParentNode())
1932 if (cur == aRoot) break;
1933 NS_ASSERTION(cur, "aRoot not an ancestor of |this|?")do { if (!(cur)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "aRoot not an ancestor of |this|?"
, "cur", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 1933); MOZ_PretendNoReturn(); } } while (0)
;
1934 }
1935#endif
1936
1937 if (this == aRoot) {
1938 return nullptr;
1939 }
1940 nsIContent* cur = this->GetParent();
1941 nsIContent* iter = this->GetPreviousSibling();
1942 while (iter) {
1943 cur = iter;
1944 iter = reinterpret_cast<nsINode*>(iter)->GetLastChild();
1945 }
1946 return cur;
1947 }
1948
1949 /**
1950 * Boolean flags
1951 */
1952 private:
1953 enum BooleanFlag {
1954 // Set if we're being used from -moz-element or observed via a mask,
1955 // clipPath, filter or use element.
1956 NodeHasDirectRenderingObservers,
1957 // Set if our parent chain (including this node itself) terminates
1958 // in a document
1959 IsInDocument,
1960 // Set if we're part of the composed doc.
1961 // https://dom.spec.whatwg.org/#connected
1962 IsConnected,
1963 // Set if mParent is an nsIContent
1964 ParentIsContent,
1965 // Set if this node is an Element
1966 NodeIsElement,
1967 // Set if the element has a non-empty id attribute. This can in rare
1968 // cases lie for nsXMLElement, such as when the node has been moved between
1969 // documents with different id mappings.
1970 ElementHasID,
1971 // Set if the element might have a class.
1972 ElementMayHaveClass,
1973 // Set if the element might have inline style.
1974 ElementMayHaveStyle,
1975 // Set if the element has a name attribute set.
1976 ElementHasName,
1977 // Set if the element has a part attribute set.
1978 ElementHasPart,
1979 // Set if the element might have a contenteditable attribute set.
1980 ElementMayHaveContentEditableAttr,
1981 // Set if the element has a contenteditable attribute whose value makes the
1982 // element editable.
1983 ElementHasContentEditableAttrTrueOrPlainTextOnly,
1984 // Set if the node is the closest common inclusive ancestor of the start/end
1985 // nodes of a Range that is in a Selection.
1986 NodeIsClosestCommonInclusiveAncestorForRangeInSelection,
1987 // Set if the node is a descendant of a node with the above bit set.
1988 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection,
1989 // Set if CanSkipInCC check has been done for this subtree root.
1990 NodeIsCCMarkedRoot,
1991 // Maybe set if this node is in black subtree.
1992 NodeIsCCBlackTree,
1993 // Maybe set if the node is a root of a subtree
1994 // which needs to be kept in the purple buffer.
1995 NodeIsPurpleRoot,
1996 // Set if the element has some style states locked
1997 ElementHasLockedStyleStates,
1998 // Set if element has pointer locked
1999 ElementHasPointerLock,
2000 // Set if the node may have DOMMutationObserver attached to it.
2001 NodeMayHaveDOMMutationObserver,
2002 // Set if node is Content
2003 NodeIsContent,
2004 // Set if the node has animations or transitions
2005 ElementHasAnimations,
2006 // Set if node has a dir attribute with a valid value (ltr, rtl, or auto).
2007 // Note that we cannot compute this from the dir attribute event state
2008 // flags, because we can't use those to distinguish
2009 // <bdi dir="some-invalid-value"> and <bdi dir="auto">.
2010 NodeHasValidDirAttribute,
2011 // Set if a node in the node's parent chain has dir=auto and nothing
2012 // inbetween nor the node itself establishes its own direction.
2013 NodeAncestorHasDirAuto,
2014 // Set if the node or an ancestor is assigned to a dir=auto slot and
2015 // nothing between nor the node itself establishes its own direction.
2016 // Except for when the node assigned to the dir=auto slot establishes
2017 // its own direction, then the flag is still set.
2018 NodeAffectsDirAutoSlot,
2019 // Set if the node is handling a click.
2020 NodeHandlingClick,
2021 // Set if the element has a parser insertion mode other than "in body",
2022 // per the HTML5 "Parse state" section.
2023 ElementHasWeirdParserInsertionMode,
2024 // Parser sets this flag if it has notified about the node.
2025 ParserHasNotified,
2026 // Sets if the node is apz aware or we have apz aware listeners.
2027 MayBeApzAware,
2028 // Set if the element might have any kind of anonymous content children,
2029 // which would not be found through the element's children list.
2030 ElementMayHaveAnonymousChildren,
2031 // Set if element has CustomElementData.
2032 ElementHasCustomElementData,
2033 // Set if the element was created from prototype cache and
2034 // its l10n attributes haven't been changed.
2035 ElementCreatedFromPrototypeAndHasUnmodifiedL10n,
2036 // Guard value
2037 BooleanFlagCount
2038 };
2039
2040 void SetBoolFlag(BooleanFlag name, bool value) {
2041 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags),
2042 "Too many boolean flags");
2043 mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
2044 }
2045
2046 void SetBoolFlag(BooleanFlag name) {
2047 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags),
2048 "Too many boolean flags");
2049 mBoolFlags |= (1 << name);
2050 }
2051
2052 void ClearBoolFlag(BooleanFlag name) {
2053 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags),
2054 "Too many boolean flags");
2055 mBoolFlags &= ~(1 << name);
2056 }
2057
2058 bool GetBoolFlag(BooleanFlag name) const {
2059 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags),
2060 "Too many boolean flags");
2061 return mBoolFlags & (1 << name);
2062 }
2063
2064 public:
2065 bool HasDirectRenderingObservers() const {
2066 return GetBoolFlag(NodeHasDirectRenderingObservers);
2067 }
2068 void SetHasDirectRenderingObservers(bool aValue) {
2069 SetBoolFlag(NodeHasDirectRenderingObservers, aValue);
2070 }
2071 bool IsContent() const { return GetBoolFlag(NodeIsContent); }
2072 bool HasID() const { return GetBoolFlag(ElementHasID); }
2073 bool MayHaveClass() const { return GetBoolFlag(ElementMayHaveClass); }
2074 void SetMayHaveClass() { SetBoolFlag(ElementMayHaveClass); }
2075 bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
2076 bool HasName() const { return GetBoolFlag(ElementHasName); }
2077 bool HasPartAttribute() const { return GetBoolFlag(ElementHasPart); }
2078 bool MayHaveContentEditableAttr() const {
2079 return GetBoolFlag(ElementMayHaveContentEditableAttr);
2080 }
2081 /**
2082 * HasContentEditableAttrTrueOrPlainTextOnly() should not be called between
2083 * nsGenericHTMLElement::BeforeSetAttr and nsGenericHTMLElement::AfterSetAttr
2084 * because this is set and cleared by nsGenericHTMLElement::AfterSetAttr.
2085 */
2086 bool HasContentEditableAttrTrueOrPlainTextOnly() const {
2087 return GetBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly);
2088 }
2089 /**
2090 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2091 */
2092 bool IsClosestCommonInclusiveAncestorForRangeInSelection() const {
2093 return GetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
2094 }
2095 /**
2096 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2097 */
2098 void SetClosestCommonInclusiveAncestorForRangeInSelection() {
2099 SetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
2100 }
2101 /**
2102 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2103 */
2104 void ClearClosestCommonInclusiveAncestorForRangeInSelection() {
2105 ClearBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
2106 }
2107 /**
2108 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2109 */
2110 bool IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() const {
2111 return GetBoolFlag(
2112 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
2113 }
2114 /**
2115 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2116 */
2117 void SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
2118 SetBoolFlag(
2119 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
2120 }
2121 /**
2122 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
2123 */
2124 void ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
2125 ClearBoolFlag(
2126 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
2127 }
2128
2129 void SetCCMarkedRoot(bool aValue) { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
2130 bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); }
2131 void SetInCCBlackTree(bool aValue) { SetBoolFlag(NodeIsCCBlackTree, aValue); }
2132 bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); }
2133 void SetIsPurpleRoot(bool aValue) { SetBoolFlag(NodeIsPurpleRoot, aValue); }
2134 bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
2135 bool MayHaveDOMMutationObserver() {
2136 return GetBoolFlag(NodeMayHaveDOMMutationObserver);
2137 }
2138 void SetMayHaveDOMMutationObserver() {
2139 SetBoolFlag(NodeMayHaveDOMMutationObserver, true);
2140 }
2141 bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
2142 bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
2143 void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
2144 void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
2145 bool MayHaveAnimations() const { return GetBoolFlag(ElementHasAnimations); }
2146 void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
2147 void ClearMayHaveAnimations() { ClearBoolFlag(ElementHasAnimations); }
2148 void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
2149 void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
2150 bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
2151 void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
2152 void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
2153 bool AncestorHasDirAuto() const {
2154 return GetBoolFlag(NodeAncestorHasDirAuto);
2155 }
2156 void SetAffectsDirAutoSlot() { SetBoolFlag(NodeAffectsDirAutoSlot); }
2157 void ClearAffectsDirAutoSlot() { ClearBoolFlag(NodeAffectsDirAutoSlot); }
2158
2159 // Set if the node or an ancestor is assigned to a dir=auto slot.
2160 bool AffectsDirAutoSlot() const {
2161 return GetBoolFlag(NodeAffectsDirAutoSlot);
2162 }
2163
2164 // Implemented in nsIContentInlines.h.
2165 inline bool NodeOrAncestorHasDirAuto() const;
2166
2167 void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };
2168 bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); }
2169
2170 void SetMayBeApzAware() { SetBoolFlag(MayBeApzAware); }
2171 bool NodeMayBeApzAware() const { return GetBoolFlag(MayBeApzAware); }
2172
2173 void SetMayHaveAnonymousChildren() {
2174 SetBoolFlag(ElementMayHaveAnonymousChildren);
2175 }
2176 bool MayHaveAnonymousChildren() const {
2177 return GetBoolFlag(ElementMayHaveAnonymousChildren);
2178 }
2179
2180 void SetHasCustomElementData() { SetBoolFlag(ElementHasCustomElementData); }
2181 bool HasCustomElementData() const {
2182 return GetBoolFlag(ElementHasCustomElementData);
2183 }
2184
2185 void SetElementCreatedFromPrototypeAndHasUnmodifiedL10n() {
2186 SetBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n);
2187 }
2188 bool HasElementCreatedFromPrototypeAndHasUnmodifiedL10n() {
2189 return GetBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n);
2190 }
2191 void ClearElementCreatedFromPrototypeAndHasUnmodifiedL10n() {
2192 ClearBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n);
2193 }
2194
2195 mozilla::dom::ShadowRoot* GetShadowRoot() const;
2196
2197 // Return the shadow root of the node if it is a shadow host and
2198 // it meets the requirements for being a shadow host of a selection.
2199 // For example, <details>, <video> and <use> elements are not valid
2200 // shadow host for selection.
2201 mozilla::dom::ShadowRoot* GetShadowRootForSelection() const;
2202
2203 protected:
2204 void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
2205 void SetIsInDocument() { SetBoolFlag(IsInDocument); }
2206 void ClearInDocument() { ClearBoolFlag(IsInDocument); }
2207 void SetIsConnected(bool aConnected) { SetBoolFlag(IsConnected, aConnected); }
2208 void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
2209 void SetIsElement() { SetBoolFlag(NodeIsElement); }
2210 void SetHasID() { SetBoolFlag(ElementHasID); }
2211 void ClearHasID() { ClearBoolFlag(ElementHasID); }
2212 void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); }
2213 void SetHasName() { SetBoolFlag(ElementHasName); }
2214 void ClearHasName() { ClearBoolFlag(ElementHasName); }
2215 void SetHasPartAttribute(bool aPart) { SetBoolFlag(ElementHasPart, aPart); }
2216 void SetMayHaveContentEditableAttr() {
2217 SetBoolFlag(ElementMayHaveContentEditableAttr);
2218 }
2219 void ClearMayHaveContentEditableAttr() {
2220 ClearBoolFlag(ElementMayHaveContentEditableAttr);
2221 }
2222 void SetHasContentEditableAttrTrueOrPlainTextOnly() {
2223 SetBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly);
2224 }
2225 void ClearHasContentEditableAttrTrueOrPlainTextOnly() {
2226 ClearBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly);
2227 }
2228 void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
2229 void ClearHasLockedStyleStates() {
2230 ClearBoolFlag(ElementHasLockedStyleStates);
2231 }
2232 bool HasLockedStyleStates() const {
2233 return GetBoolFlag(ElementHasLockedStyleStates);
2234 }
2235 void SetHasWeirdParserInsertionMode() {
2236 SetBoolFlag(ElementHasWeirdParserInsertionMode);
2237 }
2238 bool HasWeirdParserInsertionMode() const {
2239 return GetBoolFlag(ElementHasWeirdParserInsertionMode);
2240 }
2241 bool HandlingClick() const { return GetBoolFlag(NodeHandlingClick); }
2242 void SetHandlingClick() { SetBoolFlag(NodeHandlingClick); }
2243 void ClearHandlingClick() { ClearBoolFlag(NodeHandlingClick); }
2244
2245 void SetSubtreeRootPointer(nsINode* aSubtreeRoot) {
2246 NS_ASSERTION(aSubtreeRoot, "aSubtreeRoot can never be null!")do { if (!(aSubtreeRoot)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"aSubtreeRoot can never be null!", "aSubtreeRoot", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2246); MOZ_PretendNoReturn(); } } while (0)
;
2247 NS_ASSERTION(!(IsContent() && IsInUncomposedDoc()) && !IsInShadowTree(),do { if (!(!(IsContent() && IsInUncomposedDoc()) &&
!IsInShadowTree())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't be here!"
, "!(IsContent() && IsInUncomposedDoc()) && !IsInShadowTree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2248); MOZ_PretendNoReturn(); } } while (0)
2248 "Shouldn't be here!")do { if (!(!(IsContent() && IsInUncomposedDoc()) &&
!IsInShadowTree())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't be here!"
, "!(IsContent() && IsInUncomposedDoc()) && !IsInShadowTree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2248); MOZ_PretendNoReturn(); } } while (0)
;
2249 mSubtreeRoot = aSubtreeRoot;
2250 }
2251
2252 void ClearSubtreeRootPointer() { mSubtreeRoot = nullptr; }
2253
2254 public:
2255 // Makes nsINode object keep aObject alive. If a callback is provided, it's
2256 // called before deleting the node.
2257 void BindObject(nsISupports* aObject, UnbindCallback = nullptr);
2258 // After calling UnbindObject nsINode, object doesn't keep aObject alive
2259 // anymore.
2260 void UnbindObject(nsISupports* aObject);
2261
2262 void GenerateXPath(nsAString& aResult);
2263
2264 already_AddRefed<mozilla::dom::AccessibleNode> GetAccessibleNode();
2265
2266 /**
2267 * Returns the length of this node, as specified at
2268 * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
2269 */
2270 uint32_t Length() const;
2271
2272 void GetNodeName(mozilla::dom::DOMString& aNodeName) {
2273 const nsString& nodeName = NodeName();
2274 aNodeName.SetKnownLiveString(nodeName);
2275 }
2276 [[nodiscard]] nsresult GetBaseURI(nsAString& aBaseURI) const;
2277 // Return the base URI for the document.
2278 // The returned value may differ if the document is loaded via XHR, and
2279 // when accessed from chrome privileged script and
2280 // from content privileged script for compatibility.
2281 void GetBaseURIFromJS(nsAString& aBaseURI, CallerType aCallerType,
2282 ErrorResult& aRv) const;
2283 bool HasChildNodes() const { return HasChildren(); }
2284
2285 // See nsContentUtils::PositionIsBefore for aThisIndex and aOtherIndex usage.
2286 uint16_t CompareDocumentPosition(
2287 nsINode& aOther, mozilla::Maybe<uint32_t>* aThisIndex = nullptr,
2288 mozilla::Maybe<uint32_t>* aOtherIndex = nullptr) const;
2289 void GetNodeValue(nsAString& aNodeValue) { GetNodeValueInternal(aNodeValue); }
2290 void SetNodeValue(const nsAString& aNodeValue, mozilla::ErrorResult& aError) {
2291 SetNodeValueInternal(aNodeValue, aError);
2292 }
2293 virtual void GetNodeValueInternal(nsAString& aNodeValue);
2294 virtual void SetNodeValueInternal(const nsAString& aNodeValue,
2295 mozilla::ErrorResult& aError) {
2296 // The DOM spec says that when nodeValue is defined to be null "setting it
2297 // has no effect", so we don't throw an exception.
2298 }
2299 void EnsurePreInsertionValidity(nsINode& aNewChild, nsINode* aRefChild,
2300 mozilla::ErrorResult& aError);
2301 nsINode* InsertBefore(nsINode& aNode, nsINode* aChild,
2302 mozilla::ErrorResult& aError) {
2303 return ReplaceOrInsertBefore(false, &aNode, aChild, aError);
2304 }
2305
2306 /**
2307 * See <https://dom.spec.whatwg.org/#dom-node-appendchild>.
2308 */
2309 nsINode* AppendChild(nsINode& aNode, mozilla::ErrorResult& aError) {
2310 return InsertBefore(aNode, nullptr, aError);
2311 }
2312
2313 nsINode* ReplaceChild(nsINode& aNode, nsINode& aChild,
2314 mozilla::ErrorResult& aError) {
2315 return ReplaceOrInsertBefore(true, &aNode, &aChild, aError);
2316 }
2317 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
2318 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsINode* RemoveChild(
2319 nsINode& aChild, mozilla::ErrorResult& aError);
2320 already_AddRefed<nsINode> CloneNode(bool aDeep, mozilla::ErrorResult& aError);
2321 bool IsSameNode(nsINode* aNode);
2322 bool IsEqualNode(nsINode* aNode);
2323 void GetNamespaceURI(nsAString& aNamespaceURI) const {
2324 mNodeInfo->GetNamespaceURI(aNamespaceURI);
2325 }
2326#ifdef MOZILLA_INTERNAL_API1
2327 void GetPrefix(nsAString& aPrefix) { mNodeInfo->GetPrefix(aPrefix); }
2328#endif
2329 void GetLocalName(mozilla::dom::DOMString& aLocalName) const {
2330 const nsString& localName = LocalName();
2331 aLocalName.SetKnownLiveString(localName);
2332 }
2333
2334 nsDOMAttributeMap* GetAttributes();
2335
2336 // Helper method to remove this node from its parent. This is not exposed
2337 // through WebIDL.
2338 // Only call this if the node has a parent node.
2339 nsresult RemoveFromParent() {
2340 nsINode* parent = GetParentNode();
2341 mozilla::ErrorResult rv;
2342 parent->RemoveChild(*this, rv);
2343 return rv.StealNSResult();
2344 }
2345
2346 // ChildNode methods
2347 inline mozilla::dom::Element* GetPreviousElementSibling() const;
2348 inline mozilla::dom::Element* GetNextElementSibling() const;
2349
2350 MOZ_CAN_RUN_SCRIPT void Before(const Sequence<OwningNodeOrString>& aNodes,
2351 ErrorResult& aRv);
2352 MOZ_CAN_RUN_SCRIPT void After(const Sequence<OwningNodeOrString>& aNodes,
2353 ErrorResult& aRv);
2354 MOZ_CAN_RUN_SCRIPT void ReplaceWith(
2355 const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
2356 /**
2357 * Remove this node from its parent, if any.
2358 */
2359 void Remove();
2360
2361 // ParentNode methods
2362 mozilla::dom::Element* GetFirstElementChild() const;
2363 mozilla::dom::Element* GetLastElementChild() const;
2364
2365 already_AddRefed<nsIHTMLCollection> GetElementsByAttribute(
2366 const nsAString& aAttribute, const nsAString& aValue);
2367 already_AddRefed<nsIHTMLCollection> GetElementsByAttributeNS(
2368 const nsAString& aNamespaceURI, const nsAString& aAttribute,
2369 const nsAString& aValue, ErrorResult& aRv);
2370
2371 MOZ_CAN_RUN_SCRIPT void Prepend(const Sequence<OwningNodeOrString>& aNodes,
2372 ErrorResult& aRv);
2373 MOZ_CAN_RUN_SCRIPT void Append(const Sequence<OwningNodeOrString>& aNodes,
2374 ErrorResult& aRv);
2375 MOZ_CAN_RUN_SCRIPT void ReplaceChildren(
2376 const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
2377 MOZ_CAN_RUN_SCRIPT void ReplaceChildren(nsINode* aNode, ErrorResult& aRv);
2378
2379 void GetBoxQuads(const BoxQuadOptions& aOptions,
2380 nsTArray<RefPtr<DOMQuad>>& aResult, CallerType aCallerType,
2381 ErrorResult& aRv);
2382
2383 void GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions,
2384 nsTArray<RefPtr<DOMQuad>>& aResult,
2385 ErrorResult& aRv);
2386
2387 already_AddRefed<DOMQuad> ConvertQuadFromNode(
2388 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom,
2389 const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
2390 ErrorResult& aRv);
2391 already_AddRefed<DOMQuad> ConvertRectFromNode(
2392 DOMRectReadOnly& aRect, const TextOrElementOrDocument& aFrom,
2393 const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
2394 ErrorResult& aRv);
2395 already_AddRefed<DOMPoint> ConvertPointFromNode(
2396 const DOMPointInit& aPoint, const TextOrElementOrDocument& aFrom,
2397 const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
2398 ErrorResult& aRv);
2399
2400 /**
2401 * See nsSlots::mClosestCommonInclusiveAncestorRanges.
2402 */
2403 const mozilla::LinkedList<mozilla::dom::AbstractRange>*
2404 GetExistingClosestCommonInclusiveAncestorRanges() const {
2405 if (!HasSlots()) {
2406 return nullptr;
2407 }
2408 return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get();
2409 }
2410
2411 /**
2412 * See nsSlots::mClosestCommonInclusiveAncestorRanges.
2413 */
2414 mozilla::LinkedList<mozilla::dom::AbstractRange>*
2415 GetExistingClosestCommonInclusiveAncestorRanges() {
2416 if (!HasSlots()) {
2417 return nullptr;
2418 }
2419 return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get();
2420 }
2421
2422 /**
2423 * See nsSlots::mClosestCommonInclusiveAncestorRanges.
2424 */
2425 mozilla::UniquePtr<mozilla::LinkedList<mozilla::dom::AbstractRange>>&
2426 GetClosestCommonInclusiveAncestorRangesPtr() {
2427 return Slots()->mClosestCommonInclusiveAncestorRanges;
2428 }
2429
2430 nsIWeakReference* GetExistingWeakReference() {
2431 return HasSlots() ? GetExistingSlots()->mWeakReference : nullptr;
2432 }
2433
2434 protected:
2435 // Override this function to create a custom slots class.
2436 // Must not return null.
2437 virtual nsINode::nsSlots* CreateSlots();
2438
2439 bool HasSlots() const { return mSlots != nullptr; }
2440
2441 nsSlots* GetExistingSlots() const { return mSlots; }
2442
2443 nsSlots* Slots() {
2444 if (!HasSlots()) {
2445 mSlots = CreateSlots();
2446 MOZ_ASSERT(mSlots)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSlots)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mSlots))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mSlots", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSlots" ")"
); do { *((volatile int*)__null) = 2446; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2447 }
2448 return GetExistingSlots();
2449 }
2450
2451 /**
2452 * Invalidate cached child array inside mChildNodes
2453 * of type nsParentNodeChildContentList.
2454 */
2455 void InvalidateChildNodes();
2456
2457 virtual void GetTextContentInternal(nsAString& aTextContent,
2458 mozilla::OOMReporter& aError);
2459 virtual void SetTextContentInternal(const nsAString& aTextContent,
2460 nsIPrincipal* aSubjectPrincipal,
2461 mozilla::ErrorResult& aError) {}
2462
2463 void EnsurePreInsertionValidity1(mozilla::ErrorResult& aError);
2464 void EnsurePreInsertionValidity2(bool aReplace, nsINode& aNewChild,
2465 nsINode* aRefChild,
2466 mozilla::ErrorResult& aError);
2467 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
2468 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsINode* ReplaceOrInsertBefore(
2469 bool aReplace, nsINode* aNewChild, nsINode* aRefChild,
2470 mozilla::ErrorResult& aError);
2471
2472 /**
2473 * Returns the Element that should be used for resolving namespaces
2474 * on this node (ie the ownerElement for attributes, the documentElement for
2475 * documents, the node itself for elements and for other nodes the parentNode
2476 * if it is an element).
2477 */
2478 virtual mozilla::dom::Element* GetNameSpaceElement() = 0;
2479
2480 /**
2481 * Parse the given selector string into a servo SelectorList.
2482 *
2483 * Never returns null if aRv is not failing.
2484 *
2485 * Note that the selector list returned here is owned by the owner doc's
2486 * selector cache.
2487 */
2488 const mozilla::StyleSelectorList* ParseSelectorList(
2489 const nsACString& aSelectorString, mozilla::ErrorResult&);
2490
2491 public:
2492 /* Event stuff that documents and elements share.
2493
2494 Note that we include DOCUMENT_ONLY_EVENT events here so that we
2495 can forward all the document stuff to this implementation.
2496 */
2497#define EVENT(name_, id_, type_, struct_) \
2498 mozilla::dom::EventHandlerNonNull* GetOn##name_() { \
2499 return GetEventHandler(nsGkAtoms::on##name_); \
2500 } \
2501 void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler) { \
2502 SetEventHandler(nsGkAtoms::on##name_, handler); \
2503 }
2504#define TOUCH_EVENT EVENT
2505#define DOCUMENT_ONLY_EVENT EVENT
2506#include "mozilla/EventNameList.h"
2507#undef DOCUMENT_ONLY_EVENT
2508#undef TOUCH_EVENT
2509#undef EVENT
2510
2511 NodeSelectorFlags GetSelectorFlags() const {
2512 return static_cast<NodeSelectorFlags>(mSelectorFlags.Get());
2513 }
2514
2515 protected:
2516 static bool Traverse(nsINode* tmp, nsCycleCollectionTraversalCallback& cb);
2517 static void Unlink(nsINode* tmp);
2518
2519 RefPtr<mozilla::dom::NodeInfo> mNodeInfo;
2520
2521 // mParent is an owning ref most of the time, except for the case of document
2522 // nodes, so it cannot be represented by nsCOMPtr, so mark is as
2523 // MOZ_OWNING_REF.
2524 nsINode* MOZ_OWNING_REF mParent;
2525
2526 private:
2527#ifndef BOOL_FLAGS_ON_WRAPPER_CACHE
2528 // Boolean flags.
2529 uint32_t mBoolFlags;
2530#endif
2531
2532 mozilla::RustCell<uint32_t> mSelectorFlags{0};
2533
2534 uint32_t mChildCount;
2535
2536 protected:
2537 // mNextSibling and mFirstChild are strong references while
2538 // mPreviousOrLastSibling is a weak ref. |mFirstChild->mPreviousOrLastSibling|
2539 // points to the last child node.
2540 nsCOMPtr<nsIContent> mFirstChild;
2541 nsCOMPtr<nsIContent> mNextSibling;
2542 nsIContent* MOZ_NON_OWNING_REF mPreviousOrLastSibling;
2543
2544 union {
2545 // Pointer to our primary frame. Might be null.
2546 nsIFrame* mPrimaryFrame;
2547
2548 // Pointer to the root of our subtree. Might be null.
2549 // This reference is non-owning and safe, since it either points to the
2550 // object itself, or is reset by ClearSubtreeRootPointer.
2551 nsINode* MOZ_NON_OWNING_REF mSubtreeRoot;
2552 };
2553
2554 // Storage for more members that are usually not needed; allocated lazily.
2555 nsSlots* mSlots;
2556};
2557
2558NON_VIRTUAL_ADDREF_RELEASE(nsINode)
2559
2560inline nsINode* mozilla::dom::EventTarget::GetAsNode() {
2561 return IsNode() ? AsNode() : nullptr;
2562}
2563
2564inline const nsINode* mozilla::dom::EventTarget::GetAsNode() const {
2565 return const_cast<mozilla::dom::EventTarget*>(this)->GetAsNode();
2566}
2567
2568inline nsINode* mozilla::dom::EventTarget::AsNode() {
2569 MOZ_DIAGNOSTIC_ASSERT(IsNode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNode()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsNode()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2569); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "IsNode()"
")"); do { *((volatile int*)__null) = 2569; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2570 return static_cast<nsINode*>(this);
2571}
2572
2573inline const nsINode* mozilla::dom::EventTarget::AsNode() const {
2574 MOZ_DIAGNOSTIC_ASSERT(IsNode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNode()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsNode()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsINode.h"
, 2574); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "IsNode()"
")"); do { *((volatile int*)__null) = 2574; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2575 return static_cast<const nsINode*>(this);
2576}
2577
2578// Useful inline function for getting a node given an nsIContent and a Document.
2579// Returns the first argument cast to nsINode if it is non-null, otherwise
2580// returns the second (which may be null). We use type variables instead of
2581// nsIContent* and Document* because the actual types must be
2582// known for the cast to work.
2583template <class C, class D>
2584inline nsINode* NODE_FROM(C& aContent, D& aDocument) {
2585 if (aContent) return static_cast<nsINode*>(aContent);
2586 return static_cast<nsINode*>(aDocument);
2587}
2588
2589NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)template <typename T> struct nsINode::COMTypeInfo<nsINode
, T> { static const nsIID kIID __attribute__((visibility("hidden"
))); }; template <typename T> const nsIID nsINode::COMTypeInfo
<nsINode, T>::kIID __attribute__((visibility("hidden"))
) = {0x70ba4547, 0x7699, 0x44fc, {0xb3, 0x20, 0x52, 0xdb, 0xe3
, 0xd1, 0xf9, 0x0a}};
2590
2591inline nsISupports* ToSupports(nsINode* aPointer) { return aPointer; }
2592
2593// Some checks are faster to do on nsIContent or Element than on
2594// nsINode, so spit out FromNode versions taking those types too.
2595#define NS_IMPL_FROMNODE_GENERIC(_class, _check, _const)template <typename T> static auto FromNode(_const T&
aNode) -> decltype(static_cast<_const _class*>(&
aNode)) { return aNode._check ? static_cast<_const _class*
>(&aNode) : nullptr; } template <typename T> static
_const _class* FromNode(_const T* aNode) { return FromNode(*
aNode); } template <typename T> static _const _class* FromNodeOrNull
(_const T* aNode) { return aNode ? FromNode(*aNode) : nullptr
; } template <typename T> static auto FromEventTarget(_const
T& aEventTarget) -> decltype(static_cast<_const _class
*>(&aEventTarget)) { return aEventTarget.IsNode() &&
aEventTarget.AsNode()->_check ? static_cast<_const _class
*>(&aEventTarget) : nullptr; } template <typename T
> static _const _class* FromEventTarget(_const T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static _const _class* FromEventTargetOrNull(_const T* aEventTarget
) { return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; }
\
2596 template <typename T> \
2597 static auto FromNode(_const T& aNode) \
2598 -> decltype(static_cast<_const _class*>(&aNode)) { \
2599 return aNode._check ? static_cast<_const _class*>(&aNode) : nullptr; \
2600 } \
2601 template <typename T> \
2602 static _const _class* FromNode(_const T* aNode) { \
2603 return FromNode(*aNode); \
2604 } \
2605 template <typename T> \
2606 static _const _class* FromNodeOrNull(_const T* aNode) { \
2607 return aNode ? FromNode(*aNode) : nullptr; \
2608 } \
2609 template <typename T> \
2610 static auto FromEventTarget(_const T& aEventTarget) \
2611 -> decltype(static_cast<_const _class*>(&aEventTarget)) { \
2612 return aEventTarget.IsNode() && aEventTarget.AsNode()->_check \
2613 ? static_cast<_const _class*>(&aEventTarget) \
2614 : nullptr; \
2615 } \
2616 template <typename T> \
2617 static _const _class* FromEventTarget(_const T* aEventTarget) { \
2618 return FromEventTarget(*aEventTarget); \
2619 } \
2620 template <typename T> \
2621 static _const _class* FromEventTargetOrNull(_const T* aEventTarget) { \
2622 return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr; \
2623 }
2624
2625#define NS_IMPL_FROMNODE_HELPER(_class, _check)template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode._check ? static_cast< _class*>(&aNode) : nullptr
; } template <typename T> static _class* FromNode( T* aNode
) { return FromNode(*aNode); } template <typename T> static
_class* FromNodeOrNull( T* aNode) { return aNode ? FromNode(
*aNode) : nullptr; } template <typename T> static auto FromEventTarget
( T& aEventTarget) -> decltype(static_cast< _class*
>(&aEventTarget)) { return aEventTarget.IsNode() &&
aEventTarget.AsNode()->_check ? static_cast< _class*>
(&aEventTarget) : nullptr; } template <typename T> static
_class* FromEventTarget( T* aEventTarget) { return FromEventTarget
(*aEventTarget); } template <typename T> static _class*
FromEventTargetOrNull( T* aEventTarget) { return aEventTarget
? FromEventTarget(*aEventTarget) : nullptr; } template <typename
T> static auto FromNode(const T& aNode) -> decltype
(static_cast<const _class*>(&aNode)) { return aNode
._check ? static_cast<const _class*>(&aNode) : nullptr
; } template <typename T> static const _class* FromNode
(const T* aNode) { return FromNode(*aNode); } template <typename
T> static const _class* FromNodeOrNull(const T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget(const T& aEventTarget) ->
decltype(static_cast<const _class*>(&aEventTarget)
) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->_check ? static_cast<const _class*>(&aEventTarget
) : nullptr; } template <typename T> static const _class
* FromEventTarget(const T* aEventTarget) { return FromEventTarget
(*aEventTarget); } template <typename T> static const _class
* FromEventTargetOrNull(const T* aEventTarget) { return aEventTarget
? FromEventTarget(*aEventTarget) : nullptr; } template <typename
T> static _class* FromNode(T&& aNode) { return aNode
->_check ? static_cast<_class*>(static_cast<nsINode
*>(aNode)) : nullptr; } template <typename T> static
_class* FromNodeOrNull(T&& aNode) { return aNode ? FromNode
(aNode) : nullptr; } template <typename T> static _class
* FromEventTarget(T&& aEventTarget) { return aEventTarget
->IsNode() && aEventTarget->AsNode()->_check
? static_cast<_class*>(static_cast<EventTarget*>
(aEventTarget)) : nullptr; } template <typename T> static
_class* FromEventTargetOrNull(T&& aEventTarget) { return
aEventTarget ? FromEventTarget(aEventTarget) : nullptr; }
\
2626 NS_IMPL_FROMNODE_GENERIC(_class, _check, )template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode._check ? static_cast< _class*>(&aNode) : nullptr
; } template <typename T> static _class* FromNode( T* aNode
) { return FromNode(*aNode); } template <typename T> static
_class* FromNodeOrNull( T* aNode) { return aNode ? FromNode(
*aNode) : nullptr; } template <typename T> static auto FromEventTarget
( T& aEventTarget) -> decltype(static_cast< _class*
>(&aEventTarget)) { return aEventTarget.IsNode() &&
aEventTarget.AsNode()->_check ? static_cast< _class*>
(&aEventTarget) : nullptr; } template <typename T> static
_class* FromEventTarget( T* aEventTarget) { return FromEventTarget
(*aEventTarget); } template <typename T> static _class*
FromEventTargetOrNull( T* aEventTarget) { return aEventTarget
? FromEventTarget(*aEventTarget) : nullptr; }
\
2627 NS_IMPL_FROMNODE_GENERIC(_class, _check, const)template <typename T> static auto FromNode(const T&
aNode) -> decltype(static_cast<const _class*>(&
aNode)) { return aNode._check ? static_cast<const _class*>
(&aNode) : nullptr; } template <typename T> static const
_class* FromNode(const T* aNode) { return FromNode(*aNode); }
template <typename T> static const _class* FromNodeOrNull
(const T* aNode) { return aNode ? FromNode(*aNode) : nullptr;
} template <typename T> static auto FromEventTarget(const
T& aEventTarget) -> decltype(static_cast<const _class
*>(&aEventTarget)) { return aEventTarget.IsNode() &&
aEventTarget.AsNode()->_check ? static_cast<const _class
*>(&aEventTarget) : nullptr; } template <typename T
> static const _class* FromEventTarget(const T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static const _class* FromEventTargetOrNull(const T* aEventTarget
) { return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; }
\
2628 \
2629 template <typename T> \
2630 static _class* FromNode(T&& aNode) { \
2631 /* We need the double-cast in case aNode is a smartptr. Those */ \
2632 /* can cast to superclasses of the type they're templated on, */ \
2633 /* but not directly to subclasses. */ \
2634 return aNode->_check ? static_cast<_class*>(static_cast<nsINode*>(aNode)) \
2635 : nullptr; \
2636 } \
2637 template <typename T> \
2638 static _class* FromNodeOrNull(T&& aNode) { \
2639 return aNode ? FromNode(aNode) : nullptr; \
2640 } \
2641 template <typename T> \
2642 static _class* FromEventTarget(T&& aEventTarget) { \
2643 /* We need the double-cast in case aEventTarget is a smartptr. Those */ \
2644 /* can cast to superclasses of the type they're templated on, */ \
2645 /* but not directly to subclasses. */ \
2646 return aEventTarget->IsNode() && aEventTarget->AsNode()->_check \
2647 ? static_cast<_class*>(static_cast<EventTarget*>(aEventTarget)) \
2648 : nullptr; \
2649 } \
2650 template <typename T> \
2651 static _class* FromEventTargetOrNull(T&& aEventTarget) { \
2652 return aEventTarget ? FromEventTarget(aEventTarget) : nullptr; \
2653 }
2654
2655#define NS_IMPL_FROMNODE(_class, _nsid)template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.IsInNamespace(_nsid) ? static_cast< _class*>(&
aNode) : nullptr; } template <typename T> static _class
* FromNode( T* aNode) { return FromNode(*aNode); } template <
typename T> static _class* FromNodeOrNull( T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget( T& aEventTarget) -> decltype
(static_cast< _class*>(&aEventTarget)) { return aEventTarget
.IsNode() && aEventTarget.AsNode()->IsInNamespace(
_nsid) ? static_cast< _class*>(&aEventTarget) : nullptr
; } template <typename T> static _class* FromEventTarget
( T* aEventTarget) { return FromEventTarget(*aEventTarget); }
template <typename T> static _class* FromEventTargetOrNull
( T* aEventTarget) { return aEventTarget ? FromEventTarget(*aEventTarget
) : nullptr; } template <typename T> static auto FromNode
(const T& aNode) -> decltype(static_cast<const _class
*>(&aNode)) { return aNode.IsInNamespace(_nsid) ? static_cast
<const _class*>(&aNode) : nullptr; } template <typename
T> static const _class* FromNode(const T* aNode) { return
FromNode(*aNode); } template <typename T> static const
_class* FromNodeOrNull(const T* aNode) { return aNode ? FromNode
(*aNode) : nullptr; } template <typename T> static auto
FromEventTarget(const T& aEventTarget) -> decltype(static_cast
<const _class*>(&aEventTarget)) { return aEventTarget
.IsNode() && aEventTarget.AsNode()->IsInNamespace(
_nsid) ? static_cast<const _class*>(&aEventTarget) :
nullptr; } template <typename T> static const _class* FromEventTarget
(const T* aEventTarget) { return FromEventTarget(*aEventTarget
); } template <typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->IsInNamespace
(_nsid) ? static_cast<_class*>(static_cast<nsINode*>
(aNode)) : nullptr; } template <typename T> static _class
* FromNodeOrNull(T&& aNode) { return aNode ? FromNode
(aNode) : nullptr; } template <typename T> static _class
* FromEventTarget(T&& aEventTarget) { return aEventTarget
->IsNode() && aEventTarget->AsNode()->IsInNamespace
(_nsid) ? static_cast<_class*>(static_cast<EventTarget
*>(aEventTarget)) : nullptr; } template <typename T>
static _class* FromEventTargetOrNull(T&& aEventTarget
) { return aEventTarget ? FromEventTarget(aEventTarget) : nullptr
; }
\
2656 NS_IMPL_FROMNODE_HELPER(_class, IsInNamespace(_nsid))template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.IsInNamespace(_nsid) ? static_cast< _class*>(&
aNode) : nullptr; } template <typename T> static _class
* FromNode( T* aNode) { return FromNode(*aNode); } template <
typename T> static _class* FromNodeOrNull( T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget( T& aEventTarget) -> decltype
(static_cast< _class*>(&aEventTarget)) { return aEventTarget
.IsNode() && aEventTarget.AsNode()->IsInNamespace(
_nsid) ? static_cast< _class*>(&aEventTarget) : nullptr
; } template <typename T> static _class* FromEventTarget
( T* aEventTarget) { return FromEventTarget(*aEventTarget); }
template <typename T> static _class* FromEventTargetOrNull
( T* aEventTarget) { return aEventTarget ? FromEventTarget(*aEventTarget
) : nullptr; } template <typename T> static auto FromNode
(const T& aNode) -> decltype(static_cast<const _class
*>(&aNode)) { return aNode.IsInNamespace(_nsid) ? static_cast
<const _class*>(&aNode) : nullptr; } template <typename
T> static const _class* FromNode(const T* aNode) { return
FromNode(*aNode); } template <typename T> static const
_class* FromNodeOrNull(const T* aNode) { return aNode ? FromNode
(*aNode) : nullptr; } template <typename T> static auto
FromEventTarget(const T& aEventTarget) -> decltype(static_cast
<const _class*>(&aEventTarget)) { return aEventTarget
.IsNode() && aEventTarget.AsNode()->IsInNamespace(
_nsid) ? static_cast<const _class*>(&aEventTarget) :
nullptr; } template <typename T> static const _class* FromEventTarget
(const T* aEventTarget) { return FromEventTarget(*aEventTarget
); } template <typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->IsInNamespace
(_nsid) ? static_cast<_class*>(static_cast<nsINode*>
(aNode)) : nullptr; } template <typename T> static _class
* FromNodeOrNull(T&& aNode) { return aNode ? FromNode
(aNode) : nullptr; } template <typename T> static _class
* FromEventTarget(T&& aEventTarget) { return aEventTarget
->IsNode() && aEventTarget->AsNode()->IsInNamespace
(_nsid) ? static_cast<_class*>(static_cast<EventTarget
*>(aEventTarget)) : nullptr; } template <typename T>
static _class* FromEventTargetOrNull(T&& aEventTarget
) { return aEventTarget ? FromEventTarget(aEventTarget) : nullptr
; }
2657
2658#define NS_IMPL_FROMNODE_WITH_TAG(_class, _nsid, _tag)template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
< _class*>(&aNode) : nullptr; } template <typename
T> static _class* FromNode( T* aNode) { return FromNode(*
aNode); } template <typename T> static _class* FromNodeOrNull
( T* aNode) { return aNode ? FromNode(*aNode) : nullptr; } template
<typename T> static auto FromEventTarget( T& aEventTarget
) -> decltype(static_cast< _class*>(&aEventTarget
)) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
< _class*>(&aEventTarget) : nullptr; } template <
typename T> static _class* FromEventTarget( T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static _class* FromEventTargetOrNull( T* aEventTarget)
{ return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; } template <typename T> static auto FromNode(const T&
aNode) -> decltype(static_cast<const _class*>(&
aNode)) { return aNode.NodeInfo()->Equals(nsGkAtoms::_tag,
_nsid) ? static_cast<const _class*>(&aNode) : nullptr
; } template <typename T> static const _class* FromNode
(const T* aNode) { return FromNode(*aNode); } template <typename
T> static const _class* FromNodeOrNull(const T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget(const T& aEventTarget) ->
decltype(static_cast<const _class*>(&aEventTarget)
) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
<const _class*>(&aEventTarget) : nullptr; } template
<typename T> static const _class* FromEventTarget(const
T* aEventTarget) { return FromEventTarget(*aEventTarget); } template
<typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->NodeInfo
()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast<_class
*>(static_cast<nsINode*>(aNode)) : nullptr; } template
<typename T> static _class* FromNodeOrNull(T&&
aNode) { return aNode ? FromNode(aNode) : nullptr; } template
<typename T> static _class* FromEventTarget(T&&
aEventTarget) { return aEventTarget->IsNode() && aEventTarget
->AsNode()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid
) ? static_cast<_class*>(static_cast<EventTarget*>
(aEventTarget)) : nullptr; } template <typename T> static
_class* FromEventTargetOrNull(T&& aEventTarget) { return
aEventTarget ? FromEventTarget(aEventTarget) : nullptr; }
\
2659 NS_IMPL_FROMNODE_HELPER(_class, NodeInfo()->Equals(nsGkAtoms::_tag, _nsid))template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
< _class*>(&aNode) : nullptr; } template <typename
T> static _class* FromNode( T* aNode) { return FromNode(*
aNode); } template <typename T> static _class* FromNodeOrNull
( T* aNode) { return aNode ? FromNode(*aNode) : nullptr; } template
<typename T> static auto FromEventTarget( T& aEventTarget
) -> decltype(static_cast< _class*>(&aEventTarget
)) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
< _class*>(&aEventTarget) : nullptr; } template <
typename T> static _class* FromEventTarget( T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static _class* FromEventTargetOrNull( T* aEventTarget)
{ return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; } template <typename T> static auto FromNode(const T&
aNode) -> decltype(static_cast<const _class*>(&
aNode)) { return aNode.NodeInfo()->Equals(nsGkAtoms::_tag,
_nsid) ? static_cast<const _class*>(&aNode) : nullptr
; } template <typename T> static const _class* FromNode
(const T* aNode) { return FromNode(*aNode); } template <typename
T> static const _class* FromNodeOrNull(const T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget(const T& aEventTarget) ->
decltype(static_cast<const _class*>(&aEventTarget)
) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast
<const _class*>(&aEventTarget) : nullptr; } template
<typename T> static const _class* FromEventTarget(const
T* aEventTarget) { return FromEventTarget(*aEventTarget); } template
<typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->NodeInfo
()->Equals(nsGkAtoms::_tag, _nsid) ? static_cast<_class
*>(static_cast<nsINode*>(aNode)) : nullptr; } template
<typename T> static _class* FromNodeOrNull(T&&
aNode) { return aNode ? FromNode(aNode) : nullptr; } template
<typename T> static _class* FromEventTarget(T&&
aEventTarget) { return aEventTarget->IsNode() && aEventTarget
->AsNode()->NodeInfo()->Equals(nsGkAtoms::_tag, _nsid
) ? static_cast<_class*>(static_cast<EventTarget*>
(aEventTarget)) : nullptr; } template <typename T> static
_class* FromEventTargetOrNull(T&& aEventTarget) { return
aEventTarget ? FromEventTarget(aEventTarget) : nullptr; }
2660
2661#define NS_IMPL_FROMNODE_HTML_WITH_TAG(_class, _tag)template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
< _class*>(&aNode) : nullptr; } template <typename
T> static _class* FromNode( T* aNode) { return FromNode(*
aNode); } template <typename T> static _class* FromNodeOrNull
( T* aNode) { return aNode ? FromNode(*aNode) : nullptr; } template
<typename T> static auto FromEventTarget( T& aEventTarget
) -> decltype(static_cast< _class*>(&aEventTarget
)) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
< _class*>(&aEventTarget) : nullptr; } template <
typename T> static _class* FromEventTarget( T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static _class* FromEventTargetOrNull( T* aEventTarget)
{ return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; } template <typename T> static auto FromNode(const T&
aNode) -> decltype(static_cast<const _class*>(&
aNode)) { return aNode.NodeInfo()->Equals(nsGkAtoms::_tag,
3) ? static_cast<const _class*>(&aNode) : nullptr;
} template <typename T> static const _class* FromNode(
const T* aNode) { return FromNode(*aNode); } template <typename
T> static const _class* FromNodeOrNull(const T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget(const T& aEventTarget) ->
decltype(static_cast<const _class*>(&aEventTarget)
) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
<const _class*>(&aEventTarget) : nullptr; } template
<typename T> static const _class* FromEventTarget(const
T* aEventTarget) { return FromEventTarget(*aEventTarget); } template
<typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->NodeInfo
()->Equals(nsGkAtoms::_tag, 3) ? static_cast<_class*>
(static_cast<nsINode*>(aNode)) : nullptr; } template <
typename T> static _class* FromNodeOrNull(T&& aNode
) { return aNode ? FromNode(aNode) : nullptr; } template <
typename T> static _class* FromEventTarget(T&& aEventTarget
) { return aEventTarget->IsNode() && aEventTarget->
AsNode()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
<_class*>(static_cast<EventTarget*>(aEventTarget)
) : nullptr; } template <typename T> static _class* FromEventTargetOrNull
(T&& aEventTarget) { return aEventTarget ? FromEventTarget
(aEventTarget) : nullptr; }
\
2662 NS_IMPL_FROMNODE_WITH_TAG(_class, kNameSpaceID_XHTML, _tag)template <typename T> static auto FromNode( T& aNode
) -> decltype(static_cast< _class*>(&aNode)) { return
aNode.NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
< _class*>(&aNode) : nullptr; } template <typename
T> static _class* FromNode( T* aNode) { return FromNode(*
aNode); } template <typename T> static _class* FromNodeOrNull
( T* aNode) { return aNode ? FromNode(*aNode) : nullptr; } template
<typename T> static auto FromEventTarget( T& aEventTarget
) -> decltype(static_cast< _class*>(&aEventTarget
)) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
< _class*>(&aEventTarget) : nullptr; } template <
typename T> static _class* FromEventTarget( T* aEventTarget
) { return FromEventTarget(*aEventTarget); } template <typename
T> static _class* FromEventTargetOrNull( T* aEventTarget)
{ return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr
; } template <typename T> static auto FromNode(const T&
aNode) -> decltype(static_cast<const _class*>(&
aNode)) { return aNode.NodeInfo()->Equals(nsGkAtoms::_tag,
3) ? static_cast<const _class*>(&aNode) : nullptr;
} template <typename T> static const _class* FromNode(
const T* aNode) { return FromNode(*aNode); } template <typename
T> static const _class* FromNodeOrNull(const T* aNode) { return
aNode ? FromNode(*aNode) : nullptr; } template <typename T
> static auto FromEventTarget(const T& aEventTarget) ->
decltype(static_cast<const _class*>(&aEventTarget)
) { return aEventTarget.IsNode() && aEventTarget.AsNode
()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
<const _class*>(&aEventTarget) : nullptr; } template
<typename T> static const _class* FromEventTarget(const
T* aEventTarget) { return FromEventTarget(*aEventTarget); } template
<typename T> static const _class* FromEventTargetOrNull
(const T* aEventTarget) { return aEventTarget ? FromEventTarget
(*aEventTarget) : nullptr; } template <typename T> static
_class* FromNode(T&& aNode) { return aNode->NodeInfo
()->Equals(nsGkAtoms::_tag, 3) ? static_cast<_class*>
(static_cast<nsINode*>(aNode)) : nullptr; } template <
typename T> static _class* FromNodeOrNull(T&& aNode
) { return aNode ? FromNode(aNode) : nullptr; } template <
typename T> static _class* FromEventTarget(T&& aEventTarget
) { return aEventTarget->IsNode() && aEventTarget->
AsNode()->NodeInfo()->Equals(nsGkAtoms::_tag, 3) ? static_cast
<_class*>(static_cast<EventTarget*>(aEventTarget)
) : nullptr; } template <typename T> static _class* FromEventTargetOrNull
(T&& aEventTarget) { return aEventTarget ? FromEventTarget
(aEventTarget) : nullptr; }
2663
2664#endif /* nsINode_h___ */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h

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#ifndef MOZILLA_GFX_TEXTURECLIENT_H
8#define MOZILLA_GFX_TEXTURECLIENT_H
9
10#include <stddef.h> // for size_t
11#include <stdint.h> // for uint32_t, uint8_t, uint64_t
12
13#include "GLTextureImage.h" // for TextureImage
14#include "GfxTexturesReporter.h"
15#include "ImageTypes.h" // for StereoMode
16#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
17#include "mozilla/Atomics.h"
18#include "mozilla/Attributes.h" // for override
19#include "mozilla/DebugOnly.h"
20#include "mozilla/Mutex.h"
21#include "mozilla/RefPtr.h" // for RefPtr, RefCounted
22#include "mozilla/dom/ipc/IdType.h"
23#include "mozilla/gfx/2D.h" // for DrawTarget
24#include "mozilla/gfx/CriticalSection.h"
25#include "mozilla/gfx/Point.h" // for IntSize
26#include "mozilla/gfx/Types.h" // for SurfaceFormat
27#include "mozilla/ipc/FileDescriptor.h"
28#include "mozilla/ipc/Shmem.h" // for Shmem
29#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
30#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
31#include "mozilla/layers/ISurfaceAllocator.h"
32#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
33#include "mozilla/layers/LayersTypes.h"
34#include "mozilla/layers/SyncObject.h"
35#include "mozilla/mozalloc.h" // for operator delete
36#include "mozilla/webrender/WebRenderTypes.h"
37#include "nsCOMPtr.h" // for already_AddRefed
38#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
39#include "nsThreadUtils.h"
40#include "pratom.h"
41
42class gfxImageSurface;
43struct ID3D11Device;
44
45namespace mozilla {
46
47namespace layers {
48
49class AndroidHardwareBufferTextureData;
50class BufferTextureData;
51class CompositableForwarder;
52class FwdTransactionTracker;
53class KnowsCompositor;
54class LayersIPCChannel;
55class CompositableClient;
56struct PlanarYCbCrData;
57class Image;
58class PTextureChild;
59class TextureChild;
60class TextureData;
61class GPUVideoTextureData;
62class TextureClient;
63class ITextureClientRecycleAllocator;
64class SharedSurfaceTextureData;
65class TextureForwarder;
66class RecordedTextureData;
67struct RemoteTextureOwnerId;
68
69/**
70 * TextureClient is the abstraction that allows us to share data between the
71 * content and the compositor side.
72 */
73
74enum TextureAllocationFlags {
75 ALLOC_DEFAULT = 0,
76 ALLOC_CLEAR_BUFFER =
77 1 << 1, // Clear the buffer to whatever is best for the draw target
78 ALLOC_CLEAR_BUFFER_WHITE = 1 << 2, // explicit all white
79 ALLOC_CLEAR_BUFFER_BLACK = 1 << 3, // explicit all black
80 ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 1 << 4,
81
82 // Allocate the texture for out-of-band content updates. This is mostly for
83 // TextureClientD3D11, which may otherwise choose D3D10 or non-KeyedMutex
84 // surfaces when used on the main thread.
85 ALLOC_FOR_OUT_OF_BAND_CONTENT = 1 << 5,
86
87 // Disable any cross-device synchronization. This is also for
88 // TextureClientD3D11, and creates a texture without KeyedMutex.
89 ALLOC_MANUAL_SYNCHRONIZATION = 1 << 6,
90
91 // The texture is going to be updated using UpdateFromSurface and needs to
92 // support that call.
93 ALLOC_UPDATE_FROM_SURFACE = 1 << 7,
94
95 // Do not use an accelerated texture type.
96 ALLOC_DO_NOT_ACCELERATE = 1 << 8,
97
98 // Force allocation of remote/recorded texture, or fail if not possible.
99 ALLOC_FORCE_REMOTE = 1 << 9,
100};
101
102enum class BackendSelector { Content, Canvas };
103
104/// Temporary object providing direct access to a Texture's memory.
105///
106/// see TextureClient::CanExposeMappedData() and
107/// TextureClient::BorrowMappedData().
108struct MappedTextureData {
109 uint8_t* data;
110 gfx::IntSize size;
111 int32_t stride;
112 gfx::SurfaceFormat format;
113};
114
115struct MappedYCbCrChannelData {
116 uint8_t* data;
117 gfx::IntSize size;
118 int32_t stride;
119 int32_t skip;
120 uint32_t bytesPerPixel;
121
122 bool CopyInto(MappedYCbCrChannelData& aDst);
123};
124
125struct MappedYCbCrTextureData {
126 MappedYCbCrChannelData y;
127 MappedYCbCrChannelData cb;
128 MappedYCbCrChannelData cr;
129 // Sad but because of how SharedPlanarYCbCrData is used we have to expose this
130 // for now.
131 uint8_t* metadata;
132 StereoMode stereoMode;
133
134 bool CopyInto(MappedYCbCrTextureData& aDst) {
135 return y.CopyInto(aDst.y) && cb.CopyInto(aDst.cb) && cr.CopyInto(aDst.cr);
136 }
137};
138
139class ReadLockDescriptor;
140class NonBlockingTextureReadLock;
141
142// A class to help implement copy-on-write semantics for shared textures.
143//
144// A TextureClient/Host pair can opt into using a ReadLock by calling
145// TextureClient::EnableReadLock. This will equip the TextureClient with a
146// ReadLock object that will be automatically ReadLock()'ed by the texture
147// itself when it is written into (see TextureClient::Unlock). A
148// TextureReadLock's counter starts at 1 and is expected to be equal to 1 when
149// the lock is destroyed. See ShmemTextureReadLock for explanations about why we
150// use 1 instead of 0 as the initial state. TextureReadLock is mostly internally
151// managed by the TextureClient/Host pair, and the compositable only has to
152// forward it during updates. If an update message contains a null_t lock, it
153// means that the texture was not written into on the content side, and there is
154// no synchronization required on the compositor side (or it means that the
155// texture pair did not opt into using ReadLocks). On the compositor side, the
156// TextureHost can receive a ReadLock during a transaction, and will both
157// ReadUnlock() it and drop it as soon as the shared data is available again for
158// writing (the texture upload is done, or the compositor not reading the
159// texture anymore). The lock is dropped to make sure it is ReadUnlock()'ed only
160// once.
161class TextureReadLock {
162 protected:
163 virtual ~TextureReadLock() = default;
164
165 public:
166 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadLock)public: MozExternalRefCountType AddRef(void) { static_assert(
!std::is_destructible_v<TextureReadLock>, "Reference-counted class "
"TextureReadLock" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 166); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
166; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this
), (count), ("TextureReadLock"), (uint32_t)(sizeof(*this))); return
(nsrefcnt)count; } MozExternalRefCountType Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 166); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 166
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); nsrefcnt count = --mRefCnt; NS_LogRelease((this), (
count), ("TextureReadLock")); if (count == 0) { delete (this)
; return 0; } return count; } using HasThreadSafeRefCnt = std
::true_type; protected: ::mozilla::ThreadSafeAutoRefCnt mRefCnt
; public:
167
168 virtual bool ReadLock() = 0;
169 virtual bool TryReadLock(TimeDuration aTimeout) { return ReadLock(); }
170 virtual int32_t ReadUnlock() = 0;
171 virtual bool IsValid() const = 0;
172
173 static already_AddRefed<TextureReadLock> Deserialize(
174 ReadLockDescriptor&& aDescriptor, ISurfaceAllocator* aAllocator);
175
176 virtual bool Serialize(ReadLockDescriptor& aOutput,
177 base::ProcessId aOther) = 0;
178
179 enum LockType {
180 TYPE_NONBLOCKING_MEMORY,
181 TYPE_NONBLOCKING_SHMEM,
182 TYPE_CROSS_PROCESS_SEMAPHORE
183 };
184 virtual LockType GetType() = 0;
185
186 virtual NonBlockingTextureReadLock* AsNonBlockingLock() { return nullptr; }
187};
188
189class NonBlockingTextureReadLock : public TextureReadLock {
190 public:
191 virtual int32_t GetReadCount() = 0;
192
193 static already_AddRefed<TextureReadLock> Create(LayersIPCChannel* aAllocator);
194
195 NonBlockingTextureReadLock* AsNonBlockingLock() override { return this; }
196};
197
198#ifdef XP_WIN
199class D3D11TextureData;
200class DXGIYCbCrTextureData;
201#endif
202
203class TextureData {
204 public:
205 struct Info {
206 gfx::IntSize size;
207 gfx::SurfaceFormat format;
208 bool hasSynchronization;
209 bool supportsMoz2D;
210 bool canExposeMappedData;
211 bool canConcurrentlyReadLock;
212
213 Info()
214 : format(gfx::SurfaceFormat::UNKNOWN),
215 hasSynchronization(false),
216 supportsMoz2D(false),
217 canExposeMappedData(false),
218 canConcurrentlyReadLock(true) {}
219 };
220
221 static TextureData* Create(
222 TextureType aTextureType, gfx::SurfaceFormat aFormat,
223 const gfx::IntSize& aSize, TextureAllocationFlags aAllocFlags,
224 gfx::BackendType aBackendType = gfx::BackendType::NONE);
225 static TextureData* Create(TextureForwarder* aAllocator,
226 gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
227 KnowsCompositor* aKnowsCompositor,
228 BackendSelector aSelector,
229 TextureFlags aTextureFlags,
230 TextureAllocationFlags aAllocFlags);
231
232 static bool IsRemote(KnowsCompositor* aKnowsCompositor,
233 BackendSelector aSelector,
234 gfx::SurfaceFormat aFormat = gfx::SurfaceFormat::UNKNOWN,
235 gfx::IntSize aSize = gfx::IntSize(1, 1));
236
237 MOZ_COUNTED_DTOR_VIRTUAL(TextureData)virtual ~TextureData() { do { static_assert(std::is_class_v<
TextureData>, "Token '" "TextureData" "' is not a class type."
); static_assert(!std::is_base_of<nsISupports, TextureData
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "TextureData", sizeof
(*this)); } while (0); }
238
239 virtual TextureType GetTextureType() const { return TextureType::Last; }
240
241 virtual void FillInfo(TextureData::Info& aInfo) const = 0;
242
243 virtual void InvalidateContents() {}
244
245 virtual bool Lock(OpenMode aMode) = 0;
246
247 virtual void Unlock() = 0;
248
249 virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() {
250 return nullptr;
251 }
252
253 /**
254 * When the TextureData is not being Unlocked, this can be used to inform a
255 * TextureData that drawing has finished until the next BorrowDrawTarget.
256 */
257 virtual void EndDraw() {}
258
259 virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() {
260 return nullptr;
261 }
262
263 virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) {}
264
265 virtual bool BorrowMappedData(MappedTextureData&) { return false; }
266
267 virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
268
269 virtual void Deallocate(LayersIPCChannel* aAllocator) = 0;
270
271 /// Depending on the texture's flags either Deallocate or Forget is called.
272 virtual void Forget(LayersIPCChannel* aAllocator) {}
273
274 virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
275 virtual void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) {}
276
277 virtual void OnForwardedToHost() {}
278
279 virtual TextureData* CreateSimilar(
280 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
281 TextureFlags aFlags = TextureFlags::DEFAULT,
282 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const {
283 return nullptr;
284 }
285
286 virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) {
287 return false;
288 };
289
290 virtual void SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) {};
291
292 virtual TextureFlags GetTextureFlags() const {
293 return TextureFlags::NO_FLAGS;
294 }
295
296#ifdef XP_WIN
297 virtual D3D11TextureData* AsD3D11TextureData() { return nullptr; }
298 virtual DXGIYCbCrTextureData* AsDXGIYCbCrTextureData() { return nullptr; }
299#endif
300
301 virtual BufferTextureData* AsBufferTextureData() { return nullptr; }
302
303 virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; }
304
305 virtual AndroidHardwareBufferTextureData*
306 AsAndroidHardwareBufferTextureData() {
307 return nullptr;
308 }
309
310 virtual RecordedTextureData* AsRecordedTextureData() { return nullptr; }
311
312 // It is used by AndroidHardwareBufferTextureData and
313 // SharedSurfaceTextureData. Returns buffer id when it owns
314 // AndroidHardwareBuffer. It is used only on android.
315 virtual Maybe<uint64_t> GetBufferId() const { return Nothing(); }
316
317 // The acquire fence is a fence that is used for waiting until rendering to
318 // its AHardwareBuffer is completed.
319 // It is used only on android.
320 virtual mozilla::ipc::FileDescriptor GetAcquireFence() {
321 return mozilla::ipc::FileDescriptor();
322 }
323
324 virtual bool RequiresRefresh() const { return false; }
325
326 virtual already_AddRefed<FwdTransactionTracker> UseCompositableForwarder(
327 CompositableForwarder* aForwarder) {
328 return nullptr;
329 }
330
331 protected:
332 MOZ_COUNTED_DEFAULT_CTOR(TextureData)TextureData() { do { static_assert(std::is_class_v<TextureData
>, "Token '" "TextureData" "' is not a class type."); static_assert
(!std::is_base_of<nsISupports, TextureData>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "TextureData", sizeof
(*this)); } while (0); }
333};
334
335/**
336 * TextureClient is a thin abstraction over texture data that need to be shared
337 * between the content process and the compositor process. It is the
338 * content-side half of a TextureClient/TextureHost pair. A corresponding
339 * TextureHost lives on the compositor-side.
340 *
341 * TextureClient's primary purpose is to present texture data in a way that is
342 * understood by the IPC system. There are two ways to use it:
343 * - Use it to serialize image data that is not IPC-friendly (most likely
344 * involving a copy into shared memory)
345 * - preallocate it and paint directly into it, which avoids copy but requires
346 * the painting code to be aware of TextureClient (or at least the underlying
347 * shared memory).
348 *
349 * There is always one and only one TextureClient per TextureHost, and the
350 * TextureClient/Host pair only owns one buffer of image data through its
351 * lifetime. This means that the lifetime of the underlying shared data
352 * matches the lifetime of the TextureClient/Host pair. It also means
353 * TextureClient/Host do not implement double buffering, which is the
354 * responsibility of the compositable (which would use pairs of Textures).
355 * In order to send several different buffers to the compositor side, use
356 * several TextureClients.
357 */
358class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
359 public:
360 TextureClient(TextureData* aData, TextureFlags aFlags,
361 LayersIPCChannel* aAllocator);
362
363 virtual ~TextureClient();
364
365 static already_AddRefed<TextureClient> CreateWithData(
366 TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator);
367
368 // Creates and allocates a TextureClient usable with Moz2D.
369 static already_AddRefed<TextureClient> CreateForDrawing(
370 KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat,
371 gfx::IntSize aSize, BackendSelector aSelector, TextureFlags aTextureFlags,
372 TextureAllocationFlags flags = ALLOC_DEFAULT);
373
374 static already_AddRefed<TextureClient> CreateFromSurface(
375 KnowsCompositor* aAllocator, gfx::SourceSurface* aSurface,
376 BackendSelector aSelector, TextureFlags aTextureFlags,
377 TextureAllocationFlags aAllocFlags);
378
379 // Creates and allocates a TextureClient supporting the YCbCr format.
380 static already_AddRefed<TextureClient> CreateForYCbCr(
381 KnowsCompositor* aAllocator, const gfx::IntRect& aDisplay,
382 const gfx::IntSize& aYSize, uint32_t aYStride,
383 const gfx::IntSize& aCbCrSize, uint32_t aCbCrStride,
384 StereoMode aStereoMode, gfx::ColorDepth aColorDepth,
385 gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange,
386 gfx::ChromaSubsampling aSubsampling, TextureFlags aTextureFlags);
387
388 // Creates and allocates a TextureClient (can be accessed through raw
389 // pointers).
390 static already_AddRefed<TextureClient> CreateForRawBufferAccess(
391 KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat,
392 gfx::IntSize aSize, gfx::BackendType aMoz2dBackend,
393 TextureFlags aTextureFlags, TextureAllocationFlags flags = ALLOC_DEFAULT);
394
395 // Creates and allocates a TextureClient of the same type.
396 already_AddRefed<TextureClient> CreateSimilar(
397 LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
398 TextureFlags aFlags = TextureFlags::DEFAULT,
399 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const;
400
401 /**
402 * Locks the shared data, allowing the caller to get access to it.
403 *
404 * Please always lock/unlock when accessing the shared data.
405 * If Lock() returns false, you should not attempt to access the shared data.
406 */
407 bool Lock(OpenMode aMode);
408
409 void Unlock();
410
411 bool IsLocked() const { return mIsLocked; }
412
413 gfx::IntSize GetSize() const { return mInfo.size; }
414
415 gfx::SurfaceFormat GetFormat() const { return mInfo.format; }
416
417 /**
418 * Returns true if this texture has a synchronization mechanism (mutex, fence,
419 * etc.). Textures that do not implement synchronization should be immutable
420 * or should use immediate uploads (see TextureFlags in CompositorTypes.h)
421 * Even if a texture does not implement synchronization, Lock and Unlock need
422 * to be used appropriately since the latter are also there to map/numap data.
423 */
424 bool HasSynchronization() const { return mInfo.hasSynchronization; }
425
426 bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; }
427
428 bool CanExposeMappedData() const { return mInfo.canExposeMappedData; }
429
430 /**
431 * Returns a DrawTarget to draw into the TextureClient.
432 * This function should never be called when not on the main thread!
433 *
434 * This must never be called on a TextureClient that is not sucessfully
435 * locked. When called several times within one Lock/Unlock pair, this method
436 * should return the same DrawTarget. The DrawTarget is automatically flushed
437 * by the TextureClient when the latter is unlocked, and the DrawTarget that
438 * will be returned within the next lock/unlock pair may or may not be the
439 * same object. Do not keep references to the DrawTarget outside of the
440 * lock/unlock pair.
441 *
442 * This is typically used as follows:
443 *
444 * if (!texture->Lock(OpenMode::OPEN_READ_WRITE)) {
445 * return false;
446 * }
447 * {
448 * // Restrict this code's scope to ensure all references to dt are gone
449 * // when Unlock is called.
450 * DrawTarget* dt = texture->BorrowDrawTarget();
451 * // use the draw target ...
452 * }
453 * texture->Unlock();
454 *
455 */
456 gfx::DrawTarget* BorrowDrawTarget();
457
458 /**
459 * When the TextureClient is not being Unlocked, this can be used to inform it
460 * that drawing has finished until the next BorrowDrawTarget.
461 */
462 void EndDraw();
463
464 already_AddRefed<gfx::SourceSurface> BorrowSnapshot();
465
466 void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot);
467
468 /**
469 * Similar to BorrowDrawTarget but provides direct access to the texture's
470 * bits instead of a DrawTarget.
471 */
472 bool BorrowMappedData(MappedTextureData&);
473 bool BorrowMappedYCbCrData(MappedYCbCrTextureData&);
474
475 /**
476 * This function can be used to update the contents of the TextureClient
477 * off the main thread.
478 */
479 void UpdateFromSurface(gfx::SourceSurface* aSurface);
480
481 /**
482 * This method is strictly for debugging. It causes locking and
483 * needless copies.
484 */
485 already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
486
487 /**
488 * Copies a rectangle from this texture client to a position in aTarget.
489 * It is assumed that the necessary locks are in place; so this should at
490 * least have a read lock and aTarget should at least have a write lock.
491 */
492 bool CopyToTextureClient(TextureClient* aTarget, const gfx::IntRect* aRect,
493 const gfx::IntPoint* aPoint);
494
495 /**
496 * Allocate and deallocate a TextureChild actor.
497 *
498 * TextureChild is an implementation detail of TextureClient that is not
499 * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
500 * are for use with the managing IPDL protocols only (so that they can
501 * implement AllocPextureChild and DeallocPTextureChild).
502 */
503 static PTextureChild* CreateIPDLActor();
504 static bool DestroyIPDLActor(PTextureChild* actor);
505
506 /**
507 * Get the TextureClient corresponding to the actor passed in parameter.
508 */
509 static already_AddRefed<TextureClient> AsTextureClient(PTextureChild* actor);
510
511 /**
512 * TextureFlags contain important information about various aspects
513 * of the texture, like how its liferime is managed, and how it
514 * should be displayed.
515 * See TextureFlags in CompositorTypes.h.
516 */
517 TextureFlags GetFlags() const { return mFlags; }
518
519 bool HasFlags(TextureFlags aFlags) const {
520 return (mFlags & aFlags) == aFlags;
521 }
522
523 void AddFlags(TextureFlags aFlags);
524
525 void RemoveFlags(TextureFlags aFlags);
526
527 // Must not be called when TextureClient is in use by CompositableClient.
528 void RecycleTexture(TextureFlags aFlags);
529
530 /**
531 * After being shared with the compositor side, an immutable texture is never
532 * modified, it can only be read. It is safe to not Lock/Unlock immutable
533 * textures.
534 */
535 bool IsImmutable() const { return !!(mFlags & TextureFlags::IMMUTABLE); }
536
537 void MarkImmutable() { AddFlags(TextureFlags::IMMUTABLE); }
538
539 bool IsSharedWithCompositor() const;
540
541 /**
542 * If this method returns false users of TextureClient are not allowed
543 * to access the shared data.
544 */
545 bool IsValid() const { return !!mData; }
546
547 /**
548 * Called when TextureClient is added to CompositableClient.
549 */
550 void SetAddedToCompositableClient();
551
552 /**
553 * If this method retuns false, TextureClient is already added to
554 * CompositableClient, since its creation or recycling.
555 */
556 bool IsAddedToCompositableClient() const {
557 return mAddedToCompositableClient;
558 }
559
560 /**
561 * Create and init the TextureChild/Parent IPDL actor pair
562 * with a CompositableForwarder.
563 *
564 * Should be called only once per TextureClient.
565 * The TextureClient must not be locked when calling this method.
566 */
567 bool InitIPDLActor(CompositableForwarder* aForwarder);
568
569 /**
570 * Create and init the TextureChild/Parent IPDL actor pair
571 * with a TextureForwarder.
572 *
573 * Should be called only once per TextureClient.
574 * The TextureClient must not be locked when calling this method.
575 */
576 bool InitIPDLActor(KnowsCompositor* aKnowsCompositor,
577 const dom::ContentParentId& aContentId);
578
579 /**
580 * Return a pointer to the IPDLActor.
581 *
582 * This is to be used with IPDL messages only. Do not store the returned
583 * pointer.
584 */
585 PTextureChild* GetIPDLActor();
586
587 /**
588 * Triggers the destruction of the shared data and the corresponding
589 * TextureHost.
590 *
591 * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the
592 * destruction will be synchronously coordinated with the compositor side,
593 * otherwise it will be done asynchronously.
594 */
595 void Destroy();
596
597 /**
598 * Track how much of this texture is wasted.
599 * For example we might allocate a 256x256 tile but only use 10x10.
600 */
601 void SetWaste(int aWasteArea) {
602 mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
603 }
604
605 void SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) {
606 mData->SyncWithObject(aSyncObject);
607 }
608
609 LayersIPCChannel* GetAllocator() { return mAllocator; }
610
611 ITextureClientRecycleAllocator* GetRecycleAllocator() {
612 return mRecycleAllocator;
613 }
614 void SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator);
615
616 /// If you add new code that uses this method, you are probably doing
617 /// something wrong.
618 TextureData* GetInternalData() { return mData; }
619 const TextureData* GetInternalData() const { return mData; }
620
621 uint64_t GetSerial() const { return mSerial; }
622 void GetSurfaceDescriptorRemoteDecoder(
623 SurfaceDescriptorRemoteDecoder* aOutDesc);
624
625 void CancelWaitForNotifyNotUsed();
626
627 /**
628 * Set last transaction id of CompositableForwarder.
629 *
630 * Called when TextureClient has TextureFlags::RECYCLE flag.
631 * When CompositableForwarder forwards the TextureClient with
632 * TextureFlags::RECYCLE, it holds TextureClient's ref until host side
633 * releases it. The host side sends TextureClient release message.
634 * The id is used to check if the message is for the last TextureClient
635 * forwarding.
636 */
637 void SetLastFwdTransactionId(uint64_t aTransactionId) {
638 MOZ_ASSERT(mFwdTransactionId <= aTransactionId)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFwdTransactionId <= aTransactionId)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mFwdTransactionId <= aTransactionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mFwdTransactionId <= aTransactionId"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 638); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFwdTransactionId <= aTransactionId"
")"); do { *((volatile int*)__null) = 638; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
639 mFwdTransactionId = aTransactionId;
640 }
641
642 uint64_t GetLastFwdTransactionId() { return mFwdTransactionId; }
643
644 bool HasReadLock() const {
645 MutexAutoLock lock(mMutex);
646 return !!mReadLock;
647 }
648
649 int32_t GetNonBlockingReadLockCount() {
650 MutexAutoLock lock(mMutex);
651 if (NS_WARN_IF(!mReadLock)NS_warn_if_impl(!mReadLock, "!mReadLock", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 651)
) {
652 MOZ_ASSERT_UNREACHABLE("No read lock created yet?")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: "
"No read lock created yet?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "No read lock created yet?" ")");
do { *((volatile int*)__null) = 652; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
653 return 0;
654 }
655 MOZ_ASSERT(mReadLock->AsNonBlockingLock(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mReadLock->AsNonBlockingLock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mReadLock->AsNonBlockingLock
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mReadLock->AsNonBlockingLock()" " (" "Can only check locked for non-blocking locks!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mReadLock->AsNonBlockingLock()"
") (" "Can only check locked for non-blocking locks!" ")"); do
{ *((volatile int*)__null) = 656; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
656 "Can only check locked for non-blocking locks!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mReadLock->AsNonBlockingLock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mReadLock->AsNonBlockingLock
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mReadLock->AsNonBlockingLock()" " (" "Can only check locked for non-blocking locks!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mReadLock->AsNonBlockingLock()"
") (" "Can only check locked for non-blocking locks!" ")"); do
{ *((volatile int*)__null) = 656; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
657 return mReadLock->AsNonBlockingLock()->GetReadCount();
658 }
659
660 bool IsReadLocked();
661
662 bool ShouldReadLock() const {
663 return bool(mFlags & (TextureFlags::NON_BLOCKING_READ_LOCK |
664 TextureFlags::BLOCKING_READ_LOCK));
665 }
666
667 bool TryReadLock();
668 void ReadUnlock();
669
670 void SetUpdated() { mUpdated = true; }
671
672 void OnPrepareForwardToHost();
673 void OnAbandonForwardToHost();
674 bool OnForwardedToHost();
675
676 // Mark that the TextureClient will be used by the paint thread, and should
677 // not free its underlying texture data. This must only be called from the
678 // main thread.
679 void AddPaintThreadRef();
680
681 // Mark that the TextureClient is no longer in use by the PaintThread. This
682 // must only be called from the PaintThread.
683 void DropPaintThreadRef();
684
685 wr::MaybeExternalImageId GetExternalImageKey() { return mExternalImageId; }
686
687 private:
688 static void TextureClientRecycleCallback(TextureClient* aClient,
689 void* aClosure);
690
691 static already_AddRefed<TextureClient> CreateForDrawing(
692 TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat,
693 gfx::IntSize aSize, KnowsCompositor* aKnowsCompositor,
694 BackendSelector aSelector, TextureFlags aTextureFlags,
695 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
696
697 static already_AddRefed<TextureClient> CreateForRawBufferAccess(
698 LayersIPCChannel* aAllocator, gfx::SurfaceFormat aFormat,
699 gfx::IntSize aSize, gfx::BackendType aMoz2dBackend,
700 LayersBackend aLayersBackend, TextureFlags aTextureFlags,
701 TextureAllocationFlags flags = ALLOC_DEFAULT);
702
703 void EnsureHasReadLock() MOZ_REQUIRES(mMutex)__attribute__((exclusive_locks_required(mMutex)));
704 void EnableReadLock() MOZ_REQUIRES(mMutex)__attribute__((exclusive_locks_required(mMutex)));
705 void EnableBlockingReadLock() MOZ_REQUIRES(mMutex)__attribute__((exclusive_locks_required(mMutex)));
706
707 /**
708 * Called once, during the destruction of the Texture, on the thread in which
709 * texture's reference count reaches 0 (could be any thread).
710 *
711 * Here goes the shut-down code that uses virtual methods.
712 * Must only be called by Release().
713 */
714 void Finalize() {}
715
716 friend class AtomicRefCountedWithFinalize<TextureClient>;
717
718 protected:
719 /**
720 * Should only be called *once* per texture, in TextureClient::InitIPDLActor.
721 * Some texture implementations rely on the fact that the descriptor will be
722 * deserialized.
723 * Calling ToSurfaceDescriptor again after it has already returned true,
724 * or never constructing a TextureHost with aDescriptor may result in a memory
725 * leak (see TextureClientD3D9 for example).
726 */
727 bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor);
728
729 void LockActor() const;
730 void UnlockActor() const;
731
732 TextureData::Info mInfo;
733 mutable Mutex mMutex;
734
735 RefPtr<LayersIPCChannel> mAllocator;
736 RefPtr<TextureChild> mActor;
737 RefPtr<ITextureClientRecycleAllocator> mRecycleAllocator;
738 RefPtr<TextureReadLock> mReadLock MOZ_GUARDED_BY(mMutex)__attribute__((guarded_by(mMutex)));
739
740 TextureData* mData;
741 RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
742 bool mBorrowedSnapshot = false;
743
744 TextureFlags mFlags;
745
746 gl::GfxTextureWasteTracker mWasteTracker;
747
748 OpenMode mOpenMode;
749#ifdef DEBUG1
750 uint32_t mExpectedDtRefs;
751#endif
752 bool mIsLocked;
753 bool mIsReadLocked MOZ_GUARDED_BY(mMutex)__attribute__((guarded_by(mMutex)));
754 bool mIsPendingForwardReadLocked MOZ_GUARDED_BY(mMutex)__attribute__((guarded_by(mMutex))) = false;
755 // This member tracks that the texture was written into until the update
756 // is sent to the compositor. We need this remember to lock mReadLock on
757 // behalf of the compositor just before sending the notification.
758 bool mUpdated;
759
760 // Used when TextureClient is recycled with TextureFlags::RECYCLE flag.
761 bool mAddedToCompositableClient;
762
763 uint64_t mFwdTransactionId;
764
765 // Serial id of TextureClient. It is unique in current process.
766 const uint64_t mSerial;
767
768 // When non-zero, texture data must not be freed.
769 mozilla::Atomic<uintptr_t> mPaintThreadRefs;
770
771 // External image id. It is unique if it is allocated.
772 // The id is allocated in TextureClient::InitIPDLActor().
773 // Its allocation is supported by
774 // CompositorBridgeChild and ImageBridgeChild for now.
775 wr::MaybeExternalImageId mExternalImageId;
776
777 // Used to assign serial ids of TextureClient.
778 static mozilla::Atomic<uint64_t> sSerialCounter;
779
780 friend class TextureChild;
781 friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
782 friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
783 friend already_AddRefed<TextureHost> CreateTextureHostWithBackend(
784 TextureClient*, ISurfaceAllocator*, LayersBackend&);
785};
786
787/**
788 * Task that releases TextureClient pointer on a specified thread.
789 */
790class TextureClientReleaseTask : public Runnable {
791 public:
792 explicit TextureClientReleaseTask(TextureClient* aClient)
793 : Runnable("layers::TextureClientReleaseTask"), mTextureClient(aClient) {}
794
795 NS_IMETHODvirtual nsresult Run() override {
796 mTextureClient = nullptr;
797 return NS_OK;
798 }
799
800 private:
801 RefPtr<TextureClient> mTextureClient;
802};
803
804// Automatically lock and unlock a texture. Since texture locking is fallible,
805// Succeeded() must be checked on the guard object before proceeding.
806class MOZ_RAII TextureClientAutoLock {
807 public:
808 TextureClientAutoLock(TextureClient* aTexture, OpenMode aMode)
809 : mTexture(aTexture), mSucceeded(false) {
810 mSucceeded = mTexture->Lock(aMode);
811#ifdef DEBUG1
812 mChecked = false;
813#endif
814 }
815 ~TextureClientAutoLock() {
816 MOZ_ASSERT(mChecked)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChecked)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChecked))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mChecked", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/layers/TextureClient.h"
, 816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChecked" ")"
); do { *((volatile int*)__null) = 816; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
46
1st function call argument is an uninitialized value
817 if (mSucceeded) {
818 mTexture->Unlock();
819 }
820 }
821
822 bool Succeeded() {
823#ifdef DEBUG1
824 mChecked = true;
825#endif
826 return mSucceeded;
827 }
828
829 private:
830 TextureClient* mTexture;
831#ifdef DEBUG1
832 bool mChecked;
833#endif
834 bool mSucceeded;
835};
836
837/// Convenience function to set the content of ycbcr texture.
838bool UpdateYCbCrTextureClient(TextureClient* aTexture,
839 const PlanarYCbCrData& aData);
840
841TextureType PreferredCanvasTextureType(KnowsCompositor* aKnowsCompositor);
842
843} // namespace layers
844} // namespace mozilla
845
846#endif