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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
12 | using namespace mozilla::gfx; | |||
13 | ||||
14 | namespace mozilla::gfx { | |||
15 | ||||
16 | InlineTranslator::InlineTranslator() : mFontContext(nullptr) {} | |||
17 | ||||
18 | InlineTranslator::InlineTranslator(DrawTarget* aDT, void* aFontContext) | |||
19 | : mBaseDT(aDT), mFontContext(aFontContext) {} | |||
20 | ||||
21 | bool 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) { | |||
| ||||
27 | mError = "Magic"; | |||
28 | return false; | |||
29 | } | |||
30 | ||||
31 | uint16_t majorRevision; | |||
32 | ReadElement(reader, majorRevision); | |||
33 | if (majorRevision != kMajorRevision) { | |||
| ||||
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 | ||||
78 | already_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 | ||||
88 | already_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 |
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 | |
15 | namespace mozilla { |
16 | namespace gfx { |
17 | |
18 | template <class S, class T> |
19 | struct 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)); |
25 | } |
26 | }; |
27 | template <class S> |
28 | struct 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 | |
50 | template <class S, class T> |
51 | void WriteElement(S& aStream, const T& aElement) { |
52 | ElementStreamFormat<S, T>::Write(aStream, aElement); |
53 | } |
54 | template <class S, class T> |
55 | void 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. |
65 | template <class S, class T, |
66 | typename = typename std::enable_if<!std::is_enum<T>::value>::type> |
67 | void ReadElement(S& aStream, T& aElement) { |
68 | ElementStreamFormat<S, T>::Read(aStream, aElement); |
69 | } |
70 | template <class S, class T> |
71 | void 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 | } |
78 | template <class S, class T> |
79 | void 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_ */ |
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 | |
22 | namespace mozilla { |
23 | namespace gfx { |
24 | |
25 | const 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. |
31 | const uint16_t kMajorRevision = 10; |
32 | // A change in minor revision means additions of new events. New streams will |
33 | // not play in older players. |
34 | const uint16_t kMinorRevision = 3; |
35 | |
36 | struct 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 | |
62 | struct RecordedFontDetails { |
63 | uint64_t fontDataKey = 0; |
64 | uint32_t size = 0; |
65 | uint32_t index = 0; |
66 | }; |
67 | |
68 | struct 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) |
83 | inline std::string StringFromPtr(ReferencePtr aPtr) { |
84 | std::stringstream stream; |
85 | stream << aPtr; |
86 | return stream.str(); |
87 | } |
88 | |
89 | class 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 | |
165 | struct ColorPatternStorage { |
166 | DeviceColor mColor; |
167 | }; |
168 | |
169 | struct LinearGradientPatternStorage { |
170 | Point mBegin; |
171 | Point mEnd; |
172 | ReferencePtr mStops; |
173 | Matrix mMatrix; |
174 | }; |
175 | |
176 | struct RadialGradientPatternStorage { |
177 | Point mCenter1; |
178 | Point mCenter2; |
179 | Float mRadius1; |
180 | Float mRadius2; |
181 | ReferencePtr mStops; |
182 | Matrix mMatrix; |
183 | }; |
184 | |
185 | struct ConicGradientPatternStorage { |
186 | Point mCenter; |
187 | Float mAngle; |
188 | Float mStartOffset; |
189 | Float mEndOffset; |
190 | ReferencePtr mStops; |
191 | Matrix mMatrix; |
192 | }; |
193 | |
194 | struct SurfacePatternStorage { |
195 | ExtendMode mExtend; |
196 | SamplingFilter mSamplingFilter; |
197 | ReferencePtr mSurface; |
198 | Matrix mMatrix; |
199 | IntRect mSamplingRect; |
200 | }; |
201 | |
202 | struct 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. */ |
219 | struct SizeCollector { |
220 | SizeCollector() : mTotalSize(0) {} |
221 | void write(const char*, size_t s) { mTotalSize += s; } |
222 | size_t mTotalSize; |
223 | }; |
224 | |
225 | struct 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 |
235 | struct 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)) { |
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 | |
256 | class 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. |
275 | class 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 | |
309 | struct 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 | |
365 | class 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 | |
373 | class 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 | |
510 | template <class Derived> |
511 | class 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 |