Bug Summary

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