Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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