Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.cpp
Warning:line 33, column 21
The left operand of '!=' is a garbage 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 InlineTranslator.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/2d -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/2d -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D USE_SSE2 -D USE_CAIRO -D MOZ2D_HAS_MOZ_CAIRO -D MOZ_ENABLE_FREETYPE -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/2d -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/gfx/skia -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/cairo/cairo/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/freetype2 -I /usr/include/libpng16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.cpp

/var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.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 "InlineTranslator.h"
8#include "RecordedEventImpl.h"
9
10#include "mozilla/gfx/RecordingTypes.h"
11
12using namespace mozilla::gfx;
13
14namespace mozilla::gfx {
15
16InlineTranslator::InlineTranslator() : mFontContext(nullptr) {}
17
18InlineTranslator::InlineTranslator(DrawTarget* aDT, void* aFontContext)
19 : mBaseDT(aDT), mFontContext(aFontContext) {}
20
21bool InlineTranslator::TranslateRecording(char* aData, size_t aLen) {
22 MemReader reader(aData, aLen);
23
24 uint32_t magicInt;
25 ReadElement(reader, magicInt);
26 if (magicInt != mozilla::gfx::kMagicInt) {
1
Assuming 'magicInt' is equal to 'kMagicInt'
2
Taking false branch
27 mError = "Magic";
28 return false;
29 }
30
31 uint16_t majorRevision;
3
'majorRevision' declared without an initial value
32 ReadElement(reader, majorRevision);
4
Calling 'ReadElement<mozilla::gfx::MemReader, unsigned short, void>'
13
Returning from 'ReadElement<mozilla::gfx::MemReader, unsigned short, void>'
33 if (majorRevision != kMajorRevision) {
14
The left operand of '!=' is a garbage value
34 mError = "Major";
35 return false;
36 }
37
38 uint16_t minorRevision;
39 ReadElement(reader, minorRevision);
40 if (minorRevision > kMinorRevision) {
41 mError = "Minor";
42 return false;
43 }
44
45 uint8_t eventType = RecordedEvent::EventType::INVALID;
46 ReadElement(reader, eventType);
47 while (reader.good()) {
48 bool success = RecordedEvent::DoWithEvent(
49 reader, static_cast<RecordedEvent::EventType>(eventType),
50 [&](RecordedEvent* recordedEvent) -> bool {
51 // Make sure that the whole event was read from the stream
52 // successfully.
53 if (!reader.good()) {
54 mError = " READ";
55 return false;
56 }
57
58 if (!recordedEvent->PlayEvent(this)) {
59 mError = " PLAY";
60 return false;
61 }
62
63 return true;
64 });
65 if (!success) {
66 mError = RecordedEvent::GetEventName(
67 static_cast<RecordedEvent::EventType>(eventType)) +
68 mError;
69 return false;
70 }
71
72 ReadElement(reader, eventType);
73 }
74
75 return true;
76}
77
78already_AddRefed<DrawTarget> InlineTranslator::CreateDrawTarget(
79 ReferencePtr aRefPtr, const gfx::IntSize& aSize,
80 gfx::SurfaceFormat aFormat) {
81 MOZ_ASSERT(mBaseDT, "mBaseDT has not been initialized.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBaseDT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBaseDT))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mBaseDT" " (" "mBaseDT has not been initialized."
")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.cpp"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBaseDT" ") ("
"mBaseDT has not been initialized." ")"); do { *((volatile int
*)__null) = 81; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
82
83 RefPtr<DrawTarget> drawTarget = mBaseDT;
84 AddDrawTarget(aRefPtr, drawTarget);
85 return drawTarget.forget();
86}
87
88already_AddRefed<SourceSurface> InlineTranslator::LookupExternalSurface(
89 uint64_t aKey) {
90 if (!mExternalSurfaces) {
91 return nullptr;
92 }
93 RefPtr<SourceSurface> surface = mExternalSurfaces->Get(aKey);
94 return surface.forget();
95}
96
97} // namespace mozilla::gfx

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordingTypes.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_RECORDINGTYPES_H_
8#define MOZILLA_GFX_RECORDINGTYPES_H_
9
10#include <ostream>
11#include <vector>
12
13#include "Logging.h"
14
15namespace mozilla {
16namespace gfx {
17
18template <class S, class T>
19struct ElementStreamFormat {
20 static void Write(S& aStream, const T& aElement) {
21 aStream.write(reinterpret_cast<const char*>(&aElement), sizeof(T));
22 }
23 static void Read(S& aStream, T& aElement) {
24 aStream.read(reinterpret_cast<char*>(&aElement), sizeof(T));
6
Calling 'MemReader::read'
9
Returning from 'MemReader::read'
25 }
10
Returning without writing to 'aElement'
26};
27template <class S>
28struct ElementStreamFormat<S, bool> {
29 static void Write(S& aStream, const bool& aElement) {
30 char boolChar = aElement ? '\x01' : '\x00';
31 aStream.write(&boolChar, sizeof(boolChar));
32 }
33 static void Read(S& aStream, bool& aElement) {
34 char boolChar;
35 aStream.read(&boolChar, sizeof(boolChar));
36 switch (boolChar) {
37 case '\x00':
38 aElement = false;
39 break;
40 case '\x01':
41 aElement = true;
42 break;
43 default:
44 aStream.SetIsBad();
45 break;
46 }
47 }
48};
49
50template <class S, class T>
51void WriteElement(S& aStream, const T& aElement) {
52 ElementStreamFormat<S, T>::Write(aStream, aElement);
53}
54template <class S, class T>
55void WriteVector(S& aStream, const std::vector<T>& aVector) {
56 size_t size = aVector.size();
57 WriteElement(aStream, size);
58 if (size) {
59 aStream.write(reinterpret_cast<const char*>(aVector.data()),
60 sizeof(T) * size);
61 }
62}
63
64// ReadElement is disabled for enum types. Use ReadElementConstrained instead.
65template <class S, class T,
66 typename = typename std::enable_if<!std::is_enum<T>::value>::type>
67void ReadElement(S& aStream, T& aElement) {
68 ElementStreamFormat<S, T>::Read(aStream, aElement);
5
Calling 'ElementStreamFormat::Read'
11
Returning from 'ElementStreamFormat::Read'
69}
12
Returning without writing to 'aElement'
70template <class S, class T>
71void ReadElementConstrained(S& aStream, T& aElement, const T& aMinValue,
72 const T& aMaxValue) {
73 ElementStreamFormat<S, T>::Read(aStream, aElement);
74 if (aElement < aMinValue || aElement > aMaxValue) {
75 aStream.SetIsBad();
76 }
77}
78template <class S, class T>
79void ReadVector(S& aStream, std::vector<T>& aVector) {
80 size_t size;
81 ReadElement(aStream, size);
82 if (size && aStream.good()) {
83 aVector.resize(size);
84 aStream.read(reinterpret_cast<char*>(aVector.data()), sizeof(T) * size);
85 } else {
86 aVector.clear();
87 }
88}
89
90} // namespace gfx
91} // namespace mozilla
92
93#endif /* MOZILLA_GFX_RECORDINGTYPES_H_ */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.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_RECORDEDEVENT_H_
8#define MOZILLA_GFX_RECORDEDEVENT_H_
9
10#include <ostream>
11#include <sstream>
12#include <cstring>
13#include <functional>
14#include <vector>
15
16#include "RecordingTypes.h"
17#include "mozilla/gfx/Point.h"
18#include "mozilla/gfx/Types.h"
19#include "mozilla/ipc/ByteBuf.h"
20#include "nsRefPtrHashtable.h"
21
22namespace mozilla {
23namespace gfx {
24
25const uint32_t kMagicInt = 0xc001feed;
26
27// A change in major revision means a change in event binary format, causing
28// loss of backwards compatibility. Old streams will not work in a player
29// using a newer major revision. And new streams will not work in a player
30// using an older major revision.
31const uint16_t kMajorRevision = 10;
32// A change in minor revision means additions of new events. New streams will
33// not play in older players.
34const uint16_t kMinorRevision = 3;
35
36struct ReferencePtr {
37 ReferencePtr() : mLongPtr(0) {}
38
39 MOZ_IMPLICIT ReferencePtr(const void* aLongPtr)
40 : mLongPtr(uint64_t(aLongPtr)) {}
41
42 template <typename T>
43 MOZ_IMPLICIT ReferencePtr(const RefPtr<T>& aPtr)
44 : mLongPtr(uint64_t(aPtr.get())) {}
45
46 ReferencePtr& operator=(const void* aLongPtr) {
47 mLongPtr = uint64_t(aLongPtr);
48 return *this;
49 }
50
51 template <typename T>
52 ReferencePtr& operator=(const RefPtr<T>& aPtr) {
53 mLongPtr = uint64_t(aPtr.get());
54 return *this;
55 }
56
57 operator void*() const { return (void*)mLongPtr; }
58
59 uint64_t mLongPtr;
60};
61
62struct RecordedFontDetails {
63 uint64_t fontDataKey = 0;
64 uint32_t size = 0;
65 uint32_t index = 0;
66};
67
68struct RecordedDependentSurface {
69 NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface)public: MozExternalRefCountType AddRef(void) { static_assert(
!std::is_destructible_v<RecordedDependentSurface>, "Reference-counted class "
"RecordedDependentSurface" " 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/gfx/RecordedEvent.h"
, 69); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
69; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("RecordedDependentSurface"
" not thread-safe"); ++mRefCnt; NS_LogAddRef((this), (mRefCnt
), ("RecordedDependentSurface"), (uint32_t)(sizeof(*this))); return
mRefCnt; } 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/gfx/RecordedEvent.h"
, 69); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 69
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("RecordedDependentSurface"
" not thread-safe"); --mRefCnt; NS_LogRelease((this), (mRefCnt
), ("RecordedDependentSurface")); if (mRefCnt == 0) { mRefCnt
= 1; delete (this); return 0; } return mRefCnt; } using HasThreadSafeRefCnt
= std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
;
70
71 RecordedDependentSurface(const IntSize& aSize,
72 mozilla::ipc::ByteBuf&& aRecording)
73 : mSize(aSize), mRecording(std::move(aRecording)) {}
74
75 IntSize mSize;
76 mozilla::ipc::ByteBuf mRecording;
77
78 private:
79 ~RecordedDependentSurface() = default;
80};
81
82// Used by the Azure drawing debugger (player2d)
83inline std::string StringFromPtr(ReferencePtr aPtr) {
84 std::stringstream stream;
85 stream << aPtr;
86 return stream.str();
87}
88
89class Translator {
90 public:
91 virtual ~Translator() = default;
92
93 virtual DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) = 0;
94 virtual Path* LookupPath(ReferencePtr aRefPtr) = 0;
95 virtual SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) = 0;
96 virtual FilterNode* LookupFilterNode(ReferencePtr aRefPtr) = 0;
97 virtual already_AddRefed<GradientStops> LookupGradientStops(
98 ReferencePtr aRefPtr) = 0;
99 virtual ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) = 0;
100 virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0;
101 virtual NativeFontResource* LookupNativeFontResource(uint64_t aKey) = 0;
102 virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) {
103 return nullptr;
104 }
105 virtual already_AddRefed<SourceSurface>
106 LookupSourceSurfaceFromSurfaceDescriptor(
107 const layers::SurfaceDescriptor& aDesc) {
108 MOZ_ASSERT_UNREACHABLE("unexpected to be called")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"unexpected to be called" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h"
, 108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unexpected to be called" ")"); do
{ *((volatile int*)__null) = 108; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
109 return nullptr;
110 }
111 void DrawDependentSurface(uint64_t aKey, const Rect& aRect);
112 virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0;
113 virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0;
114 virtual bool SetCurrentDrawTarget(ReferencePtr aRefPtr) = 0;
115 virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0;
116 virtual void RemovePath(ReferencePtr aRefPtr) = 0;
117 virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface* aPath) = 0;
118 virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0;
119 virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr,
120 FilterNode* aSurface) = 0;
121 virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0;
122
123 /**
124 * Get GradientStops compatible with the translation DrawTarget type.
125 * @param aRawStops array of raw gradient stops required
126 * @param aNumStops length of aRawStops
127 * @param aExtendMode extend mode required
128 * @return an already addrefed GradientStops for our DrawTarget type
129 */
130 virtual already_AddRefed<GradientStops> GetOrCreateGradientStops(
131 DrawTarget* aDrawTarget, GradientStop* aRawStops, uint32_t aNumStops,
132 ExtendMode aExtendMode) {
133 return aDrawTarget->CreateGradientStops(aRawStops, aNumStops, aExtendMode);
134 }
135 virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops* aPath) = 0;
136 virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0;
137 virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont* aScaledFont) = 0;
138 virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0;
139 virtual void AddUnscaledFont(ReferencePtr aRefPtr,
140 UnscaledFont* aUnscaledFont) = 0;
141 virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0;
142 virtual void AddNativeFontResource(
143 uint64_t aKey, NativeFontResource* aNativeFontResource) = 0;
144
145 virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr,
146 const IntSize& aSize,
147 SurfaceFormat aFormat);
148 virtual DrawTarget* GetReferenceDrawTarget() = 0;
149 virtual Matrix GetReferenceDrawTargetTransform() { return Matrix(); }
150 virtual void* GetFontContext() { return nullptr; }
151
152 void SetDependentSurfaces(
153 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
154 aDependentSurfaces) {
155 mDependentSurfaces = aDependentSurfaces;
156 }
157
158 DrawTarget* GetCurrentDrawTarget() const { return mCurrentDT; }
159
160 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
161 mDependentSurfaces = nullptr;
162 DrawTarget* mCurrentDT = nullptr;
163};
164
165struct ColorPatternStorage {
166 DeviceColor mColor;
167};
168
169struct LinearGradientPatternStorage {
170 Point mBegin;
171 Point mEnd;
172 ReferencePtr mStops;
173 Matrix mMatrix;
174};
175
176struct RadialGradientPatternStorage {
177 Point mCenter1;
178 Point mCenter2;
179 Float mRadius1;
180 Float mRadius2;
181 ReferencePtr mStops;
182 Matrix mMatrix;
183};
184
185struct ConicGradientPatternStorage {
186 Point mCenter;
187 Float mAngle;
188 Float mStartOffset;
189 Float mEndOffset;
190 ReferencePtr mStops;
191 Matrix mMatrix;
192};
193
194struct SurfacePatternStorage {
195 ExtendMode mExtend;
196 SamplingFilter mSamplingFilter;
197 ReferencePtr mSurface;
198 Matrix mMatrix;
199 IntRect mSamplingRect;
200};
201
202struct PatternStorage {
203 PatternType mType;
204 union {
205 char* mStorage;
206 char mColor[sizeof(ColorPatternStorage)];
207 char mLinear[sizeof(LinearGradientPatternStorage)];
208 char mRadial[sizeof(RadialGradientPatternStorage)];
209 char mConic[sizeof(ConicGradientPatternStorage)];
210 char mSurface[sizeof(SurfacePatternStorage)];
211 };
212};
213
214/* SizeCollector and MemWriter are used
215 * in a pair to first collect the size of the
216 * event that we're going to write and then
217 * to write it without checking each individual
218 * size. */
219struct SizeCollector {
220 SizeCollector() : mTotalSize(0) {}
221 void write(const char*, size_t s) { mTotalSize += s; }
222 size_t mTotalSize;
223};
224
225struct MemWriter {
226 constexpr explicit MemWriter(char* aPtr) : mPtr(aPtr) {}
227 void write(const char* aData, size_t aSize) {
228 memcpy(mPtr, aData, aSize);
229 mPtr += aSize;
230 }
231 char* mPtr;
232};
233
234// An istream like class for reading from memory
235struct MemReader {
236 constexpr MemReader(char* aData, size_t aLen)
237 : mData(aData), mEnd(aData + aLen) {}
238 void read(char* s, std::streamsize n) {
239 if (n <= (mEnd - mData)) {
7
Assuming the condition is false
8
Taking false branch
240 memcpy(s, mData, n);
241 mData += n;
242 } else {
243 // We've requested more data than is available
244 // set the Reader into an eof state
245 SetIsBad();
246 }
247 }
248 bool eof() { return mData > mEnd; }
249 bool good() { return !eof(); }
250 void SetIsBad() { mData = mEnd + 1; }
251
252 char* mData;
253 char* mEnd;
254};
255
256class ContiguousBuffer {
257 public:
258 ContiguousBuffer(char* aStart, size_t aSize)
259 : mWriter(aStart), mEnd(aStart + aSize) {}
260
261 constexpr MOZ_IMPLICIT ContiguousBuffer(std::nullptr_t) : mWriter(nullptr) {}
262
263 MemWriter& Writer() { return mWriter; }
264
265 size_t SizeRemaining() { return mWriter.mPtr ? mEnd - mWriter.mPtr : 0; }
266
267 bool IsValid() { return !!mWriter.mPtr; }
268
269 private:
270 MemWriter mWriter;
271 char* mEnd = nullptr;
272};
273
274// Allows a derived class to provide guaranteed contiguous buffer.
275class ContiguousBufferStream {
276 public:
277 /**
278 * Templated RecordEvent function so that we can record into the buffer
279 * quickly using MemWriter.
280 *
281 * @param aRecordedEvent the event to record
282 */
283 template <class RE>
284 void RecordEvent(const RE* aRecordedEvent) {
285 SizeCollector size;
286 WriteElement(size, aRecordedEvent->GetType());
287 aRecordedEvent->Record(size);
288 auto& buffer = GetContiguousBuffer(size.mTotalSize);
289 if (!buffer.IsValid()) {
290 return;
291 }
292
293 MOZ_ASSERT(size.mTotalSize <= buffer.SizeRemaining())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(size.mTotalSize <= buffer.SizeRemaining())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(size.mTotalSize <= buffer.SizeRemaining()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("size.mTotalSize <= buffer.SizeRemaining()"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "size.mTotalSize <= buffer.SizeRemaining()"
")"); do { *((volatile int*)__null) = 293; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
294
295 WriteElement(buffer.Writer(), aRecordedEvent->GetType());
296 aRecordedEvent->Record(buffer.Writer());
297 IncrementEventCount();
298 }
299
300 protected:
301 /**
302 * Provide a contiguous buffer with at least aSize remaining.
303 */
304 virtual ContiguousBuffer& GetContiguousBuffer(size_t aSize) = 0;
305
306 virtual void IncrementEventCount() = 0;
307};
308
309struct MemStream {
310 char* mData;
311 size_t mLength;
312 size_t mCapacity;
313 bool mValid = true;
314 bool Resize(size_t aSize) {
315 if (!mValid) {
316 return false;
317 }
318 mLength = aSize;
319 if (mLength > mCapacity) {
320 mCapacity = mCapacity * 2;
321 // check if the doubled capacity is enough
322 // otherwise use double mLength
323 if (mLength > mCapacity) {
324 mCapacity = mLength * 2;
325 }
326 char* data = (char*)realloc(mData, mCapacity);
327 if (!data) {
328 free(mData);
329 }
330 mData = data;
331 }
332 if (mData) {
333 return true;
334 }
335 NS_ERROR("Failed to allocate MemStream!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to allocate MemStream!"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h"
, 335); MOZ_PretendNoReturn(); } while (0)
;
336 mValid = false;
337 mLength = 0;
338 mCapacity = 0;
339 return false;
340 }
341
342 void reset() {
343 free(mData);
344 mData = nullptr;
345 mValid = true;
346 mLength = 0;
347 mCapacity = 0;
348 }
349
350 MemStream(const MemStream&) = delete;
351 MemStream(MemStream&&) = delete;
352 MemStream& operator=(const MemStream&) = delete;
353 MemStream& operator=(MemStream&&) = delete;
354
355 void write(const char* aData, size_t aSize) {
356 if (Resize(mLength + aSize)) {
357 memcpy(mData + mLength - aSize, aData, aSize);
358 }
359 }
360
361 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {}
362 ~MemStream() { free(mData); }
363};
364
365class EventStream {
366 public:
367 virtual void write(const char* aData, size_t aSize) = 0;
368 virtual void read(char* aOut, size_t aSize) = 0;
369 virtual bool good() = 0;
370 virtual void SetIsBad() = 0;
371};
372
373class RecordedEvent {
374 public:
375 enum EventType : uint8_t {
376 INVALID = 0,
377 DRAWTARGETCREATION,
378 DRAWTARGETDESTRUCTION,
379 SETCURRENTDRAWTARGET,
380 FILLRECT,
381 STROKERECT,
382 STROKELINE,
383 STROKECIRCLE,
384 CLEARRECT,
385 COPYSURFACE,
386 SETPERMITSUBPIXELAA,
387 SETTRANSFORM,
388 PUSHCLIP,
389 PUSHCLIPRECT,
390 POPCLIP,
391 REMOVEALLCLIPS,
392 FILL,
393 FILLCIRCLE,
394 FILLGLYPHS,
395 STROKEGLYPHS,
396 MASK,
397 STROKE,
398 DRAWSURFACE,
399 DRAWSURFACEDESCRIPTOR,
400 DRAWDEPENDENTSURFACE,
401 DRAWSURFACEWITHSHADOW,
402 DRAWSHADOW,
403 PATHCREATION,
404 PATHDESTRUCTION,
405 SOURCESURFACECREATION,
406 SOURCESURFACEDESTRUCTION,
407 GRADIENTSTOPSCREATION,
408 GRADIENTSTOPSDESTRUCTION,
409 SNAPSHOT,
410 SCALEDFONTCREATION,
411 SCALEDFONTDESTRUCTION,
412 MASKSURFACE,
413 FILTERNODECREATION,
414 FILTERNODEDESTRUCTION,
415 DRAWFILTER,
416 FILTERNODESETATTRIBUTE,
417 FILTERNODESETINPUT,
418 CREATESIMILARDRAWTARGET,
419 CREATECLIPPEDDRAWTARGET,
420 CREATEDRAWTARGETFORFILTER,
421 FONTDATA,
422 FONTDESC,
423 PUSHLAYER,
424 PUSHLAYERWITHBLEND,
425 POPLAYER,
426 UNSCALEDFONTCREATION,
427 UNSCALEDFONTDESTRUCTION,
428 INTOLUMINANCE,
429 EXTRACTSUBRECT,
430 EXTERNALSURFACECREATION,
431 FLUSH,
432 DETACHALLSNAPSHOTS,
433 OPTIMIZESOURCESURFACE,
434 LINK,
435 DESTINATION,
436 LAST,
437 };
438
439 virtual ~RecordedEvent() = default;
440
441 static std::string GetEventName(EventType aType);
442
443 /**
444 * Play back this event using the translator. Note that derived classes
445 * should
446 * only return false when there is a fatal error, as it will probably mean
447 * the
448 * translation will abort.
449 * @param aTranslator Translator to be used for retrieving other referenced
450 * objects and making playback decisions.
451 * @return true unless a fatal problem has occurred and playback should
452 * abort.
453 */
454 virtual bool PlayEvent(Translator* aTranslator) const { return true; }
455
456 virtual void RecordToStream(std::ostream& aStream) const = 0;
457 virtual void RecordToStream(EventStream& aStream) const = 0;
458 virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0;
459 virtual void RecordToStream(MemStream& aStream) const = 0;
460
461 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
462
463 template <class S>
464 void RecordPatternData(S& aStream,
465 const PatternStorage& aPatternStorage) const;
466 template <class S>
467 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const;
468 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const;
469 template <class S>
470 void RecordStrokeOptions(S& aStream,
471 const StrokeOptions& aStrokeOptions) const;
472 template <class S>
473 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions);
474
475 virtual std::string GetName() const = 0;
476
477 virtual ReferencePtr GetDestinedDT() { return nullptr; }
478
479 void OutputSimplePatternInfo(const PatternStorage& aStorage,
480 std::stringstream& aOutput) const;
481
482 template <class S>
483 static bool DoWithEvent(S& aStream, EventType aType,
484 const std::function<bool(RecordedEvent*)>& aAction);
485 static bool DoWithEventFromStream(
486 EventStream& aStream, EventType aType,
487 const std::function<bool(RecordedEvent*)>& aAction);
488 static bool DoWithEventFromReader(
489 MemReader& aReader, EventType aType,
490 const std::function<bool(RecordedEvent*)>& aAction);
491
492 EventType GetType() const { return (EventType)mType; }
493
494 protected:
495 friend class DrawEventRecorderPrivate;
496 friend class DrawEventRecorderMemory;
497 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
498 std::ostream* aOutput);
499 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
500 MemStream& aOutput);
501 template <class S>
502 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput);
503
504 MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {}
505
506 EventType mType;
507 std::vector<Float> mDashPatternStorage;
508};
509
510template <class Derived>
511class RecordedEventDerived : public RecordedEvent {
512 using RecordedEvent::RecordedEvent;
513
514 public:
515 void RecordToStream(std::ostream& aStream) const override {
516 WriteElement(aStream, this->mType);
517 static_cast<const Derived*>(this)->Record(aStream);
518 }
519 void RecordToStream(EventStream& aStream) const override {
520 WriteElement(aStream, this->mType);
521 static_cast<const Derived*>(this)->Record(aStream);
522 }
523 void RecordToStream(ContiguousBufferStream& aStream) const final {
524 aStream.RecordEvent(static_cast<const Derived*>(this));
525 }
526 void RecordToStream(MemStream& aStream) const override {
527 SizeCollector size;
528 WriteElement(size, this->mType);
529 static_cast<const Derived*>(this)->Record(size);
530
531 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) {
532 return;
533 }
534
535 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
536 WriteElement(writer, this->mType);
537 static_cast<const Derived*>(this)->Record(writer);
538 }
539};
540
541} // namespace gfx
542} // namespace mozilla
543
544#endif