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-20/lib/clang/20 -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 _GLIBCXX_ASSERTIONS -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-20/lib/clang/20/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-2025-01-20-090804-167946-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 aElement = false;
46 break;
47 }
48 }
49};
50
51template <class S, class T>
52void WriteElement(S& aStream, const T& aElement) {
53 ElementStreamFormat<S, T>::Write(aStream, aElement);
54}
55template <class S, class T>
56void WriteVector(S& aStream, const std::vector<T>& aVector) {
57 size_t size = aVector.size();
58 WriteElement(aStream, size);
59 if (size) {
60 aStream.write(reinterpret_cast<const char*>(aVector.data()),
61 sizeof(T) * size);
62 }
63}
64
65// ReadElement is disabled for enum types. Use ReadElementConstrained instead.
66template <class S, class T,
67 typename = typename std::enable_if<!std::is_enum<T>::value>::type>
68void ReadElement(S& aStream, T& aElement) {
69 ElementStreamFormat<S, T>::Read(aStream, aElement);
5
Calling 'ElementStreamFormat::Read'
11
Returning from 'ElementStreamFormat::Read'
70}
12
Returning without writing to 'aElement'
71template <class S, class T>
72void ReadElementConstrained(S& aStream, T& aElement, const T& aMinValue,
73 const T& aMaxValue) {
74 ElementStreamFormat<S, T>::Read(aStream, aElement);
75 if (aElement < aMinValue || aElement > aMaxValue) {
76 aStream.SetIsBad();
77 }
78}
79template <class S, class T>
80void ReadVector(S& aStream, std::vector<T>& aVector) {
81 size_t size;
82 ReadElement(aStream, size);
83 if (size && aStream.good()) {
84 aVector.resize(size);
85 aStream.read(reinterpret_cast<char*>(aVector.data()), sizeof(T) * size);
86 } else {
87 aVector.clear();
88 }
89}
90
91} // namespace gfx
92} // namespace mozilla
93
94#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 {
159 return mCurrentDT && mCurrentDT->IsValid() ? mCurrentDT : nullptr;
160 }
161
162 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
163 mDependentSurfaces = nullptr;
164 DrawTarget* mCurrentDT = nullptr;
165};
166
167struct ColorPatternStorage {
168 DeviceColor mColor;
169};
170
171struct LinearGradientPatternStorage {
172 Point mBegin;
173 Point mEnd;
174 ReferencePtr mStops;
175 Matrix mMatrix;
176};
177
178struct RadialGradientPatternStorage {
179 Point mCenter1;
180 Point mCenter2;
181 Float mRadius1;
182 Float mRadius2;
183 ReferencePtr mStops;
184 Matrix mMatrix;
185};
186
187struct ConicGradientPatternStorage {
188 Point mCenter;
189 Float mAngle;
190 Float mStartOffset;
191 Float mEndOffset;
192 ReferencePtr mStops;
193 Matrix mMatrix;
194};
195
196struct SurfacePatternStorage {
197 ExtendMode mExtend;
198 SamplingFilter mSamplingFilter;
199 ReferencePtr mSurface;
200 Matrix mMatrix;
201 IntRect mSamplingRect;
202};
203
204struct PatternStorage {
205 PatternType mType;
206 union {
207 char* mStorage;
208 char mColor[sizeof(ColorPatternStorage)];
209 char mLinear[sizeof(LinearGradientPatternStorage)];
210 char mRadial[sizeof(RadialGradientPatternStorage)];
211 char mConic[sizeof(ConicGradientPatternStorage)];
212 char mSurface[sizeof(SurfacePatternStorage)];
213 };
214};
215
216/* SizeCollector and MemWriter are used
217 * in a pair to first collect the size of the
218 * event that we're going to write and then
219 * to write it without checking each individual
220 * size. */
221struct SizeCollector {
222 SizeCollector() : mTotalSize(0) {}
223 void write(const char*, size_t s) { mTotalSize += s; }
224 size_t mTotalSize;
225};
226
227struct MemWriter {
228 constexpr explicit MemWriter(char* aPtr) : mPtr(aPtr) {}
229 void write(const char* aData, size_t aSize) {
230 memcpy(mPtr, aData, aSize);
231 mPtr += aSize;
232 }
233 char* mPtr;
234};
235
236// An istream like class for reading from memory
237struct MemReader {
238 constexpr MemReader(char* aData, size_t aLen)
239 : mData(aData), mEnd(aData + aLen) {}
240 void read(char* s, std::streamsize n) {
241 if (n <= (mEnd - mData)) {
7
Assuming the condition is false
8
Taking false branch
242 memcpy(s, mData, n);
243 mData += n;
244 } else {
245 // We've requested more data than is available
246 // set the Reader into an eof state
247 SetIsBad();
248 }
249 }
250 bool eof() { return mData > mEnd; }
251 bool good() { return !eof(); }
252 void SetIsBad() { mData = mEnd + 1; }
253
254 char* mData;
255 char* mEnd;
256};
257
258class ContiguousBuffer {
259 public:
260 ContiguousBuffer(char* aStart, size_t aSize)
261 : mWriter(aStart), mEnd(aStart + aSize) {}
262
263 constexpr MOZ_IMPLICIT ContiguousBuffer(std::nullptr_t) : mWriter(nullptr) {}
264
265 MemWriter& Writer() { return mWriter; }
266
267 size_t SizeRemaining() { return mWriter.mPtr ? mEnd - mWriter.mPtr : 0; }
268
269 bool IsValid() { return !!mWriter.mPtr; }
270
271 private:
272 MemWriter mWriter;
273 char* mEnd = nullptr;
274};
275
276// Allows a derived class to provide guaranteed contiguous buffer.
277class ContiguousBufferStream {
278 public:
279 /**
280 * Templated RecordEvent function so that we can record into the buffer
281 * quickly using MemWriter.
282 *
283 * @param aRecordedEvent the event to record
284 */
285 template <class RE>
286 void RecordEvent(const RE* aRecordedEvent) {
287 SizeCollector size;
288 WriteElement(size, aRecordedEvent->GetType());
289 aRecordedEvent->Record(size);
290 auto& buffer = GetContiguousBuffer(size.mTotalSize);
291 if (!buffer.IsValid()) {
292 return;
293 }
294
295 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"
, 295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "size.mTotalSize <= buffer.SizeRemaining()"
")"); do { *((volatile int*)__null) = 295; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
296
297 WriteElement(buffer.Writer(), aRecordedEvent->GetType());
298 aRecordedEvent->Record(buffer.Writer());
299 IncrementEventCount();
300 }
301
302 protected:
303 /**
304 * Provide a contiguous buffer with at least aSize remaining.
305 */
306 virtual ContiguousBuffer& GetContiguousBuffer(size_t aSize) = 0;
307
308 virtual void IncrementEventCount() = 0;
309};
310
311struct MemStream {
312 char* mData;
313 size_t mLength;
314 size_t mCapacity;
315 bool mValid = true;
316 bool Resize(size_t aSize) {
317 if (!mValid) {
318 return false;
319 }
320 mLength = aSize;
321 if (mLength > mCapacity) {
322 mCapacity = mCapacity * 2;
323 // check if the doubled capacity is enough
324 // otherwise use double mLength
325 if (mLength > mCapacity) {
326 mCapacity = mLength * 2;
327 }
328 char* data = (char*)realloc(mData, mCapacity);
329 if (!data) {
330 free(mData);
331 }
332 mData = data;
333 }
334 if (mData) {
335 return true;
336 }
337 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"
, 337); MOZ_PretendNoReturn(); } while (0)
;
338 mValid = false;
339 mLength = 0;
340 mCapacity = 0;
341 return false;
342 }
343
344 void reset() {
345 free(mData);
346 mData = nullptr;
347 mValid = true;
348 mLength = 0;
349 mCapacity = 0;
350 }
351
352 MemStream(const MemStream&) = delete;
353 MemStream(MemStream&&) = delete;
354 MemStream& operator=(const MemStream&) = delete;
355 MemStream& operator=(MemStream&&) = delete;
356
357 void write(const char* aData, size_t aSize) {
358 if (Resize(mLength + aSize)) {
359 memcpy(mData + mLength - aSize, aData, aSize);
360 }
361 }
362
363 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {}
364 ~MemStream() { free(mData); }
365};
366
367class EventStream {
368 public:
369 virtual void write(const char* aData, size_t aSize) = 0;
370 virtual void read(char* aOut, size_t aSize) = 0;
371 virtual bool good() = 0;
372 virtual void SetIsBad() = 0;
373};
374
375class RecordedEvent {
376 public:
377 enum EventType : uint8_t {
378 INVALID = 0,
379 DRAWTARGETCREATION,
380 DRAWTARGETDESTRUCTION,
381 SETCURRENTDRAWTARGET,
382 FILLRECT,
383 STROKERECT,
384 STROKELINE,
385 STROKECIRCLE,
386 CLEARRECT,
387 COPYSURFACE,
388 SETPERMITSUBPIXELAA,
389 SETTRANSFORM,
390 PUSHCLIP,
391 PUSHCLIPRECT,
392 POPCLIP,
393 REMOVEALLCLIPS,
394 FILL,
395 FILLCIRCLE,
396 FILLGLYPHS,
397 STROKEGLYPHS,
398 MASK,
399 STROKE,
400 DRAWSURFACE,
401 DRAWSURFACEDESCRIPTOR,
402 DRAWDEPENDENTSURFACE,
403 DRAWSURFACEWITHSHADOW,
404 DRAWSHADOW,
405 PATHCREATION,
406 PATHDESTRUCTION,
407 SOURCESURFACECREATION,
408 SOURCESURFACEDESTRUCTION,
409 GRADIENTSTOPSCREATION,
410 GRADIENTSTOPSDESTRUCTION,
411 SNAPSHOT,
412 SCALEDFONTCREATION,
413 SCALEDFONTDESTRUCTION,
414 MASKSURFACE,
415 FILTERNODECREATION,
416 FILTERNODEDESTRUCTION,
417 DRAWFILTER,
418 FILTERNODESETATTRIBUTE,
419 FILTERNODESETINPUT,
420 CREATESIMILARDRAWTARGET,
421 CREATECLIPPEDDRAWTARGET,
422 CREATEDRAWTARGETFORFILTER,
423 FONTDATA,
424 FONTDESC,
425 PUSHLAYER,
426 PUSHLAYERWITHBLEND,
427 POPLAYER,
428 UNSCALEDFONTCREATION,
429 UNSCALEDFONTDESTRUCTION,
430 INTOLUMINANCE,
431 EXTRACTSUBRECT,
432 EXTERNALSURFACECREATION,
433 FLUSH,
434 DETACHALLSNAPSHOTS,
435 OPTIMIZESOURCESURFACE,
436 LINK,
437 DESTINATION,
438 LAST,
439 };
440
441 virtual ~RecordedEvent() = default;
442
443 static std::string GetEventName(EventType aType);
444
445 /**
446 * Play back this event using the translator. Note that derived classes
447 * should
448 * only return false when there is a fatal error, as it will probably mean
449 * the
450 * translation will abort.
451 * @param aTranslator Translator to be used for retrieving other referenced
452 * objects and making playback decisions.
453 * @return true unless a fatal problem has occurred and playback should
454 * abort.
455 */
456 virtual bool PlayEvent(Translator* aTranslator) const { return true; }
457
458 virtual void RecordToStream(std::ostream& aStream) const = 0;
459 virtual void RecordToStream(EventStream& aStream) const = 0;
460 virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0;
461 virtual void RecordToStream(MemStream& aStream) const = 0;
462
463 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
464
465 template <class S>
466 void RecordPatternData(S& aStream,
467 const PatternStorage& aPatternStorage) const;
468 template <class S>
469 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const;
470 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const;
471 template <class S>
472 void RecordStrokeOptions(S& aStream,
473 const StrokeOptions& aStrokeOptions) const;
474 template <class S>
475 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions);
476
477 virtual std::string GetName() const = 0;
478
479 virtual ReferencePtr GetDestinedDT() { return nullptr; }
480
481 void OutputSimplePatternInfo(const PatternStorage& aStorage,
482 std::stringstream& aOutput) const;
483
484 template <class S>
485 static bool DoWithEvent(S& aStream, EventType aType,
486 const std::function<bool(RecordedEvent*)>& aAction);
487 static bool DoWithEventFromStream(
488 EventStream& aStream, EventType aType,
489 const std::function<bool(RecordedEvent*)>& aAction);
490 static bool DoWithEventFromReader(
491 MemReader& aReader, EventType aType,
492 const std::function<bool(RecordedEvent*)>& aAction);
493
494 EventType GetType() const { return (EventType)mType; }
495
496 protected:
497 friend class DrawEventRecorderPrivate;
498 friend class DrawEventRecorderMemory;
499 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
500 std::ostream* aOutput);
501 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
502 MemStream& aOutput);
503 template <class S>
504 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput);
505
506 MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {}
507
508 EventType mType;
509 std::vector<Float> mDashPatternStorage;
510};
511
512template <class Derived>
513class RecordedEventDerived : public RecordedEvent {
514 using RecordedEvent::RecordedEvent;
515
516 public:
517 void RecordToStream(std::ostream& aStream) const override {
518 WriteElement(aStream, this->mType);
519 static_cast<const Derived*>(this)->Record(aStream);
520 }
521 void RecordToStream(EventStream& aStream) const override {
522 WriteElement(aStream, this->mType);
523 static_cast<const Derived*>(this)->Record(aStream);
524 }
525 void RecordToStream(ContiguousBufferStream& aStream) const final {
526 aStream.RecordEvent(static_cast<const Derived*>(this));
527 }
528 void RecordToStream(MemStream& aStream) const override {
529 SizeCollector size;
530 WriteElement(size, this->mType);
531 static_cast<const Derived*>(this)->Record(size);
532
533 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) {
534 return;
535 }
536
537 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
538 WriteElement(writer, this->mType);
539 static_cast<const Derived*>(this)->Record(writer);
540 }
541};
542
543} // namespace gfx
544} // namespace mozilla
545
546#endif