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-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 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 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/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/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 FILL,
392 FILLCIRCLE,
393 FILLGLYPHS,
394 STROKEGLYPHS,
395 MASK,
396 STROKE,
397 DRAWSURFACE,
398 DRAWSURFACEDESCRIPTOR,
399 DRAWDEPENDENTSURFACE,
400 DRAWSURFACEWITHSHADOW,
401 DRAWSHADOW,
402 PATHCREATION,
403 PATHDESTRUCTION,
404 SOURCESURFACECREATION,
405 SOURCESURFACEDESTRUCTION,
406 GRADIENTSTOPSCREATION,
407 GRADIENTSTOPSDESTRUCTION,
408 SNAPSHOT,
409 SCALEDFONTCREATION,
410 SCALEDFONTDESTRUCTION,
411 MASKSURFACE,
412 FILTERNODECREATION,
413 FILTERNODEDESTRUCTION,
414 DRAWFILTER,
415 FILTERNODESETATTRIBUTE,
416 FILTERNODESETINPUT,
417 CREATESIMILARDRAWTARGET,
418 CREATECLIPPEDDRAWTARGET,
419 CREATEDRAWTARGETFORFILTER,
420 FONTDATA,
421 FONTDESC,
422 PUSHLAYER,
423 PUSHLAYERWITHBLEND,
424 POPLAYER,
425 UNSCALEDFONTCREATION,
426 UNSCALEDFONTDESTRUCTION,
427 INTOLUMINANCE,
428 EXTRACTSUBRECT,
429 EXTERNALSURFACECREATION,
430 FLUSH,
431 DETACHALLSNAPSHOTS,
432 OPTIMIZESOURCESURFACE,
433 LINK,
434 DESTINATION,
435 LAST,
436 };
437
438 virtual ~RecordedEvent() = default;
439
440 static std::string GetEventName(EventType aType);
441
442 /**
443 * Play back this event using the translator. Note that derived classes
444 * should
445 * only return false when there is a fatal error, as it will probably mean
446 * the
447 * translation will abort.
448 * @param aTranslator Translator to be used for retrieving other referenced
449 * objects and making playback decisions.
450 * @return true unless a fatal problem has occurred and playback should
451 * abort.
452 */
453 virtual bool PlayEvent(Translator* aTranslator) const { return true; }
454
455 virtual void RecordToStream(std::ostream& aStream) const = 0;
456 virtual void RecordToStream(EventStream& aStream) const = 0;
457 virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0;
458 virtual void RecordToStream(MemStream& aStream) const = 0;
459
460 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
461
462 template <class S>
463 void RecordPatternData(S& aStream,
464 const PatternStorage& aPatternStorage) const;
465 template <class S>
466 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const;
467 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const;
468 template <class S>
469 void RecordStrokeOptions(S& aStream,
470 const StrokeOptions& aStrokeOptions) const;
471 template <class S>
472 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions);
473
474 virtual std::string GetName() const = 0;
475
476 virtual ReferencePtr GetDestinedDT() { return nullptr; }
477
478 void OutputSimplePatternInfo(const PatternStorage& aStorage,
479 std::stringstream& aOutput) const;
480
481 template <class S>
482 static bool DoWithEvent(S& aStream, EventType aType,
483 const std::function<bool(RecordedEvent*)>& aAction);
484 static bool DoWithEventFromStream(
485 EventStream& aStream, EventType aType,
486 const std::function<bool(RecordedEvent*)>& aAction);
487 static bool DoWithEventFromReader(
488 MemReader& aReader, EventType aType,
489 const std::function<bool(RecordedEvent*)>& aAction);
490
491 EventType GetType() const { return (EventType)mType; }
492
493 protected:
494 friend class DrawEventRecorderPrivate;
495 friend class DrawEventRecorderMemory;
496 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
497 std::ostream* aOutput);
498 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
499 MemStream& aOutput);
500 template <class S>
501 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput);
502
503 MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {}
504
505 EventType mType;
506 std::vector<Float> mDashPatternStorage;
507};
508
509template <class Derived>
510class RecordedEventDerived : public RecordedEvent {
511 using RecordedEvent::RecordedEvent;
512
513 public:
514 void RecordToStream(std::ostream& aStream) const override {
515 WriteElement(aStream, this->mType);
516 static_cast<const Derived*>(this)->Record(aStream);
517 }
518 void RecordToStream(EventStream& aStream) const override {
519 WriteElement(aStream, this->mType);
520 static_cast<const Derived*>(this)->Record(aStream);
521 }
522 void RecordToStream(ContiguousBufferStream& aStream) const final {
523 aStream.RecordEvent(static_cast<const Derived*>(this));
524 }
525 void RecordToStream(MemStream& aStream) const override {
526 SizeCollector size;
527 WriteElement(size, this->mType);
528 static_cast<const Derived*>(this)->Record(size);
529
530 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) {
531 return;
532 }
533
534 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
535 WriteElement(writer, this->mType);
536 static_cast<const Derived*>(this)->Record(writer);
537 }
538};
539
540} // namespace gfx
541} // namespace mozilla
542
543#endif