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