Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / 2d / RecordedEvent.h
blob835460ff25014857cb463d7325e12423b3029628
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_
10 #include <ostream>
11 #include <sstream>
12 #include <cstring>
13 #include <functional>
14 #include <vector>
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"
22 namespace mozilla {
23 namespace gfx {
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;
36 struct ReferencePtr {
37 ReferencePtr() : mLongPtr(0) {}
39 MOZ_IMPLICIT ReferencePtr(const void* aLongPtr)
40 : mLongPtr(uint64_t(aLongPtr)) {}
42 template <typename T>
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);
48 return *this;
51 template <typename T>
52 ReferencePtr& operator=(const RefPtr<T>& aPtr) {
53 mLongPtr = uint64_t(aPtr.get());
54 return *this;
57 operator void*() const { return (void*)mLongPtr; }
59 uint64_t mLongPtr;
62 struct RecordedFontDetails {
63 uint64_t fontDataKey = 0;
64 uint32_t size = 0;
65 uint32_t index = 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)) {}
75 IntSize mSize;
76 mozilla::ipc::ByteBuf mRecording;
78 private:
79 ~RecordedDependentSurface() = default;
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();
89 class Translator {
90 public:
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) {
103 return nullptr;
105 virtual already_AddRefed<SourceSurface>
106 LookupSourceSurfaceFromSurfaceDescriptor(
107 const layers::SurfaceDescriptor& aDesc) {
108 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
109 return nullptr;
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;
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
130 virtual already_AddRefed<GradientStops> GetOrCreateGradientStops(
131 DrawTarget* aDrawTarget, GradientStop* aRawStops, uint32_t aNumStops,
132 ExtendMode aExtendMode) {
133 return aDrawTarget->CreateGradientStops(aRawStops, aNumStops, aExtendMode);
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;
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; }
152 void SetDependentSurfaces(
153 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
154 aDependentSurfaces) {
155 mDependentSurfaces = aDependentSurfaces;
158 DrawTarget* GetCurrentDrawTarget() const { return mCurrentDT; }
160 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
161 mDependentSurfaces = nullptr;
162 DrawTarget* mCurrentDT = nullptr;
165 struct ColorPatternStorage {
166 DeviceColor mColor;
169 struct LinearGradientPatternStorage {
170 Point mBegin;
171 Point mEnd;
172 ReferencePtr mStops;
173 Matrix mMatrix;
176 struct RadialGradientPatternStorage {
177 Point mCenter1;
178 Point mCenter2;
179 Float mRadius1;
180 Float mRadius2;
181 ReferencePtr mStops;
182 Matrix mMatrix;
185 struct ConicGradientPatternStorage {
186 Point mCenter;
187 Float mAngle;
188 Float mStartOffset;
189 Float mEndOffset;
190 ReferencePtr mStops;
191 Matrix mMatrix;
194 struct SurfacePatternStorage {
195 ExtendMode mExtend;
196 SamplingFilter mSamplingFilter;
197 ReferencePtr mSurface;
198 Matrix mMatrix;
199 IntRect mSamplingRect;
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)];
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;
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;
231 char* mPtr;
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();
248 bool eof() { return mData > mEnd; }
249 bool good() { return !eof(); }
250 void SetIsBad() { mData = mEnd + 1; }
252 char* mData;
253 char* mEnd;
256 class ContiguousBuffer {
257 public:
258 ContiguousBuffer(char* aStart, size_t aSize)
259 : mWriter(aStart), mEnd(aStart + aSize) {}
261 constexpr MOZ_IMPLICIT ContiguousBuffer(std::nullptr_t) : mWriter(nullptr) {}
263 MemWriter& Writer() { return mWriter; }
265 size_t SizeRemaining() { return mWriter.mPtr ? mEnd - mWriter.mPtr : 0; }
267 bool IsValid() { return !!mWriter.mPtr; }
269 private:
270 MemWriter mWriter;
271 char* mEnd = nullptr;
274 // Allows a derived class to provide guaranteed contiguous buffer.
275 class ContiguousBufferStream {
276 public:
278 * Templated RecordEvent function so that we can record into the buffer
279 * quickly using MemWriter.
281 * @param aRecordedEvent the event to record
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;
293 MOZ_ASSERT(size.mTotalSize <= buffer.SizeRemaining());
295 WriteElement(buffer.Writer(), aRecordedEvent->GetType());
296 aRecordedEvent->Record(buffer.Writer());
297 IncrementEventCount();
300 protected:
302 * Provide a contiguous buffer with at least aSize remaining.
304 virtual ContiguousBuffer& GetContiguousBuffer(size_t aSize) = 0;
306 virtual void IncrementEventCount() = 0;
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;
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;
326 char* data = (char*)realloc(mData, mCapacity);
327 if (!data) {
328 free(mData);
330 mData = data;
332 if (mData) {
333 return true;
335 NS_ERROR("Failed to allocate MemStream!");
336 mValid = false;
337 mLength = 0;
338 mCapacity = 0;
339 return false;
342 void reset() {
343 free(mData);
344 mData = nullptr;
345 mValid = true;
346 mLength = 0;
347 mCapacity = 0;
350 MemStream(const MemStream&) = delete;
351 MemStream(MemStream&&) = delete;
352 MemStream& operator=(const MemStream&) = delete;
353 MemStream& operator=(MemStream&&) = delete;
355 void write(const char* aData, size_t aSize) {
356 if (Resize(mLength + aSize)) {
357 memcpy(mData + mLength - aSize, aData, aSize);
361 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {}
362 ~MemStream() { free(mData); }
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;
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 FILL,
392 FILLCIRCLE,
393 FILLGLYPHS,
394 STROKEGLYPHS,
395 MASK,
396 STROKE,
397 DRAWSURFACE,
398 DRAWSURFACEDESCRIPTOR,
399 DRAWDEPENDENTSURFACE,
400 DRAWSURFACEWITHSHADOW,
401 DRAWSHADOW,
402 PATHCREATION,
403 PATHDESTRUCTION,
404 SOURCESURFACECREATION,
405 SOURCESURFACEDESTRUCTION,
406 GRADIENTSTOPSCREATION,
407 GRADIENTSTOPSDESTRUCTION,
408 SNAPSHOT,
409 SCALEDFONTCREATION,
410 SCALEDFONTDESTRUCTION,
411 MASKSURFACE,
412 FILTERNODECREATION,
413 FILTERNODEDESTRUCTION,
414 DRAWFILTER,
415 FILTERNODESETATTRIBUTE,
416 FILTERNODESETINPUT,
417 CREATESIMILARDRAWTARGET,
418 CREATECLIPPEDDRAWTARGET,
419 CREATEDRAWTARGETFORFILTER,
420 FONTDATA,
421 FONTDESC,
422 PUSHLAYER,
423 PUSHLAYERWITHBLEND,
424 POPLAYER,
425 UNSCALEDFONTCREATION,
426 UNSCALEDFONTDESTRUCTION,
427 INTOLUMINANCE,
428 EXTRACTSUBRECT,
429 EXTERNALSURFACECREATION,
430 FLUSH,
431 DETACHALLSNAPSHOTS,
432 OPTIMIZESOURCESURFACE,
433 LINK,
434 DESTINATION,
435 LAST,
438 virtual ~RecordedEvent() = default;
440 static std::string GetEventName(EventType aType);
443 * Play back this event using the translator. Note that derived classes
444 * should
445 * only return false when there is a fatal error, as it will probably mean
446 * the
447 * translation will abort.
448 * @param aTranslator Translator to be used for retrieving other referenced
449 * objects and making playback decisions.
450 * @return true unless a fatal problem has occurred and playback should
451 * abort.
453 virtual bool PlayEvent(Translator* aTranslator) const { return true; }
455 virtual void RecordToStream(std::ostream& aStream) const = 0;
456 virtual void RecordToStream(EventStream& aStream) const = 0;
457 virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0;
458 virtual void RecordToStream(MemStream& aStream) const = 0;
460 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
462 template <class S>
463 void RecordPatternData(S& aStream,
464 const PatternStorage& aPatternStorage) const;
465 template <class S>
466 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const;
467 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const;
468 template <class S>
469 void RecordStrokeOptions(S& aStream,
470 const StrokeOptions& aStrokeOptions) const;
471 template <class S>
472 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions);
474 virtual std::string GetName() const = 0;
476 virtual ReferencePtr GetDestinedDT() { return nullptr; }
478 void OutputSimplePatternInfo(const PatternStorage& aStorage,
479 std::stringstream& aOutput) const;
481 template <class S>
482 static bool DoWithEvent(S& aStream, EventType aType,
483 const std::function<bool(RecordedEvent*)>& aAction);
484 static bool DoWithEventFromStream(
485 EventStream& aStream, EventType aType,
486 const std::function<bool(RecordedEvent*)>& aAction);
487 static bool DoWithEventFromReader(
488 MemReader& aReader, EventType aType,
489 const std::function<bool(RecordedEvent*)>& aAction);
491 EventType GetType() const { return (EventType)mType; }
493 protected:
494 friend class DrawEventRecorderPrivate;
495 friend class DrawEventRecorderMemory;
496 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
497 std::ostream* aOutput);
498 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont,
499 MemStream& aOutput);
500 template <class S>
501 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput);
503 MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {}
505 EventType mType;
506 std::vector<Float> mDashPatternStorage;
509 template <class Derived>
510 class RecordedEventDerived : public RecordedEvent {
511 using RecordedEvent::RecordedEvent;
513 public:
514 void RecordToStream(std::ostream& aStream) const override {
515 WriteElement(aStream, this->mType);
516 static_cast<const Derived*>(this)->Record(aStream);
518 void RecordToStream(EventStream& aStream) const override {
519 WriteElement(aStream, this->mType);
520 static_cast<const Derived*>(this)->Record(aStream);
522 void RecordToStream(ContiguousBufferStream& aStream) const final {
523 aStream.RecordEvent(static_cast<const Derived*>(this));
525 void RecordToStream(MemStream& aStream) const override {
526 SizeCollector size;
527 WriteElement(size, this->mType);
528 static_cast<const Derived*>(this)->Record(size);
530 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) {
531 return;
534 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
535 WriteElement(writer, this->mType);
536 static_cast<const Derived*>(this)->Record(writer);
540 } // namespace gfx
541 } // namespace mozilla
543 #endif