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