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/. */
7 #ifndef MOZILLA_GFX_RECORDEDEVENT_H_
8 #define MOZILLA_GFX_RECORDEDEVENT_H_
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"
25 const uint32_t kMagicInt
= 0xc001feed;
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;
37 ReferencePtr() : mLongPtr(0) {}
39 MOZ_IMPLICIT
ReferencePtr(const void* aLongPtr
)
40 : mLongPtr(uint64_t(aLongPtr
)) {}
43 MOZ_IMPLICIT
ReferencePtr(const RefPtr
<T
>& aPtr
)
44 : mLongPtr(uint64_t(aPtr
.get())) {}
46 ReferencePtr
& operator=(const void* aLongPtr
) {
47 mLongPtr
= uint64_t(aLongPtr
);
52 ReferencePtr
& operator=(const RefPtr
<T
>& aPtr
) {
53 mLongPtr
= uint64_t(aPtr
.get());
57 operator void*() const { return (void*)mLongPtr
; }
62 struct RecordedFontDetails
{
63 uint64_t fontDataKey
= 0;
68 struct RecordedDependentSurface
{
69 NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface
);
71 RecordedDependentSurface(const IntSize
& aSize
,
72 mozilla::ipc::ByteBuf
&& aRecording
)
73 : mSize(aSize
), mRecording(std::move(aRecording
)) {}
76 mozilla::ipc::ByteBuf mRecording
;
79 ~RecordedDependentSurface() = default;
82 // Used by the Azure drawing debugger (player2d)
83 inline std::string
StringFromPtr(ReferencePtr aPtr
) {
84 std::stringstream stream
;
91 virtual ~Translator() = default;
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
) {
105 void DrawDependentSurface(uint64_t aKey
, const Rect
& aRect
);
106 virtual void AddDrawTarget(ReferencePtr aRefPtr
, DrawTarget
* aDT
) = 0;
107 virtual void RemoveDrawTarget(ReferencePtr aRefPtr
) = 0;
108 virtual bool SetCurrentDrawTarget(ReferencePtr aRefPtr
) = 0;
109 virtual void AddPath(ReferencePtr aRefPtr
, Path
* aPath
) = 0;
110 virtual void RemovePath(ReferencePtr aRefPtr
) = 0;
111 virtual void AddSourceSurface(ReferencePtr aRefPtr
, SourceSurface
* aPath
) = 0;
112 virtual void RemoveSourceSurface(ReferencePtr aRefPtr
) = 0;
113 virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr
,
114 FilterNode
* aSurface
) = 0;
115 virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr
) = 0;
118 * Get GradientStops compatible with the translation DrawTarget type.
119 * @param aRawStops array of raw gradient stops required
120 * @param aNumStops length of aRawStops
121 * @param aExtendMode extend mode required
122 * @return an already addrefed GradientStops for our DrawTarget type
124 virtual already_AddRefed
<GradientStops
> GetOrCreateGradientStops(
125 DrawTarget
* aDrawTarget
, GradientStop
* aRawStops
, uint32_t aNumStops
,
126 ExtendMode aExtendMode
) {
127 return aDrawTarget
->CreateGradientStops(aRawStops
, aNumStops
, aExtendMode
);
129 virtual void AddGradientStops(ReferencePtr aRefPtr
, GradientStops
* aPath
) = 0;
130 virtual void RemoveGradientStops(ReferencePtr aRefPtr
) = 0;
131 virtual void AddScaledFont(ReferencePtr aRefPtr
, ScaledFont
* aScaledFont
) = 0;
132 virtual void RemoveScaledFont(ReferencePtr aRefPtr
) = 0;
133 virtual void AddUnscaledFont(ReferencePtr aRefPtr
,
134 UnscaledFont
* aUnscaledFont
) = 0;
135 virtual void RemoveUnscaledFont(ReferencePtr aRefPtr
) = 0;
136 virtual void AddNativeFontResource(
137 uint64_t aKey
, NativeFontResource
* aNativeFontResource
) = 0;
139 virtual already_AddRefed
<DrawTarget
> CreateDrawTarget(ReferencePtr aRefPtr
,
140 const IntSize
& aSize
,
141 SurfaceFormat aFormat
);
142 virtual DrawTarget
* GetReferenceDrawTarget() = 0;
143 virtual Matrix
GetReferenceDrawTargetTransform() { return Matrix(); }
144 virtual void* GetFontContext() { return nullptr; }
146 void SetDependentSurfaces(
147 nsRefPtrHashtable
<nsUint64HashKey
, RecordedDependentSurface
>*
148 aDependentSurfaces
) {
149 mDependentSurfaces
= aDependentSurfaces
;
152 DrawTarget
* GetCurrentDrawTarget() const { return mCurrentDT
; }
154 nsRefPtrHashtable
<nsUint64HashKey
, RecordedDependentSurface
>*
155 mDependentSurfaces
= nullptr;
156 DrawTarget
* mCurrentDT
= nullptr;
159 struct ColorPatternStorage
{
163 struct LinearGradientPatternStorage
{
170 struct RadialGradientPatternStorage
{
179 struct ConicGradientPatternStorage
{
188 struct SurfacePatternStorage
{
190 SamplingFilter mSamplingFilter
;
191 ReferencePtr mSurface
;
193 IntRect mSamplingRect
;
196 struct PatternStorage
{
200 char mColor
[sizeof(ColorPatternStorage
)];
201 char mLinear
[sizeof(LinearGradientPatternStorage
)];
202 char mRadial
[sizeof(RadialGradientPatternStorage
)];
203 char mConic
[sizeof(ConicGradientPatternStorage
)];
204 char mSurface
[sizeof(SurfacePatternStorage
)];
208 /* SizeCollector and MemWriter are used
209 * in a pair to first collect the size of the
210 * event that we're going to write and then
211 * to write it without checking each individual
213 struct SizeCollector
{
214 SizeCollector() : mTotalSize(0) {}
215 void write(const char*, size_t s
) { mTotalSize
+= s
; }
220 constexpr explicit MemWriter(char* aPtr
) : mPtr(aPtr
) {}
221 void write(const char* aData
, size_t aSize
) {
222 memcpy(mPtr
, aData
, aSize
);
228 // An istream like class for reading from memory
230 constexpr MemReader(char* aData
, size_t aLen
)
231 : mData(aData
), mEnd(aData
+ aLen
) {}
232 void read(char* s
, std::streamsize n
) {
233 if (n
<= (mEnd
- mData
)) {
237 // We've requested more data than is available
238 // set the Reader into an eof state
242 bool eof() { return mData
> mEnd
; }
243 bool good() { return !eof(); }
244 void SetIsBad() { mData
= mEnd
+ 1; }
250 class ContiguousBuffer
{
252 ContiguousBuffer(char* aStart
, size_t aSize
)
253 : mWriter(aStart
), mEnd(aStart
+ aSize
) {}
255 constexpr MOZ_IMPLICIT
ContiguousBuffer(std::nullptr_t
) : mWriter(nullptr) {}
257 MemWriter
& Writer() { return mWriter
; }
259 size_t SizeRemaining() { return mWriter
.mPtr
? mEnd
- mWriter
.mPtr
: 0; }
261 bool IsValid() { return !!mWriter
.mPtr
; }
265 char* mEnd
= nullptr;
268 // Allows a derived class to provide guaranteed contiguous buffer.
269 class ContiguousBufferStream
{
272 * Templated RecordEvent function so that we can record into the buffer
273 * quickly using MemWriter.
275 * @param aRecordedEvent the event to record
278 void RecordEvent(const RE
* aRecordedEvent
) {
280 WriteElement(size
, aRecordedEvent
->GetType());
281 aRecordedEvent
->Record(size
);
282 auto& buffer
= GetContiguousBuffer(size
.mTotalSize
);
283 if (!buffer
.IsValid()) {
287 MOZ_ASSERT(size
.mTotalSize
<= buffer
.SizeRemaining());
289 WriteElement(buffer
.Writer(), aRecordedEvent
->GetType());
290 aRecordedEvent
->Record(buffer
.Writer());
291 IncrementEventCount();
296 * Provide a contiguous buffer with at least aSize remaining.
298 virtual ContiguousBuffer
& GetContiguousBuffer(size_t aSize
) = 0;
300 virtual void IncrementEventCount() = 0;
308 bool Resize(size_t aSize
) {
313 if (mLength
> mCapacity
) {
314 mCapacity
= mCapacity
* 2;
315 // check if the doubled capacity is enough
316 // otherwise use double mLength
317 if (mLength
> mCapacity
) {
318 mCapacity
= mLength
* 2;
320 char* data
= (char*)realloc(mData
, mCapacity
);
329 NS_ERROR("Failed to allocate MemStream!");
344 MemStream(const MemStream
&) = delete;
345 MemStream(MemStream
&&) = delete;
346 MemStream
& operator=(const MemStream
&) = delete;
347 MemStream
& operator=(MemStream
&&) = delete;
349 void write(const char* aData
, size_t aSize
) {
350 if (Resize(mLength
+ aSize
)) {
351 memcpy(mData
+ mLength
- aSize
, aData
, aSize
);
355 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {}
356 ~MemStream() { free(mData
); }
361 virtual void write(const char* aData
, size_t aSize
) = 0;
362 virtual void read(char* aOut
, size_t aSize
) = 0;
363 virtual bool good() = 0;
364 virtual void SetIsBad() = 0;
367 class RecordedEvent
{
369 enum EventType
: uint8_t {
372 DRAWTARGETDESTRUCTION
,
373 SETCURRENTDRAWTARGET
,
392 DRAWDEPENDENTSURFACE
,
393 DRAWSURFACEWITHSHADOW
,
397 SOURCESURFACECREATION
,
398 SOURCESURFACEDESTRUCTION
,
399 GRADIENTSTOPSCREATION
,
400 GRADIENTSTOPSDESTRUCTION
,
403 SCALEDFONTDESTRUCTION
,
406 FILTERNODEDESTRUCTION
,
408 FILTERNODESETATTRIBUTE
,
410 CREATESIMILARDRAWTARGET
,
411 CREATECLIPPEDDRAWTARGET
,
412 CREATEDRAWTARGETFORFILTER
,
418 UNSCALEDFONTCREATION
,
419 UNSCALEDFONTDESTRUCTION
,
422 EXTERNALSURFACECREATION
,
425 OPTIMIZESOURCESURFACE
,
431 virtual ~RecordedEvent() = default;
433 static std::string
GetEventName(EventType aType
);
436 * Play back this event using the translator. Note that derived classes
438 * only return false when there is a fatal error, as it will probably mean
440 * translation will abort.
441 * @param aTranslator Translator to be used for retrieving other referenced
442 * objects and making playback decisions.
443 * @return true unless a fatal problem has occurred and playback should
446 virtual bool PlayEvent(Translator
* aTranslator
) const { return true; }
448 virtual void RecordToStream(std::ostream
& aStream
) const = 0;
449 virtual void RecordToStream(EventStream
& aStream
) const = 0;
450 virtual void RecordToStream(ContiguousBufferStream
& aStream
) const = 0;
451 virtual void RecordToStream(MemStream
& aStream
) const = 0;
453 virtual void OutputSimpleEventInfo(std::stringstream
& aStringStream
) const {}
456 void RecordPatternData(S
& aStream
,
457 const PatternStorage
& aPatternStorage
) const;
459 void ReadPatternData(S
& aStream
, PatternStorage
& aPatternStorage
) const;
460 void StorePattern(PatternStorage
& aDestination
, const Pattern
& aSource
) const;
462 void RecordStrokeOptions(S
& aStream
,
463 const StrokeOptions
& aStrokeOptions
) const;
465 void ReadStrokeOptions(S
& aStream
, StrokeOptions
& aStrokeOptions
);
467 virtual std::string
GetName() const = 0;
469 virtual ReferencePtr
GetDestinedDT() { return nullptr; }
471 void OutputSimplePatternInfo(const PatternStorage
& aStorage
,
472 std::stringstream
& aOutput
) const;
475 static bool DoWithEvent(S
& aStream
, EventType aType
,
476 const std::function
<bool(RecordedEvent
*)>& aAction
);
477 static bool DoWithEventFromStream(
478 EventStream
& aStream
, EventType aType
,
479 const std::function
<bool(RecordedEvent
*)>& aAction
);
480 static bool DoWithEventFromReader(
481 MemReader
& aReader
, EventType aType
,
482 const std::function
<bool(RecordedEvent
*)>& aAction
);
484 EventType
GetType() const { return (EventType
)mType
; }
487 friend class DrawEventRecorderPrivate
;
488 friend class DrawEventRecorderMemory
;
489 static void RecordUnscaledFont(UnscaledFont
* aUnscaledFont
,
490 std::ostream
* aOutput
);
491 static void RecordUnscaledFont(UnscaledFont
* aUnscaledFont
,
494 static void RecordUnscaledFontImpl(UnscaledFont
* aUnscaledFont
, S
& aOutput
);
496 MOZ_IMPLICIT
RecordedEvent(EventType aType
) : mType(aType
) {}
499 std::vector
<Float
> mDashPatternStorage
;
502 template <class Derived
>
503 class RecordedEventDerived
: public RecordedEvent
{
504 using RecordedEvent::RecordedEvent
;
507 void RecordToStream(std::ostream
& aStream
) const override
{
508 WriteElement(aStream
, this->mType
);
509 static_cast<const Derived
*>(this)->Record(aStream
);
511 void RecordToStream(EventStream
& aStream
) const override
{
512 WriteElement(aStream
, this->mType
);
513 static_cast<const Derived
*>(this)->Record(aStream
);
515 void RecordToStream(ContiguousBufferStream
& aStream
) const final
{
516 aStream
.RecordEvent(static_cast<const Derived
*>(this));
518 void RecordToStream(MemStream
& aStream
) const override
{
520 WriteElement(size
, this->mType
);
521 static_cast<const Derived
*>(this)->Record(size
);
523 if (!aStream
.Resize(aStream
.mLength
+ size
.mTotalSize
)) {
527 MemWriter
writer(aStream
.mData
+ aStream
.mLength
- size
.mTotalSize
);
528 WriteElement(writer
, this->mType
);
529 static_cast<const Derived
*>(this)->Record(writer
);
534 } // namespace mozilla