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
21 namespace mozilla {
22 namespace gfx {
23
24 const uint32_t kMagicInt = 0xc001feed;
25
26 // A change in major revision means a change in event binary format, causing
27 // loss of backwards compatibility. Old streams will not work in a player
28 // using a newer major revision. And new streams will not work in a player
29 // using an older major revision.
30 const uint16_t kMajorRevision = 10;
31 // A change in minor revision means additions of new events. New streams will
32 // not play in older players.
33 const uint16_t kMinorRevision = 2;
34
35 struct ReferencePtr {
ReferencePtrReferencePtr36 ReferencePtr() : mLongPtr(0) {}
37
ReferencePtrReferencePtr38 MOZ_IMPLICIT ReferencePtr(const void* aLongPtr)
39 : mLongPtr(uint64_t(aLongPtr)) {}
40
41 template <typename T>
ReferencePtrReferencePtr42 MOZ_IMPLICIT ReferencePtr(const RefPtr<T>& aPtr)
43 : mLongPtr(uint64_t(aPtr.get())) {}
44
45 ReferencePtr& operator=(const void* aLongPtr) {
46 mLongPtr = uint64_t(aLongPtr);
47 return *this;
48 }
49
50 template <typename T>
51 ReferencePtr& operator=(const RefPtr<T>& aPtr) {
52 mLongPtr = uint64_t(aPtr.get());
53 return *this;
54 }
55
56 operator void*() const { return (void*)mLongPtr; }
57
58 uint64_t mLongPtr;
59 };
60
61 struct RecordedFontDetails {
62 uint64_t fontDataKey = 0;
63 uint32_t size = 0;
64 uint32_t index = 0;
65 };
66
67 struct RecordedDependentSurface {
68 NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface);
69
RecordedDependentSurfaceRecordedDependentSurface70 RecordedDependentSurface(const IntSize& aSize,
71 mozilla::ipc::ByteBuf&& aRecording)
72 : mSize(aSize), mRecording(std::move(aRecording)) {}
73
74 IntSize mSize;
75 mozilla::ipc::ByteBuf mRecording;
76
77 private:
78 ~RecordedDependentSurface() = default;
79 };
80
81 // Used by the Azure drawing debugger (player2d)
StringFromPtr(ReferencePtr aPtr)82 inline std::string StringFromPtr(ReferencePtr aPtr) {
83 std::stringstream stream;
84 stream << aPtr;
85 return stream.str();
86 }
87
88 class Translator {
89 public:
90 virtual ~Translator() = default;
91
92 virtual DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) = 0;
93 virtual Path* LookupPath(ReferencePtr aRefPtr) = 0;
94 virtual SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) = 0;
95 virtual FilterNode* LookupFilterNode(ReferencePtr aRefPtr) = 0;
96 virtual already_AddRefed<GradientStops> LookupGradientStops(
97 ReferencePtr aRefPtr) = 0;
98 virtual ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) = 0;
99 virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0;
100 virtual NativeFontResource* LookupNativeFontResource(uint64_t aKey) = 0;
LookupExternalSurface(uint64_t aKey)101 virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) {
102 return nullptr;
103 }
104 virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0;
105 virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0;
106 virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0;
107 virtual void RemovePath(ReferencePtr aRefPtr) = 0;
108 virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface* aPath) = 0;
109 virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0;
110 virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr,
111 FilterNode* aSurface) = 0;
112 virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0;
113
114 /**
115 * Get GradientStops compatible with the translation DrawTarget type.
116 * @param aRawStops array of raw gradient stops required
117 * @param aNumStops length of aRawStops
118 * @param aExtendMode extend mode required
119 * @return an already addrefed GradientStops for our DrawTarget type
120 */
GetOrCreateGradientStops(GradientStop * aRawStops,uint32_t aNumStops,ExtendMode aExtendMode)121 virtual already_AddRefed<GradientStops> GetOrCreateGradientStops(
122 GradientStop* aRawStops, uint32_t aNumStops, ExtendMode aExtendMode) {
123 return GetReferenceDrawTarget()->CreateGradientStops(aRawStops, aNumStops,
124 aExtendMode);
125 }
126 virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops* aPath) = 0;
127 virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0;
128 virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont* aScaledFont) = 0;
129 virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0;
130 virtual void AddUnscaledFont(ReferencePtr aRefPtr,
131 UnscaledFont* aUnscaledFont) = 0;
132 virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0;
133 virtual void AddNativeFontResource(
134 uint64_t aKey, NativeFontResource* aNativeFontResource) = 0;
135
136 virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr,
137 const IntSize& aSize,
138 SurfaceFormat aFormat);
139 virtual DrawTarget* GetReferenceDrawTarget() = 0;
GetFontContext()140 virtual void* GetFontContext() { return nullptr; }
141 };
142
143 struct ColorPatternStorage {
144 DeviceColor mColor;
145 };
146
147 struct LinearGradientPatternStorage {
148 Point mBegin;
149 Point mEnd;
150 ReferencePtr mStops;
151 Matrix mMatrix;
152 };
153
154 struct RadialGradientPatternStorage {
155 Point mCenter1;
156 Point mCenter2;
157 Float mRadius1;
158 Float mRadius2;
159 ReferencePtr mStops;
160 Matrix mMatrix;
161 };
162
163 struct ConicGradientPatternStorage {
164 Point mCenter;
165 Float mAngle;
166 Float mStartOffset;
167 Float mEndOffset;
168 ReferencePtr mStops;
169 Matrix mMatrix;
170 };
171
172 struct SurfacePatternStorage {
173 ExtendMode mExtend;
174 SamplingFilter mSamplingFilter;
175 ReferencePtr mSurface;
176 Matrix mMatrix;
177 IntRect mSamplingRect;
178 };
179
180 struct PatternStorage {
181 PatternType mType;
182 union {
183 char* mStorage;
184 char mColor[sizeof(ColorPatternStorage)];
185 char mLinear[sizeof(LinearGradientPatternStorage)];
186 char mRadial[sizeof(RadialGradientPatternStorage)];
187 char mConic[sizeof(ConicGradientPatternStorage)];
188 char mSurface[sizeof(SurfacePatternStorage)];
189 };
190 };
191
192 /* SizeCollector and MemWriter are used
193 * in a pair to first collect the size of the
194 * event that we're going to write and then
195 * to write it without checking each individual
196 * size. */
197 struct SizeCollector {
SizeCollectorSizeCollector198 SizeCollector() : mTotalSize(0) {}
writeSizeCollector199 void write(const char*, size_t s) { mTotalSize += s; }
200 size_t mTotalSize;
201 };
202
203 struct MemWriter {
MemWriterMemWriter204 explicit MemWriter(char* aPtr) : mPtr(aPtr) {}
writeMemWriter205 void write(const char* aData, size_t aSize) {
206 memcpy(mPtr, aData, aSize);
207 mPtr += aSize;
208 }
209 char* mPtr;
210 };
211
212 // This is a simple interface for an EventRingBuffer, so we can use it in the
213 // RecordedEvent reading and writing machinery.
214 class EventRingBuffer {
215 public:
216 /**
217 * Templated RecordEvent function so that when we have enough contiguous
218 * space we can record into the buffer quickly using MemWriter.
219 *
220 * @param aRecordedEvent the event to record
221 */
222 template <class RE>
RecordEvent(const RE * aRecordedEvent)223 void RecordEvent(const RE* aRecordedEvent) {
224 SizeCollector size;
225 WriteElement(size, aRecordedEvent->GetType());
226 aRecordedEvent->Record(size);
227 if (size.mTotalSize > mAvailable) {
228 WaitForAndRecalculateAvailableSpace();
229 }
230 if (size.mTotalSize <= mAvailable) {
231 MemWriter writer(mBufPos);
232 WriteElement(writer, aRecordedEvent->GetType());
233 aRecordedEvent->Record(writer);
234 UpdateWriteTotalsBy(size.mTotalSize);
235 } else {
236 WriteElement(*this, aRecordedEvent->GetType());
237 aRecordedEvent->Record(*this);
238 }
239 }
240
241 /**
242 * Simple write function required by WriteElement.
243 *
244 * @param aData the data to be written to the buffer
245 * @param aSize the number of chars to write
246 */
247 virtual void write(const char* const aData, const size_t aSize) = 0;
248
249 /**
250 * Simple read function required by ReadElement.
251 *
252 * @param aOut the pointer to read into
253 * @param aSize the number of chars to read
254 */
255 virtual void read(char* const aOut, const size_t aSize) = 0;
256
257 virtual bool good() const = 0;
258
259 virtual void SetIsBad() = 0;
260
261 protected:
262 /**
263 * Wait until space is available for writing and then set mBufPos and
264 * mAvailable.
265 */
266 virtual bool WaitForAndRecalculateAvailableSpace() = 0;
267
268 /**
269 * Update write count, mBufPos and mAvailable.
270 *
271 * @param aCount number of bytes written
272 */
273 virtual void UpdateWriteTotalsBy(uint32_t aCount) = 0;
274
275 char* mBufPos = nullptr;
276 uint32_t mAvailable = 0;
277 };
278
279 struct MemStream {
280 char* mData;
281 size_t mLength;
282 size_t mCapacity;
283 bool mValid = true;
ResizeMemStream284 bool Resize(size_t aSize) {
285 if (!mValid) {
286 return false;
287 }
288 mLength = aSize;
289 if (mLength > mCapacity) {
290 mCapacity = mCapacity * 2;
291 // check if the doubled capacity is enough
292 // otherwise use double mLength
293 if (mLength > mCapacity) {
294 mCapacity = mLength * 2;
295 }
296 char* data = (char*)realloc(mData, mCapacity);
297 if (!data) {
298 free(mData);
299 }
300 mData = data;
301 }
302 if (mData) {
303 return true;
304 }
305 NS_ERROR("Failed to allocate MemStream!");
306 mValid = false;
307 mLength = 0;
308 mCapacity = 0;
309 return false;
310 }
311
resetMemStream312 void reset() {
313 free(mData);
314 mData = nullptr;
315 mValid = true;
316 mLength = 0;
317 mCapacity = 0;
318 }
319
320 MemStream(const MemStream&) = delete;
321 MemStream(MemStream&&) = delete;
322 MemStream& operator=(const MemStream&) = delete;
323 MemStream& operator=(MemStream&&) = delete;
324
writeMemStream325 void write(const char* aData, size_t aSize) {
326 if (Resize(mLength + aSize)) {
327 memcpy(mData + mLength - aSize, aData, aSize);
328 }
329 }
330
MemStreamMemStream331 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {}
~MemStreamMemStream332 ~MemStream() { free(mData); }
333 };
334
335 class EventStream {
336 public:
337 virtual void write(const char* aData, size_t aSize) = 0;
338 virtual void read(char* aOut, size_t aSize) = 0;
339 virtual bool good() = 0;
340 virtual void SetIsBad() = 0;
341 };
342
343 class RecordedEvent {
344 public:
345 enum EventType {
346 DRAWTARGETCREATION = 0,
347 DRAWTARGETDESTRUCTION,
348 FILLRECT,
349 STROKERECT,
350 STROKELINE,
351 CLEARRECT,
352 COPYSURFACE,
353 SETTRANSFORM,
354 PUSHCLIP,
355 PUSHCLIPRECT,
356 POPCLIP,
357 FILL,
358 FILLGLYPHS,
359 MASK,
360 STROKE,
361 DRAWSURFACE,
362 DRAWDEPENDENTSURFACE,
363 DRAWSURFACEWITHSHADOW,
364 PATHCREATION,
365 PATHDESTRUCTION,
366 SOURCESURFACECREATION,
367 SOURCESURFACEDESTRUCTION,
368 GRADIENTSTOPSCREATION,
369 GRADIENTSTOPSDESTRUCTION,
370 SNAPSHOT,
371 SCALEDFONTCREATION,
372 SCALEDFONTDESTRUCTION,
373 MASKSURFACE,
374 FILTERNODECREATION,
375 FILTERNODEDESTRUCTION,
376 DRAWFILTER,
377 FILTERNODESETATTRIBUTE,
378 FILTERNODESETINPUT,
379 CREATESIMILARDRAWTARGET,
380 CREATECLIPPEDDRAWTARGET,
381 CREATEDRAWTARGETFORFILTER,
382 FONTDATA,
383 FONTDESC,
384 PUSHLAYER,
385 PUSHLAYERWITHBLEND,
386 POPLAYER,
387 UNSCALEDFONTCREATION,
388 UNSCALEDFONTDESTRUCTION,
389 INTOLUMINANCE,
390 EXTERNALSURFACECREATION,
391 FLUSH,
392 DETACHALLSNAPSHOTS,
393 OPTIMIZESOURCESURFACE,
394 LINK,
395 LAST,
396 };
397
398 virtual ~RecordedEvent() = default;
399
400 static std::string GetEventName(EventType aType);
401
402 /**
403 * Play back this event using the translator. Note that derived classes
404 * should
405 * only return false when there is a fatal error, as it will probably mean
406 * the
407 * translation will abort.
408 * @param aTranslator Translator to be used for retrieving other referenced
409 * objects and making playback decisions.
410 * @return true unless a fatal problem has occurred and playback should
411 * abort.
412 */
PlayEvent(Translator * aTranslator)413 virtual bool PlayEvent(Translator* aTranslator) const { return true; }
414
415 virtual void RecordToStream(std::ostream& aStream) const = 0;
416 virtual void RecordToStream(EventStream& aStream) const = 0;
417 virtual void RecordToStream(EventRingBuffer& aStream) const = 0;
418 virtual void RecordToStream(MemStream& aStream) const = 0;
419
OutputSimpleEventInfo(std::stringstream & aStringStream)420 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
421
422 template <class S>
423 void RecordPatternData(S& aStream,
424 const PatternStorage& aPatternStorage) const;
425 template <class S>
426 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const;
427 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const;
428 template <class S>
429 void RecordStrokeOptions(S& aStream,
430 const StrokeOptions& aStrokeOptions) const;
431 template <class S>
432 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions);
433
434 virtual std::string GetName() const = 0;
435
GetDestinedDT()436 virtual ReferencePtr GetDestinedDT() { return nullptr; }
437
438 void OutputSimplePatternInfo(const PatternStorage& aStorage,
439 std::stringstream& aOutput) const;
440
441 template <class S>
442 static bool DoWithEvent(S& aStream, EventType aType,
443 const std::function<bool(RecordedEvent*)>& aAction);
444 static bool DoWithEventFromStream(
445 EventStream& aStream, EventType aType,
446 const std::function<bool(RecordedEvent*)>& aAction);
447 static bool DoWithEventFromStream(
448 EventRingBuffer& aStream, EventType aType,
449 const std::function<bool(RecordedEvent*)>& aAction);
450
GetType()451 EventType GetType() const { return (EventType)mType; }
452
453 protected:
454 friend class DrawEventRecorderPrivate;
455 friend class DrawEventRecorderFile;
456 friend class DrawEventRecorderMemory;
457 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
458 std::ostream* aOutput);
459 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
460 MemStream& aOutput);
461 template <class S>
462 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput);
463
RecordedEvent(int32_t aType)464 MOZ_IMPLICIT RecordedEvent(int32_t aType) : mType(aType) {}
465
466 int32_t mType;
467 std::vector<Float> mDashPatternStorage;
468 };
469
470 template <class Derived>
471 class RecordedEventDerived : public RecordedEvent {
472 using RecordedEvent::RecordedEvent;
473
474 public:
RecordToStream(std::ostream & aStream)475 void RecordToStream(std::ostream& aStream) const override {
476 WriteElement(aStream, this->mType);
477 static_cast<const Derived*>(this)->Record(aStream);
478 }
RecordToStream(EventStream & aStream)479 void RecordToStream(EventStream& aStream) const override {
480 WriteElement(aStream, this->mType);
481 static_cast<const Derived*>(this)->Record(aStream);
482 }
RecordToStream(EventRingBuffer & aStream)483 void RecordToStream(EventRingBuffer& aStream) const final {
484 aStream.RecordEvent(static_cast<const Derived*>(this));
485 }
RecordToStream(MemStream & aStream)486 void RecordToStream(MemStream& aStream) const override {
487 SizeCollector size;
488 WriteElement(size, this->mType);
489 static_cast<const Derived*>(this)->Record(size);
490
491 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) {
492 return;
493 }
494
495 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
496 WriteElement(writer, this->mType);
497 static_cast<const Derived*>(this)->Record(writer);
498 }
499 };
500
501 } // namespace gfx
502 } // namespace mozilla
503
504 #endif
505