diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/2d/RecordedEventImpl.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/2d/RecordedEventImpl.h')
-rw-r--r-- | gfx/2d/RecordedEventImpl.h | 4088 |
1 files changed, 4088 insertions, 0 deletions
diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h new file mode 100644 index 0000000000..7190299825 --- /dev/null +++ b/gfx/2d/RecordedEventImpl.h @@ -0,0 +1,4088 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_RECORDEDEVENTIMPL_H_ +#define MOZILLA_GFX_RECORDEDEVENTIMPL_H_ + +#include "RecordedEvent.h" + +#include "PathRecording.h" +#include "RecordingTypes.h" +#include "Tools.h" +#include "Filters.h" +#include "Logging.h" +#include "ScaledFontBase.h" +#include "SFNTData.h" + +namespace mozilla { +namespace gfx { + +template <class Derived> +class RecordedDrawingEvent : public RecordedEventDerived<Derived> { + public: + ReferencePtr GetDestinedDT() override { return mDT; } + + protected: + RecordedDrawingEvent(RecordedEvent::EventType aType, DrawTarget* aTarget) + : RecordedEventDerived<Derived>(aType), mDT(aTarget) {} + + template <class S> + RecordedDrawingEvent(RecordedEvent::EventType aType, S& aStream); + template <class S> + void Record(S& aStream) const; + + ReferencePtr mDT; +}; + +class RecordedDrawTargetCreation + : public RecordedEventDerived<RecordedDrawTargetCreation> { + public: + RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType, + const IntRect& aRect, SurfaceFormat aFormat, + bool aHasExistingData = false, + SourceSurface* aExistingData = nullptr) + : RecordedEventDerived(DRAWTARGETCREATION), + mRefPtr(aRefPtr), + mBackendType(aType), + mRect(aRect), + mFormat(aFormat), + mHasExistingData(aHasExistingData), + mExistingData(aExistingData) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawTarget Creation"; } + + ReferencePtr mRefPtr; + BackendType mBackendType; + IntRect mRect; + SurfaceFormat mFormat; + bool mHasExistingData; + RefPtr<SourceSurface> mExistingData; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawTargetCreation(S& aStream); +}; + +class RecordedDrawTargetDestruction + : public RecordedEventDerived<RecordedDrawTargetDestruction> { + public: + MOZ_IMPLICIT RecordedDrawTargetDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(DRAWTARGETDESTRUCTION), + mRefPtr(aRefPtr), + mBackendType(BackendType::NONE) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawTarget Destruction"; } + + ReferencePtr mRefPtr; + + BackendType mBackendType; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawTargetDestruction(S& aStream); +}; + +class RecordedCreateSimilarDrawTarget + : public RecordedEventDerived<RecordedCreateSimilarDrawTarget> { + public: + RecordedCreateSimilarDrawTarget(ReferencePtr aDT, ReferencePtr aRefPtr, + const IntSize& aSize, SurfaceFormat aFormat) + : RecordedEventDerived(CREATESIMILARDRAWTARGET), + mDT(aDT), + mRefPtr(aRefPtr), + mSize(aSize), + mFormat(aFormat) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "CreateSimilarDrawTarget"; } + + ReferencePtr mDT; + ReferencePtr mRefPtr; + IntSize mSize; + SurfaceFormat mFormat; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedCreateSimilarDrawTarget(S& aStream); +}; + +class RecordedCreateClippedDrawTarget + : public RecordedDrawingEvent<RecordedCreateClippedDrawTarget> { + public: + RecordedCreateClippedDrawTarget(DrawTarget* aDT, ReferencePtr aRefPtr, + const Rect& aBounds, SurfaceFormat aFormat) + : RecordedDrawingEvent(CREATECLIPPEDDRAWTARGET, aDT), + mRefPtr(aRefPtr), + mBounds(aBounds), + mFormat(aFormat) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "CreateClippedDrawTarget"; } + + ReferencePtr mRefPtr; + Rect mBounds; + SurfaceFormat mFormat; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedCreateClippedDrawTarget(S& aStream); +}; + +class RecordedCreateDrawTargetForFilter + : public RecordedDrawingEvent<RecordedCreateDrawTargetForFilter> { + public: + RecordedCreateDrawTargetForFilter(DrawTarget* aDT, ReferencePtr aRefPtr, + const IntSize& aMaxSize, + SurfaceFormat aFormat, FilterNode* aFilter, + FilterNode* aSource, + const Rect& aSourceRect, + const Point& aDestPoint) + : RecordedDrawingEvent(CREATEDRAWTARGETFORFILTER, aDT), + mRefPtr(aRefPtr), + mMaxSize(aMaxSize), + mFormat(aFormat), + mFilter(aFilter), + mSource(aSource), + mSourceRect(aSourceRect), + mDestPoint(aDestPoint) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { + return "CreateSimilarDrawTargetForFilter"; + } + + ReferencePtr mRefPtr; + IntSize mMaxSize; + SurfaceFormat mFormat; + ReferencePtr mFilter; + ReferencePtr mSource; + Rect mSourceRect; + Point mDestPoint; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedCreateDrawTargetForFilter(S& aStream); +}; + +class RecordedFillRect : public RecordedDrawingEvent<RecordedFillRect> { + public: + RecordedFillRect(DrawTarget* aDT, const Rect& aRect, const Pattern& aPattern, + const DrawOptions& aOptions) + : RecordedDrawingEvent(FILLRECT, aDT), + mRect(aRect), + mPattern(), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "FillRect"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedFillRect(S& aStream); + + Rect mRect; + PatternStorage mPattern; + DrawOptions mOptions; +}; + +class RecordedStrokeRect : public RecordedDrawingEvent<RecordedStrokeRect> { + public: + RecordedStrokeRect(DrawTarget* aDT, const Rect& aRect, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : RecordedDrawingEvent(STROKERECT, aDT), + mRect(aRect), + mPattern(), + mStrokeOptions(aStrokeOptions), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "StrokeRect"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedStrokeRect(S& aStream); + + Rect mRect; + PatternStorage mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class RecordedStrokeLine : public RecordedDrawingEvent<RecordedStrokeLine> { + public: + RecordedStrokeLine(DrawTarget* aDT, const Point& aBegin, const Point& aEnd, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : RecordedDrawingEvent(STROKELINE, aDT), + mBegin(aBegin), + mEnd(aEnd), + mPattern(), + mStrokeOptions(aStrokeOptions), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "StrokeLine"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedStrokeLine(S& aStream); + + Point mBegin; + Point mEnd; + PatternStorage mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class RecordedFill : public RecordedDrawingEvent<RecordedFill> { + public: + RecordedFill(DrawTarget* aDT, ReferencePtr aPath, const Pattern& aPattern, + const DrawOptions& aOptions) + : RecordedDrawingEvent(FILL, aDT), + mPath(aPath), + mPattern(), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Fill"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedFill(S& aStream); + + ReferencePtr mPath; + PatternStorage mPattern; + DrawOptions mOptions; +}; + +class RecordedFillGlyphs : public RecordedDrawingEvent<RecordedFillGlyphs> { + public: + RecordedFillGlyphs(DrawTarget* aDT, ReferencePtr aScaledFont, + const Pattern& aPattern, const DrawOptions& aOptions, + const Glyph* aGlyphs, uint32_t aNumGlyphs) + : RecordedDrawingEvent(FILLGLYPHS, aDT), + mScaledFont(aScaledFont), + mPattern(), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + mNumGlyphs = aNumGlyphs; + mGlyphs = new Glyph[aNumGlyphs]; + memcpy(mGlyphs, aGlyphs, sizeof(Glyph) * aNumGlyphs); + } + virtual ~RecordedFillGlyphs(); + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "FillGlyphs"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedFillGlyphs(S& aStream); + + ReferencePtr mScaledFont; + PatternStorage mPattern; + DrawOptions mOptions; + Glyph* mGlyphs = nullptr; + uint32_t mNumGlyphs = 0; +}; + +class RecordedMask : public RecordedDrawingEvent<RecordedMask> { + public: + RecordedMask(DrawTarget* aDT, const Pattern& aSource, const Pattern& aMask, + const DrawOptions& aOptions) + : RecordedDrawingEvent(MASK, aDT), + mSource(), + mMask(), + mOptions(aOptions) { + StorePattern(mSource, aSource); + StorePattern(mMask, aMask); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Mask"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedMask(S& aStream); + + PatternStorage mSource; + PatternStorage mMask; + DrawOptions mOptions; +}; + +class RecordedStroke : public RecordedDrawingEvent<RecordedStroke> { + public: + RecordedStroke(DrawTarget* aDT, ReferencePtr aPath, const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : RecordedDrawingEvent(STROKE, aDT), + mPath(aPath), + mPattern(), + mStrokeOptions(aStrokeOptions), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Stroke"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedStroke(S& aStream); + + ReferencePtr mPath; + PatternStorage mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class RecordedClearRect : public RecordedDrawingEvent<RecordedClearRect> { + public: + RecordedClearRect(DrawTarget* aDT, const Rect& aRect) + : RecordedDrawingEvent(CLEARRECT, aDT), mRect(aRect) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "ClearRect"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedClearRect(S& aStream); + + Rect mRect; +}; + +class RecordedCopySurface : public RecordedDrawingEvent<RecordedCopySurface> { + public: + RecordedCopySurface(DrawTarget* aDT, ReferencePtr aSourceSurface, + const IntRect& aSourceRect, const IntPoint& aDest) + : RecordedDrawingEvent(COPYSURFACE, aDT), + mSourceSurface(aSourceSurface), + mSourceRect(aSourceRect), + mDest(aDest) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "CopySurface"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedCopySurface(S& aStream); + + ReferencePtr mSourceSurface; + IntRect mSourceRect; + IntPoint mDest; +}; + +class RecordedPushClip : public RecordedDrawingEvent<RecordedPushClip> { + public: + RecordedPushClip(DrawTarget* aDT, ReferencePtr aPath) + : RecordedDrawingEvent(PUSHCLIP, aDT), mPath(aPath) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PushClip"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPushClip(S& aStream); + + ReferencePtr mPath; +}; + +class RecordedPushClipRect : public RecordedDrawingEvent<RecordedPushClipRect> { + public: + RecordedPushClipRect(DrawTarget* aDT, const Rect& aRect) + : RecordedDrawingEvent(PUSHCLIPRECT, aDT), mRect(aRect) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PushClipRect"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPushClipRect(S& aStream); + + Rect mRect; +}; + +class RecordedPopClip : public RecordedDrawingEvent<RecordedPopClip> { + public: + MOZ_IMPLICIT RecordedPopClip(DrawTarget* aDT) + : RecordedDrawingEvent(POPCLIP, aDT) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PopClip"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPopClip(S& aStream); +}; + +class RecordedPushLayer : public RecordedDrawingEvent<RecordedPushLayer> { + public: + RecordedPushLayer(DrawTarget* aDT, bool aOpaque, Float aOpacity, + SourceSurface* aMask, const Matrix& aMaskTransform, + const IntRect& aBounds, bool aCopyBackground) + : RecordedDrawingEvent(PUSHLAYER, aDT), + mOpaque(aOpaque), + mOpacity(aOpacity), + mMask(aMask), + mMaskTransform(aMaskTransform), + mBounds(aBounds), + mCopyBackground(aCopyBackground) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PushLayer"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPushLayer(S& aStream); + + bool mOpaque; + Float mOpacity; + ReferencePtr mMask; + Matrix mMaskTransform; + IntRect mBounds; + bool mCopyBackground; +}; + +class RecordedPushLayerWithBlend + : public RecordedDrawingEvent<RecordedPushLayerWithBlend> { + public: + RecordedPushLayerWithBlend(DrawTarget* aDT, bool aOpaque, Float aOpacity, + SourceSurface* aMask, const Matrix& aMaskTransform, + const IntRect& aBounds, bool aCopyBackground, + CompositionOp aCompositionOp) + : RecordedDrawingEvent(PUSHLAYERWITHBLEND, aDT), + mOpaque(aOpaque), + mOpacity(aOpacity), + mMask(aMask), + mMaskTransform(aMaskTransform), + mBounds(aBounds), + mCopyBackground(aCopyBackground), + mCompositionOp(aCompositionOp) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PushLayerWithBlend"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPushLayerWithBlend(S& aStream); + + bool mOpaque; + Float mOpacity; + ReferencePtr mMask; + Matrix mMaskTransform; + IntRect mBounds; + bool mCopyBackground; + CompositionOp mCompositionOp; +}; + +class RecordedPopLayer : public RecordedDrawingEvent<RecordedPopLayer> { + public: + MOZ_IMPLICIT RecordedPopLayer(DrawTarget* aDT) + : RecordedDrawingEvent(POPLAYER, aDT) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "PopLayer"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedPopLayer(S& aStream); +}; + +class RecordedSetTransform : public RecordedDrawingEvent<RecordedSetTransform> { + public: + RecordedSetTransform(DrawTarget* aDT, const Matrix& aTransform) + : RecordedDrawingEvent(SETTRANSFORM, aDT), mTransform(aTransform) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "SetTransform"; } + + Matrix mTransform; + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedSetTransform(S& aStream); +}; + +class RecordedDrawSurface : public RecordedDrawingEvent<RecordedDrawSurface> { + public: + RecordedDrawSurface(DrawTarget* aDT, ReferencePtr aRefSource, + const Rect& aDest, const Rect& aSource, + const DrawSurfaceOptions& aDSOptions, + const DrawOptions& aOptions) + : RecordedDrawingEvent(DRAWSURFACE, aDT), + mRefSource(aRefSource), + mDest(aDest), + mSource(aSource), + mDSOptions(aDSOptions), + mOptions(aOptions) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawSurface"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawSurface(S& aStream); + + ReferencePtr mRefSource; + Rect mDest; + Rect mSource; + DrawSurfaceOptions mDSOptions; + DrawOptions mOptions; +}; + +class RecordedDrawDependentSurface + : public RecordedDrawingEvent<RecordedDrawDependentSurface> { + public: + RecordedDrawDependentSurface(DrawTarget* aDT, uint64_t aId, const Rect& aDest) + : RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aDT), + mId(aId), + mDest(aDest) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawDependentSurface"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawDependentSurface(S& aStream); + + uint64_t mId; + Rect mDest; +}; + +class RecordedDrawSurfaceWithShadow + : public RecordedDrawingEvent<RecordedDrawSurfaceWithShadow> { + public: + RecordedDrawSurfaceWithShadow(DrawTarget* aDT, ReferencePtr aRefSource, + const Point& aDest, + const ShadowOptions& aShadow, CompositionOp aOp) + : RecordedDrawingEvent(DRAWSURFACEWITHSHADOW, aDT), + mRefSource(aRefSource), + mDest(aDest), + mShadow(aShadow), + mOp(aOp) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawSurfaceWithShadow"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawSurfaceWithShadow(S& aStream); + + ReferencePtr mRefSource; + Point mDest; + ShadowOptions mShadow; + CompositionOp mOp; +}; + +class RecordedDrawFilter : public RecordedDrawingEvent<RecordedDrawFilter> { + public: + RecordedDrawFilter(DrawTarget* aDT, ReferencePtr aNode, + const Rect& aSourceRect, const Point& aDestPoint, + const DrawOptions& aOptions) + : RecordedDrawingEvent(DRAWFILTER, aDT), + mNode(aNode), + mSourceRect(aSourceRect), + mDestPoint(aDestPoint), + mOptions(aOptions) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "DrawFilter"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDrawFilter(S& aStream); + + ReferencePtr mNode; + Rect mSourceRect; + Point mDestPoint; + DrawOptions mOptions; +}; + +class RecordedPathCreation : public RecordedEventDerived<RecordedPathCreation> { + public: + MOZ_IMPLICIT RecordedPathCreation(DrawTarget* aDT, PathRecording* aPath); + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Path Creation"; } + + private: + friend class RecordedEvent; + + ReferencePtr mDT; + ReferencePtr mRefPtr; + FillRule mFillRule; + RefPtr<PathRecording> mPath; + UniquePtr<PathOps> mPathOps; + + template <class S> + MOZ_IMPLICIT RecordedPathCreation(S& aStream); +}; + +class RecordedPathDestruction + : public RecordedEventDerived<RecordedPathDestruction> { + public: + MOZ_IMPLICIT RecordedPathDestruction(PathRecording* aPath) + : RecordedEventDerived(PATHDESTRUCTION), mRefPtr(aPath) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Path Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedPathDestruction(S& aStream); +}; + +class RecordedSourceSurfaceCreation + : public RecordedEventDerived<RecordedSourceSurfaceCreation> { + public: + RecordedSourceSurfaceCreation(ReferencePtr aRefPtr, uint8_t* aData, + int32_t aStride, const IntSize& aSize, + SurfaceFormat aFormat) + : RecordedEventDerived(SOURCESURFACECREATION), + mRefPtr(aRefPtr), + mData(aData), + mStride(aStride), + mSize(aSize), + mFormat(aFormat), + mDataOwned(false) {} + + ~RecordedSourceSurfaceCreation(); + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "SourceSurface Creation"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + uint8_t* mData = nullptr; + int32_t mStride; + IntSize mSize; + SurfaceFormat mFormat; + mutable bool mDataOwned; + + template <class S> + MOZ_IMPLICIT RecordedSourceSurfaceCreation(S& aStream); +}; + +class RecordedSourceSurfaceDestruction + : public RecordedEventDerived<RecordedSourceSurfaceDestruction> { + public: + MOZ_IMPLICIT RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(SOURCESURFACEDESTRUCTION), mRefPtr(aRefPtr) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "SourceSurface Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedSourceSurfaceDestruction(S& aStream); +}; + +class RecordedOptimizeSourceSurface + : public RecordedEventDerived<RecordedOptimizeSourceSurface> { + public: + RecordedOptimizeSourceSurface(ReferencePtr aSurface, ReferencePtr aDT, + ReferencePtr aOptimizedSurface) + : RecordedEventDerived(OPTIMIZESOURCESURFACE), + mSurface(aSurface), + mDT(aDT), + mOptimizedSurface(aOptimizedSurface) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "OptimizeSourceSurface"; } + + private: + friend class RecordedEvent; + + ReferencePtr mSurface; + ReferencePtr mDT; + ReferencePtr mOptimizedSurface; + + template <class S> + MOZ_IMPLICIT RecordedOptimizeSourceSurface(S& aStream); +}; + +class RecordedExternalSurfaceCreation + : public RecordedEventDerived<RecordedExternalSurfaceCreation> { + public: + RecordedExternalSurfaceCreation(ReferencePtr aRefPtr, const uint64_t aKey) + : RecordedEventDerived(EXTERNALSURFACECREATION), + mRefPtr(aRefPtr), + mKey(aKey) {} + + ~RecordedExternalSurfaceCreation() = default; + + virtual bool PlayEvent(Translator* aTranslator) const; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const; + + virtual std::string GetName() const { + return "SourceSurfaceSharedData Creation"; + } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + uint64_t mKey; + + template <class S> + MOZ_IMPLICIT RecordedExternalSurfaceCreation(S& aStream); +}; + +class RecordedFilterNodeCreation + : public RecordedEventDerived<RecordedFilterNodeCreation> { + public: + RecordedFilterNodeCreation(ReferencePtr aDT, ReferencePtr aRefPtr, + FilterType aType) + : RecordedEventDerived(FILTERNODECREATION), + mDT(aDT), + mRefPtr(aRefPtr), + mType(aType) {} + + ~RecordedFilterNodeCreation(); + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "FilterNode Creation"; } + + private: + friend class RecordedEvent; + + ReferencePtr mDT; + ReferencePtr mRefPtr; + FilterType mType; + + template <class S> + MOZ_IMPLICIT RecordedFilterNodeCreation(S& aStream); +}; + +class RecordedFilterNodeDestruction + : public RecordedEventDerived<RecordedFilterNodeDestruction> { + public: + MOZ_IMPLICIT RecordedFilterNodeDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(FILTERNODEDESTRUCTION), mRefPtr(aRefPtr) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "FilterNode Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedFilterNodeDestruction(S& aStream); +}; + +class RecordedGradientStopsCreation + : public RecordedEventDerived<RecordedGradientStopsCreation> { + public: + RecordedGradientStopsCreation(ReferencePtr aDT, ReferencePtr aRefPtr, + GradientStop* aStops, uint32_t aNumStops, + ExtendMode aExtendMode) + : RecordedEventDerived(GRADIENTSTOPSCREATION), + mDT(aDT), + mRefPtr(aRefPtr), + mStops(aStops), + mNumStops(aNumStops), + mExtendMode(aExtendMode), + mDataOwned(false) {} + + ~RecordedGradientStopsCreation(); + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "GradientStops Creation"; } + + private: + friend class RecordedEvent; + + ReferencePtr mDT; + ReferencePtr mRefPtr; + GradientStop* mStops = nullptr; + uint32_t mNumStops = 0; + ExtendMode mExtendMode; + bool mDataOwned; + + template <class S> + MOZ_IMPLICIT RecordedGradientStopsCreation(S& aStream); +}; + +class RecordedGradientStopsDestruction + : public RecordedEventDerived<RecordedGradientStopsDestruction> { + public: + MOZ_IMPLICIT RecordedGradientStopsDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(GRADIENTSTOPSDESTRUCTION), mRefPtr(aRefPtr) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "GradientStops Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedGradientStopsDestruction(S& aStream); +}; + +class RecordedFlush : public RecordedDrawingEvent<RecordedFlush> { + public: + explicit RecordedFlush(DrawTarget* aDT) : RecordedDrawingEvent(FLUSH, aDT) {} + + bool PlayEvent(Translator* aTranslator) const final; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + virtual std::string GetName() const override { return "Flush"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedFlush(S& aStream); +}; + +class RecordedDetachAllSnapshots + : public RecordedDrawingEvent<RecordedDetachAllSnapshots> { + public: + explicit RecordedDetachAllSnapshots(DrawTarget* aDT) + : RecordedDrawingEvent(DETACHALLSNAPSHOTS, aDT) {} + + bool PlayEvent(Translator* aTranslator) const final; + + template <class S> + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + virtual std::string GetName() const override { return "DetachAllSnapshots"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedDetachAllSnapshots(S& aStream); +}; + +class RecordedSnapshot : public RecordedEventDerived<RecordedSnapshot> { + public: + RecordedSnapshot(ReferencePtr aRefPtr, DrawTarget* aDT) + : RecordedEventDerived(SNAPSHOT), mRefPtr(aRefPtr), mDT(aDT) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Snapshot"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + ReferencePtr mDT; + + template <class S> + MOZ_IMPLICIT RecordedSnapshot(S& aStream); +}; + +class RecordedIntoLuminanceSource + : public RecordedEventDerived<RecordedIntoLuminanceSource> { + public: + RecordedIntoLuminanceSource(ReferencePtr aRefPtr, DrawTarget* aDT, + LuminanceType aLuminanceType, float aOpacity) + : RecordedEventDerived(INTOLUMINANCE), + mRefPtr(aRefPtr), + mDT(aDT), + mLuminanceType(aLuminanceType), + mOpacity(aOpacity) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "IntoLuminanceSource"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + ReferencePtr mDT; + LuminanceType mLuminanceType; + float mOpacity; + + template <class S> + MOZ_IMPLICIT RecordedIntoLuminanceSource(S& aStream); +}; + +class RecordedFontData : public RecordedEventDerived<RecordedFontData> { + public: + static void FontDataProc(const uint8_t* aData, uint32_t aSize, + uint32_t aIndex, void* aBaton) { + auto recordedFontData = static_cast<RecordedFontData*>(aBaton); + recordedFontData->SetFontData(aData, aSize, aIndex); + } + + explicit RecordedFontData(UnscaledFont* aUnscaledFont) + : RecordedEventDerived(FONTDATA), + mType(aUnscaledFont->GetType()), + mFontDetails() { + mGetFontFileDataSucceeded = + aUnscaledFont->GetFontFileData(&FontDataProc, this) && mData; + } + + virtual ~RecordedFontData(); + + bool IsValid() const { return mGetFontFileDataSucceeded; } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Font Data"; } + + void SetFontData(const uint8_t* aData, uint32_t aSize, uint32_t aIndex); + + bool GetFontDetails(RecordedFontDetails& fontDetails); + + private: + friend class RecordedEvent; + + FontType mType; + uint8_t* mData = nullptr; + RecordedFontDetails mFontDetails; + + bool mGetFontFileDataSucceeded; + + template <class S> + MOZ_IMPLICIT RecordedFontData(S& aStream); +}; + +class RecordedFontDescriptor + : public RecordedEventDerived<RecordedFontDescriptor> { + public: + static void FontDescCb(const uint8_t* aData, uint32_t aSize, uint32_t aIndex, + void* aBaton) { + auto recordedFontDesc = static_cast<RecordedFontDescriptor*>(aBaton); + recordedFontDesc->SetFontDescriptor(aData, aSize, aIndex); + } + + explicit RecordedFontDescriptor(UnscaledFont* aUnscaledFont) + : RecordedEventDerived(FONTDESC), + mType(aUnscaledFont->GetType()), + mIndex(0), + mRefPtr(aUnscaledFont) { + mHasDesc = aUnscaledFont->GetFontDescriptor(FontDescCb, this); + } + + virtual ~RecordedFontDescriptor(); + + bool IsValid() const { return mHasDesc; } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Font Desc"; } + + private: + friend class RecordedEvent; + + void SetFontDescriptor(const uint8_t* aData, uint32_t aSize, uint32_t aIndex); + + bool mHasDesc; + + FontType mType; + std::vector<uint8_t> mData; + uint32_t mIndex; + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedFontDescriptor(S& aStream); +}; + +class RecordedUnscaledFontCreation + : public RecordedEventDerived<RecordedUnscaledFontCreation> { + public: + static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, + void* aBaton) { + auto recordedUnscaledFontCreation = + static_cast<RecordedUnscaledFontCreation*>(aBaton); + recordedUnscaledFontCreation->SetFontInstanceData(aData, aSize); + } + + RecordedUnscaledFontCreation(UnscaledFont* aUnscaledFont, + RecordedFontDetails aFontDetails) + : RecordedEventDerived(UNSCALEDFONTCREATION), + mRefPtr(aUnscaledFont), + mFontDataKey(aFontDetails.fontDataKey), + mIndex(aFontDetails.index) { + aUnscaledFont->GetFontInstanceData(FontInstanceDataProc, this); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "UnscaledFont Creation"; } + + void SetFontInstanceData(const uint8_t* aData, uint32_t aSize); + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + uint64_t mFontDataKey; + uint32_t mIndex; + std::vector<uint8_t> mInstanceData; + + template <class S> + MOZ_IMPLICIT RecordedUnscaledFontCreation(S& aStream); +}; + +class RecordedUnscaledFontDestruction + : public RecordedEventDerived<RecordedUnscaledFontDestruction> { + public: + MOZ_IMPLICIT RecordedUnscaledFontDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(UNSCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {} + + bool PlayEvent(Translator* aTranslator) const override; + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "UnscaledFont Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedUnscaledFontDestruction(S& aStream); +}; + +class RecordedScaledFontCreation + : public RecordedEventDerived<RecordedScaledFontCreation> { + public: + static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, + const FontVariation* aVariations, + uint32_t aNumVariations, void* aBaton) { + auto recordedScaledFontCreation = + static_cast<RecordedScaledFontCreation*>(aBaton); + recordedScaledFontCreation->SetFontInstanceData(aData, aSize, aVariations, + aNumVariations); + } + + RecordedScaledFontCreation(ScaledFont* aScaledFont, + UnscaledFont* aUnscaledFont) + : RecordedEventDerived(SCALEDFONTCREATION), + mRefPtr(aScaledFont), + mUnscaledFont(aUnscaledFont), + mGlyphSize(aScaledFont->GetSize()) { + aScaledFont->GetFontInstanceData(FontInstanceDataProc, this); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "ScaledFont Creation"; } + + void SetFontInstanceData(const uint8_t* aData, uint32_t aSize, + const FontVariation* aVariations, + uint32_t aNumVariations); + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + ReferencePtr mUnscaledFont; + Float mGlyphSize; + std::vector<uint8_t> mInstanceData; + std::vector<FontVariation> mVariations; + + template <class S> + MOZ_IMPLICIT RecordedScaledFontCreation(S& aStream); +}; + +class RecordedScaledFontDestruction + : public RecordedEventDerived<RecordedScaledFontDestruction> { + public: + MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr) + : RecordedEventDerived(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {} + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "ScaledFont Destruction"; } + + private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + template <class S> + MOZ_IMPLICIT RecordedScaledFontDestruction(S& aStream); +}; + +class RecordedMaskSurface : public RecordedDrawingEvent<RecordedMaskSurface> { + public: + RecordedMaskSurface(DrawTarget* aDT, const Pattern& aPattern, + ReferencePtr aRefMask, const Point& aOffset, + const DrawOptions& aOptions) + : RecordedDrawingEvent(MASKSURFACE, aDT), + mPattern(), + mRefMask(aRefMask), + mOffset(aOffset), + mOptions(aOptions) { + StorePattern(mPattern, aPattern); + } + + bool PlayEvent(Translator* aTranslator) const override; + + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "MaskSurface"; } + + private: + friend class RecordedEvent; + + template <class S> + MOZ_IMPLICIT RecordedMaskSurface(S& aStream); + + PatternStorage mPattern; + ReferencePtr mRefMask; + Point mOffset; + DrawOptions mOptions; +}; + +class RecordedFilterNodeSetAttribute + : public RecordedEventDerived<RecordedFilterNodeSetAttribute> { + public: + enum ArgType { + ARGTYPE_UINT32, + ARGTYPE_BOOL, + ARGTYPE_FLOAT, + ARGTYPE_SIZE, + ARGTYPE_INTSIZE, + ARGTYPE_INTPOINT, + ARGTYPE_RECT, + ARGTYPE_INTRECT, + ARGTYPE_POINT, + ARGTYPE_MATRIX, + ARGTYPE_MATRIX5X4, + ARGTYPE_POINT3D, + ARGTYPE_COLOR, + ARGTYPE_FLOAT_ARRAY + }; + + template <typename T> + RecordedFilterNodeSetAttribute(FilterNode* aNode, uint32_t aIndex, + T aArgument, ArgType aArgType) + : RecordedEventDerived(FILTERNODESETATTRIBUTE), + mNode(aNode), + mIndex(aIndex), + mArgType(aArgType) { + mPayload.resize(sizeof(T)); + memcpy(&mPayload.front(), &aArgument, sizeof(T)); + } + + RecordedFilterNodeSetAttribute(FilterNode* aNode, uint32_t aIndex, + const Float* aFloat, uint32_t aSize) + : RecordedEventDerived(FILTERNODESETATTRIBUTE), + mNode(aNode), + mIndex(aIndex), + mArgType(ARGTYPE_FLOAT_ARRAY) { + mPayload.resize(sizeof(Float) * aSize); + memcpy(&mPayload.front(), aFloat, sizeof(Float) * aSize); + } + + bool PlayEvent(Translator* aTranslator) const override; + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "SetAttribute"; } + + private: + friend class RecordedEvent; + + ReferencePtr mNode; + + uint32_t mIndex; + ArgType mArgType; + std::vector<uint8_t> mPayload; + + template <class S> + MOZ_IMPLICIT RecordedFilterNodeSetAttribute(S& aStream); +}; + +class RecordedFilterNodeSetInput + : public RecordedEventDerived<RecordedFilterNodeSetInput> { + public: + RecordedFilterNodeSetInput(FilterNode* aNode, uint32_t aIndex, + FilterNode* aInputNode) + : RecordedEventDerived(FILTERNODESETINPUT), + mNode(aNode), + mIndex(aIndex), + mInputFilter(aInputNode), + mInputSurface(nullptr) {} + + RecordedFilterNodeSetInput(FilterNode* aNode, uint32_t aIndex, + SourceSurface* aInputSurface) + : RecordedEventDerived(FILTERNODESETINPUT), + mNode(aNode), + mIndex(aIndex), + mInputFilter(nullptr), + mInputSurface(aInputSurface) {} + + bool PlayEvent(Translator* aTranslator) const override; + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "SetInput"; } + + private: + friend class RecordedEvent; + + ReferencePtr mNode; + uint32_t mIndex; + ReferencePtr mInputFilter; + ReferencePtr mInputSurface; + + template <class S> + MOZ_IMPLICIT RecordedFilterNodeSetInput(S& aStream); +}; + +class RecordedLink : public RecordedDrawingEvent<RecordedLink> { + public: + RecordedLink(DrawTarget* aDT, const char* aDestination, const Rect& aRect) + : RecordedDrawingEvent(LINK, aDT), + mDestination(aDestination), + mRect(aRect) {} + + bool PlayEvent(Translator* aTranslator) const override; + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Link"; } + + private: + friend class RecordedEvent; + + std::string mDestination; + Rect mRect; + + template <class S> + MOZ_IMPLICIT RecordedLink(S& aStream); +}; + +class RecordedDestination : public RecordedDrawingEvent<RecordedDestination> { + public: + RecordedDestination(DrawTarget* aDT, const char* aDestination, + const Point& aPoint) + : RecordedDrawingEvent(DESTINATION, aDT), + mDestination(aDestination), + mPoint(aPoint) {} + + bool PlayEvent(Translator* aTranslator) const override; + template <class S> + void Record(S& aStream) const; + void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; + + std::string GetName() const override { return "Destination"; } + + private: + friend class RecordedEvent; + + std::string mDestination; + Point mPoint; + + template <class S> + MOZ_IMPLICIT RecordedDestination(S& aStream); +}; + +static std::string NameFromBackend(BackendType aType) { + switch (aType) { + case BackendType::NONE: + return "None"; + case BackendType::DIRECT2D: + return "Direct2D"; + default: + return "Unknown"; + } +} + +template <class S> +void RecordedEvent::RecordPatternData(S& aStream, + const PatternStorage& aPattern) const { + WriteElement(aStream, aPattern.mType); + + switch (aPattern.mType) { + case PatternType::COLOR: { + WriteElement(aStream, *reinterpret_cast<const ColorPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::LINEAR_GRADIENT: { + WriteElement(aStream, + *reinterpret_cast<const LinearGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::RADIAL_GRADIENT: { + WriteElement(aStream, + *reinterpret_cast<const RadialGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::CONIC_GRADIENT: { + WriteElement(aStream, + *reinterpret_cast<const ConicGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::SURFACE: { + WriteElement(aStream, *reinterpret_cast<const SurfacePatternStorage*>( + &aPattern.mStorage)); + return; + } + default: + return; + } +} + +template <class S> +void RecordedEvent::ReadPatternData(S& aStream, + PatternStorage& aPattern) const { + ReadElementConstrained(aStream, aPattern.mType, PatternType::COLOR, + kHighestPatternType); + + switch (aPattern.mType) { + case PatternType::COLOR: { + ReadElement(aStream, + *reinterpret_cast<ColorPatternStorage*>(&aPattern.mStorage)); + return; + } + case PatternType::LINEAR_GRADIENT: { + ReadElement(aStream, *reinterpret_cast<LinearGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::RADIAL_GRADIENT: { + ReadElement(aStream, *reinterpret_cast<RadialGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::CONIC_GRADIENT: { + ReadElement(aStream, *reinterpret_cast<ConicGradientPatternStorage*>( + &aPattern.mStorage)); + return; + } + case PatternType::SURFACE: { + SurfacePatternStorage* sps = + reinterpret_cast<SurfacePatternStorage*>(&aPattern.mStorage); + ReadElement(aStream, *sps); + if (sps->mExtend < ExtendMode::CLAMP || + sps->mExtend > ExtendMode::REFLECT) { + aStream.SetIsBad(); + return; + } + + if (sps->mSamplingFilter < SamplingFilter::GOOD || + sps->mSamplingFilter >= SamplingFilter::SENTINEL) { + aStream.SetIsBad(); + } + return; + } + default: + return; + } +} + +inline void RecordedEvent::StorePattern(PatternStorage& aDestination, + const Pattern& aSource) const { + aDestination.mType = aSource.GetType(); + + switch (aSource.GetType()) { + case PatternType::COLOR: { + reinterpret_cast<ColorPatternStorage*>(&aDestination.mStorage)->mColor = + static_cast<const ColorPattern*>(&aSource)->mColor; + return; + } + case PatternType::LINEAR_GRADIENT: { + LinearGradientPatternStorage* store = + reinterpret_cast<LinearGradientPatternStorage*>( + &aDestination.mStorage); + const LinearGradientPattern* pat = + static_cast<const LinearGradientPattern*>(&aSource); + store->mBegin = pat->mBegin; + store->mEnd = pat->mEnd; + store->mMatrix = pat->mMatrix; + store->mStops = pat->mStops.get(); + return; + } + case PatternType::RADIAL_GRADIENT: { + RadialGradientPatternStorage* store = + reinterpret_cast<RadialGradientPatternStorage*>( + &aDestination.mStorage); + const RadialGradientPattern* pat = + static_cast<const RadialGradientPattern*>(&aSource); + store->mCenter1 = pat->mCenter1; + store->mCenter2 = pat->mCenter2; + store->mRadius1 = pat->mRadius1; + store->mRadius2 = pat->mRadius2; + store->mMatrix = pat->mMatrix; + store->mStops = pat->mStops.get(); + return; + } + case PatternType::CONIC_GRADIENT: { + ConicGradientPatternStorage* store = + reinterpret_cast<ConicGradientPatternStorage*>( + &aDestination.mStorage); + const ConicGradientPattern* pat = + static_cast<const ConicGradientPattern*>(&aSource); + store->mCenter = pat->mCenter; + store->mAngle = pat->mAngle; + store->mStartOffset = pat->mStartOffset; + store->mEndOffset = pat->mEndOffset; + store->mMatrix = pat->mMatrix; + store->mStops = pat->mStops.get(); + return; + } + case PatternType::SURFACE: { + SurfacePatternStorage* store = + reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage); + const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aSource); + store->mExtend = pat->mExtendMode; + store->mSamplingFilter = pat->mSamplingFilter; + store->mMatrix = pat->mMatrix; + store->mSurface = pat->mSurface; + store->mSamplingRect = pat->mSamplingRect; + return; + } + } +} + +template <class S> +void RecordedEvent::RecordStrokeOptions( + S& aStream, const StrokeOptions& aStrokeOptions) const { + JoinStyle joinStyle = aStrokeOptions.mLineJoin; + CapStyle capStyle = aStrokeOptions.mLineCap; + + WriteElement(aStream, uint64_t(aStrokeOptions.mDashLength)); + WriteElement(aStream, aStrokeOptions.mDashOffset); + WriteElement(aStream, aStrokeOptions.mLineWidth); + WriteElement(aStream, aStrokeOptions.mMiterLimit); + WriteElement(aStream, joinStyle); + WriteElement(aStream, capStyle); + + if (!aStrokeOptions.mDashPattern) { + return; + } + + aStream.write((char*)aStrokeOptions.mDashPattern, + sizeof(Float) * aStrokeOptions.mDashLength); +} + +template <class S> +void RecordedEvent::ReadStrokeOptions(S& aStream, + StrokeOptions& aStrokeOptions) { + uint64_t dashLength; + JoinStyle joinStyle; + CapStyle capStyle; + + ReadElement(aStream, dashLength); + ReadElement(aStream, aStrokeOptions.mDashOffset); + ReadElement(aStream, aStrokeOptions.mLineWidth); + ReadElement(aStream, aStrokeOptions.mMiterLimit); + ReadElementConstrained(aStream, joinStyle, JoinStyle::BEVEL, + JoinStyle::MITER_OR_BEVEL); + ReadElementConstrained(aStream, capStyle, CapStyle::BUTT, CapStyle::SQUARE); + // On 32 bit we truncate the value of dashLength. + // See also bug 811850 for history. + aStrokeOptions.mDashLength = size_t(dashLength); + aStrokeOptions.mLineJoin = joinStyle; + aStrokeOptions.mLineCap = capStyle; + + if (!aStrokeOptions.mDashLength || !aStream.good()) { + return; + } + + mDashPatternStorage.resize(aStrokeOptions.mDashLength); + aStrokeOptions.mDashPattern = &mDashPatternStorage.front(); + aStream.read((char*)aStrokeOptions.mDashPattern, + sizeof(Float) * aStrokeOptions.mDashLength); +} + +template <class S> +static void ReadDrawOptions(S& aStream, DrawOptions& aDrawOptions) { + ReadElement(aStream, aDrawOptions); + if (aDrawOptions.mAntialiasMode < AntialiasMode::NONE || + aDrawOptions.mAntialiasMode > AntialiasMode::DEFAULT) { + aStream.SetIsBad(); + return; + } + + if (aDrawOptions.mCompositionOp < CompositionOp::OP_CLEAR || + aDrawOptions.mCompositionOp > CompositionOp::OP_COUNT) { + aStream.SetIsBad(); + } +} + +template <class S> +static void ReadDrawSurfaceOptions(S& aStream, + DrawSurfaceOptions& aDrawSurfaceOptions) { + ReadElement(aStream, aDrawSurfaceOptions); + if (aDrawSurfaceOptions.mSamplingFilter < SamplingFilter::GOOD || + aDrawSurfaceOptions.mSamplingFilter >= SamplingFilter::SENTINEL) { + aStream.SetIsBad(); + return; + } + + if (aDrawSurfaceOptions.mSamplingBounds < SamplingBounds::UNBOUNDED || + aDrawSurfaceOptions.mSamplingBounds > SamplingBounds::BOUNDED) { + aStream.SetIsBad(); + } +} + +inline void RecordedEvent::OutputSimplePatternInfo( + const PatternStorage& aStorage, std::stringstream& aOutput) const { + switch (aStorage.mType) { + case PatternType::COLOR: { + const DeviceColor color = + reinterpret_cast<const ColorPatternStorage*>(&aStorage.mStorage) + ->mColor; + aOutput << "DeviceColor: (" << color.r << ", " << color.g << ", " + << color.b << ", " << color.a << ")"; + return; + } + case PatternType::LINEAR_GRADIENT: { + const LinearGradientPatternStorage* store = + reinterpret_cast<const LinearGradientPatternStorage*>( + &aStorage.mStorage); + + aOutput << "LinearGradient (" << store->mBegin.x << ", " + << store->mBegin.y << ") - (" << store->mEnd.x << ", " + << store->mEnd.y << ") Stops: " << store->mStops; + return; + } + case PatternType::RADIAL_GRADIENT: { + const RadialGradientPatternStorage* store = + reinterpret_cast<const RadialGradientPatternStorage*>( + &aStorage.mStorage); + aOutput << "RadialGradient (Center 1: (" << store->mCenter1.x << ", " + << store->mCenter2.y << ") Radius 2: " << store->mRadius2; + return; + } + case PatternType::CONIC_GRADIENT: { + const ConicGradientPatternStorage* store = + reinterpret_cast<const ConicGradientPatternStorage*>( + &aStorage.mStorage); + aOutput << "ConicGradient (Center: (" << store->mCenter.x << ", " + << store->mCenter.y << ") Angle: " << store->mAngle + << " Range:" << store->mStartOffset << " - " << store->mEndOffset; + return; + } + case PatternType::SURFACE: { + const SurfacePatternStorage* store = + reinterpret_cast<const SurfacePatternStorage*>(&aStorage.mStorage); + aOutput << "Surface (0x" << store->mSurface << ")"; + return; + } + } +} + +template <class T> +template <class S> +RecordedDrawingEvent<T>::RecordedDrawingEvent(RecordedEvent::EventType aType, + S& aStream) + : RecordedEventDerived<T>(aType) { + ReadElement(aStream, mDT); +} + +template <class T> +template <class S> +void RecordedDrawingEvent<T>::Record(S& aStream) const { + WriteElement(aStream, mDT); +} + +inline bool RecordedDrawTargetCreation::PlayEvent( + Translator* aTranslator) const { + RefPtr<DrawTarget> newDT = + aTranslator->CreateDrawTarget(mRefPtr, mRect.Size(), mFormat); + + // If we couldn't create a DrawTarget this will probably cause us to crash + // with nullptr later in the playback, so return false to abort. + if (!newDT) { + return false; + } + + if (mHasExistingData) { + Rect dataRect(0, 0, mExistingData->GetSize().width, + mExistingData->GetSize().height); + newDT->DrawSurface(mExistingData, dataRect, dataRect); + } + + return true; +} + +template <class S> +void RecordedDrawTargetCreation::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mBackendType); + WriteElement(aStream, mRect); + WriteElement(aStream, mFormat); + WriteElement(aStream, mHasExistingData); + + if (mHasExistingData) { + MOZ_ASSERT(mExistingData); + MOZ_ASSERT(mExistingData->GetSize() == mRect.Size()); + RefPtr<DataSourceSurface> dataSurf = mExistingData->GetDataSurface(); + + DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ); + for (int y = 0; y < mRect.height; y++) { + aStream.write((const char*)map.GetData() + y * map.GetStride(), + BytesPerPixel(mFormat) * mRect.width); + } + } +} + +template <class S> +RecordedDrawTargetCreation::RecordedDrawTargetCreation(S& aStream) + : RecordedEventDerived(DRAWTARGETCREATION), mExistingData(nullptr) { + ReadElement(aStream, mRefPtr); + ReadElementConstrained(aStream, mBackendType, BackendType::NONE, + BackendType::WEBRENDER_TEXT); + ReadElement(aStream, mRect); + ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, + SurfaceFormat::UNKNOWN); + ReadElement(aStream, mHasExistingData); + + if (mHasExistingData) { + RefPtr<DataSourceSurface> dataSurf = + Factory::CreateDataSourceSurface(mRect.Size(), mFormat); + if (!dataSurf) { + gfxWarning() + << "RecordedDrawTargetCreation had to reset mHasExistingData"; + mHasExistingData = false; + return; + } + + DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ); + for (int y = 0; y < mRect.height; y++) { + aStream.read((char*)map.GetData() + y * map.GetStride(), + BytesPerPixel(mFormat) * mRect.width); + } + mExistingData = dataSurf; + } +} + +inline void RecordedDrawTargetCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] DrawTarget Creation (Type: " + << NameFromBackend(mBackendType) << ", Size: " << mRect.width + << "x" << mRect.height << ")"; +} + +inline bool RecordedDrawTargetDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveDrawTarget(mRefPtr); + return true; +} + +template <class S> +void RecordedDrawTargetDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedDrawTargetDestruction::RecordedDrawTargetDestruction(S& aStream) + : RecordedEventDerived(DRAWTARGETDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedDrawTargetDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] DrawTarget Destruction"; +} + +inline bool RecordedCreateSimilarDrawTarget::PlayEvent( + Translator* aTranslator) const { + DrawTarget* drawTarget = aTranslator->LookupDrawTarget(mDT); + if (!drawTarget) { + return false; + } + + RefPtr<DrawTarget> newDT = + drawTarget->CreateSimilarDrawTarget(mSize, mFormat); + + // If we couldn't create a DrawTarget this will probably cause us to crash + // with nullptr later in the playback, so return false to abort. + if (!newDT) { + return false; + } + + aTranslator->AddDrawTarget(mRefPtr, newDT); + return true; +} + +template <class S> +void RecordedCreateSimilarDrawTarget::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mSize); + WriteElement(aStream, mFormat); +} + +template <class S> +RecordedCreateSimilarDrawTarget::RecordedCreateSimilarDrawTarget(S& aStream) + : RecordedEventDerived(CREATESIMILARDRAWTARGET) { + ReadElement(aStream, mDT); + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mSize); + ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, + SurfaceFormat::UNKNOWN); +} + +inline void RecordedCreateSimilarDrawTarget::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] [" << mRefPtr + << "] CreateSimilarDrawTarget (Size: " << mSize.width << "x" + << mSize.height << ")"; +} + +inline bool RecordedCreateDrawTargetForFilter::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + IntRect baseRect = dt->GetRect(); + + auto maxRect = IntRect(IntPoint(0, 0), mMaxSize); + + auto clone = dt->GetTransform(); + bool invertible = clone.Invert(); + // mSourceRect is in filter space. The filter outputs from mSourceRect need + // to be drawn at mDestPoint in user space. + Rect userSpaceSource = Rect(mDestPoint, mSourceRect.Size()); + if (invertible) { + // Try to reduce the source rect so that it's not much bigger + // than the draw target. The result is not minimal. Examples + // are left as an exercise for the reader. + auto destRect = IntRectToRect(baseRect); + Rect userSpaceBounds = clone.TransformBounds(destRect); + userSpaceSource = userSpaceSource.Intersect(userSpaceBounds); + } + + // Compute how much we moved the top-left of the source rect by, and use that + // to compute the new dest point, and move our intersected source rect back + // into the (new) filter space. + Point shift = userSpaceSource.TopLeft() - mDestPoint; + Rect filterSpaceSource = + Rect(mSourceRect.TopLeft() + shift, userSpaceSource.Size()); + + baseRect = RoundedOut(filterSpaceSource); + FilterNode* filter = aTranslator->LookupFilterNode(mFilter); + if (!filter) { + return false; + } + + IntRect transformedRect = filter->MapRectToSource( + baseRect, maxRect, aTranslator->LookupFilterNode(mSource)); + + // Intersect with maxRect to make sure we didn't end up with something bigger + transformedRect = transformedRect.Intersect(maxRect); + + // If we end up with an empty rect make it 1x1 so that things don't break. + if (transformedRect.IsEmpty()) { + transformedRect = IntRect(0, 0, 1, 1); + } + + RefPtr<DrawTarget> newDT = + dt->CreateSimilarDrawTarget(transformedRect.Size(), mFormat); + newDT = + gfx::Factory::CreateOffsetDrawTarget(newDT, transformedRect.TopLeft()); + + // If we couldn't create a DrawTarget this will probably cause us to crash + // with nullptr later in the playback, so return false to abort. + if (!newDT) { + return false; + } + + aTranslator->AddDrawTarget(mRefPtr, newDT); + return true; +} + +inline bool RecordedCreateClippedDrawTarget::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + RefPtr<DrawTarget> newDT = dt->CreateClippedDrawTarget(mBounds, mFormat); + + // If we couldn't create a DrawTarget this will probably cause us to crash + // with nullptr later in the playback, so return false to abort. + if (!newDT) { + return false; + } + + aTranslator->AddDrawTarget(mRefPtr, newDT); + return true; +} + +template <class S> +void RecordedCreateClippedDrawTarget::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mBounds); + WriteElement(aStream, mFormat); +} + +template <class S> +RecordedCreateClippedDrawTarget::RecordedCreateClippedDrawTarget(S& aStream) + : RecordedDrawingEvent(CREATECLIPPEDDRAWTARGET, aStream) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mBounds); + ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, + SurfaceFormat::UNKNOWN); +} + +inline void RecordedCreateClippedDrawTarget::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] CreateClippedDrawTarget ()"; +} + +template <class S> +void RecordedCreateDrawTargetForFilter::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mMaxSize); + WriteElement(aStream, mFormat); + WriteElement(aStream, mFilter); + WriteElement(aStream, mSource); + WriteElement(aStream, mSourceRect); + WriteElement(aStream, mDestPoint); +} + +template <class S> +RecordedCreateDrawTargetForFilter::RecordedCreateDrawTargetForFilter(S& aStream) + : RecordedDrawingEvent(CREATEDRAWTARGETFORFILTER, aStream) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mMaxSize); + ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, + SurfaceFormat::UNKNOWN); + ReadElement(aStream, mFilter); + ReadElement(aStream, mSource); + ReadElement(aStream, mSourceRect); + ReadElement(aStream, mDestPoint); +} + +inline void RecordedCreateDrawTargetForFilter::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] CreateDrawTargetForFilter ()"; +} + +struct GenericPattern { + GenericPattern(const PatternStorage& aStorage, Translator* aTranslator) + : mPattern(nullptr), mTranslator(aTranslator) { + mStorage = const_cast<PatternStorage*>(&aStorage); + } + + ~GenericPattern() { + if (mPattern) { + mPattern->~Pattern(); + } + } + + operator Pattern*() { + switch (mStorage->mType) { + case PatternType::COLOR: + return new (mColPat) ColorPattern( + reinterpret_cast<ColorPatternStorage*>(&mStorage->mStorage) + ->mColor); + case PatternType::SURFACE: { + SurfacePatternStorage* storage = + reinterpret_cast<SurfacePatternStorage*>(&mStorage->mStorage); + mPattern = new (mSurfPat) + SurfacePattern(mTranslator->LookupSourceSurface(storage->mSurface), + storage->mExtend, storage->mMatrix, + storage->mSamplingFilter, storage->mSamplingRect); + return mPattern; + } + case PatternType::LINEAR_GRADIENT: { + LinearGradientPatternStorage* storage = + reinterpret_cast<LinearGradientPatternStorage*>( + &mStorage->mStorage); + mPattern = new (mLinGradPat) LinearGradientPattern( + storage->mBegin, storage->mEnd, + storage->mStops ? mTranslator->LookupGradientStops(storage->mStops) + : nullptr, + storage->mMatrix); + return mPattern; + } + case PatternType::RADIAL_GRADIENT: { + RadialGradientPatternStorage* storage = + reinterpret_cast<RadialGradientPatternStorage*>( + &mStorage->mStorage); + mPattern = new (mRadGradPat) RadialGradientPattern( + storage->mCenter1, storage->mCenter2, storage->mRadius1, + storage->mRadius2, + storage->mStops ? mTranslator->LookupGradientStops(storage->mStops) + : nullptr, + storage->mMatrix); + return mPattern; + } + case PatternType::CONIC_GRADIENT: { + ConicGradientPatternStorage* storage = + reinterpret_cast<ConicGradientPatternStorage*>(&mStorage->mStorage); + mPattern = new (mConGradPat) ConicGradientPattern( + storage->mCenter, storage->mAngle, storage->mStartOffset, + storage->mEndOffset, + storage->mStops ? mTranslator->LookupGradientStops(storage->mStops) + : nullptr, + storage->mMatrix); + return mPattern; + } + default: + return new (mColPat) ColorPattern(DeviceColor()); + } + + return mPattern; + } + + union { + char mColPat[sizeof(ColorPattern)]; + char mLinGradPat[sizeof(LinearGradientPattern)]; + char mRadGradPat[sizeof(RadialGradientPattern)]; + char mConGradPat[sizeof(ConicGradientPattern)]; + char mSurfPat[sizeof(SurfacePattern)]; + }; + + PatternStorage* mStorage; + Pattern* mPattern; + Translator* mTranslator; +}; + +inline bool RecordedFillRect::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->FillRect(mRect, *GenericPattern(mPattern, aTranslator), mOptions); + return true; +} + +template <class S> +void RecordedFillRect::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRect); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); +} + +template <class S> +RecordedFillRect::RecordedFillRect(S& aStream) + : RecordedDrawingEvent(FILLRECT, aStream) { + ReadElement(aStream, mRect); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); +} + +inline void RecordedFillRect::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] FillRect (" << mRect.X() << ", " + << mRect.Y() << " - " << mRect.Width() << " x " + << mRect.Height() << ") "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline bool RecordedStrokeRect::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->StrokeRect(mRect, *GenericPattern(mPattern, aTranslator), mStrokeOptions, + mOptions); + return true; +} + +template <class S> +void RecordedStrokeRect::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRect); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); + RecordStrokeOptions(aStream, mStrokeOptions); +} + +template <class S> +RecordedStrokeRect::RecordedStrokeRect(S& aStream) + : RecordedDrawingEvent(STROKERECT, aStream) { + ReadElement(aStream, mRect); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); + ReadStrokeOptions(aStream, mStrokeOptions); +} + +inline void RecordedStrokeRect::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] StrokeRect (" << mRect.X() << ", " + << mRect.Y() << " - " << mRect.Width() << " x " + << mRect.Height() + << ") LineWidth: " << mStrokeOptions.mLineWidth << "px "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline bool RecordedStrokeLine::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->StrokeLine(mBegin, mEnd, *GenericPattern(mPattern, aTranslator), + mStrokeOptions, mOptions); + return true; +} + +template <class S> +void RecordedStrokeLine::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mBegin); + WriteElement(aStream, mEnd); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); + RecordStrokeOptions(aStream, mStrokeOptions); +} + +template <class S> +RecordedStrokeLine::RecordedStrokeLine(S& aStream) + : RecordedDrawingEvent(STROKELINE, aStream) { + ReadElement(aStream, mBegin); + ReadElement(aStream, mEnd); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); + ReadStrokeOptions(aStream, mStrokeOptions); +} + +inline void RecordedStrokeLine::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] StrokeLine (" << mBegin.x << ", " + << mBegin.y << " - " << mEnd.x << ", " << mEnd.y + << ") LineWidth: " << mStrokeOptions.mLineWidth << "px "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline bool RecordedFill::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->Fill(aTranslator->LookupPath(mPath), + *GenericPattern(mPattern, aTranslator), mOptions); + return true; +} + +template <class S> +RecordedFill::RecordedFill(S& aStream) : RecordedDrawingEvent(FILL, aStream) { + ReadElement(aStream, mPath); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); +} + +template <class S> +void RecordedFill::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mPath); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); +} + +inline void RecordedFill::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] Fill (" << mPath << ") "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline RecordedFillGlyphs::~RecordedFillGlyphs() { delete[] mGlyphs; } + +inline bool RecordedFillGlyphs::PlayEvent(Translator* aTranslator) const { + if (mNumGlyphs > 0 && !mGlyphs) { + // Glyph allocation failed + return false; + } + + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + ScaledFont* scaledFont = aTranslator->LookupScaledFont(mScaledFont); + if (!scaledFont) { + return false; + } + + GlyphBuffer buffer; + buffer.mGlyphs = mGlyphs; + buffer.mNumGlyphs = mNumGlyphs; + dt->FillGlyphs(scaledFont, buffer, *GenericPattern(mPattern, aTranslator), + mOptions); + return true; +} + +template <class S> +RecordedFillGlyphs::RecordedFillGlyphs(S& aStream) + : RecordedDrawingEvent(FILLGLYPHS, aStream) { + ReadElement(aStream, mScaledFont); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); + ReadElement(aStream, mNumGlyphs); + if (!aStream.good() || mNumGlyphs <= 0) { + return; + } + + mGlyphs = new (fallible) Glyph[mNumGlyphs]; + if (!mGlyphs) { + gfxCriticalNote << "RecordedFillGlyphs failed to allocate glyphs of size " + << mNumGlyphs; + aStream.SetIsBad(); + } else { + aStream.read((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs); + } +} + +template <class S> +void RecordedFillGlyphs::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mScaledFont); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); + WriteElement(aStream, mNumGlyphs); + aStream.write((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs); +} + +inline void RecordedFillGlyphs::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] FillGlyphs (" << mScaledFont << ") "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline bool RecordedMask::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->Mask(*GenericPattern(mSource, aTranslator), + *GenericPattern(mMask, aTranslator), mOptions); + return true; +} + +template <class S> +RecordedMask::RecordedMask(S& aStream) : RecordedDrawingEvent(MASK, aStream) { + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mSource); + ReadPatternData(aStream, mMask); +} + +template <class S> +void RecordedMask::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mSource); + RecordPatternData(aStream, mMask); +} + +inline void RecordedMask::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] Mask (Source: "; + OutputSimplePatternInfo(mSource, aStringStream); + aStringStream << " Mask: "; + OutputSimplePatternInfo(mMask, aStringStream); +} + +inline bool RecordedStroke::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + Path* path = aTranslator->LookupPath(mPath); + if (!path) { + return false; + } + + dt->Stroke(path, *GenericPattern(mPattern, aTranslator), mStrokeOptions, + mOptions); + return true; +} + +template <class S> +void RecordedStroke::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mPath); + WriteElement(aStream, mOptions); + RecordPatternData(aStream, mPattern); + RecordStrokeOptions(aStream, mStrokeOptions); +} + +template <class S> +RecordedStroke::RecordedStroke(S& aStream) + : RecordedDrawingEvent(STROKE, aStream) { + ReadElement(aStream, mPath); + ReadDrawOptions(aStream, mOptions); + ReadPatternData(aStream, mPattern); + ReadStrokeOptions(aStream, mStrokeOptions); +} + +inline void RecordedStroke::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] Stroke (" << mPath + << ") LineWidth: " << mStrokeOptions.mLineWidth << "px "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +inline bool RecordedClearRect::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->ClearRect(mRect); + return true; +} + +template <class S> +void RecordedClearRect::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRect); +} + +template <class S> +RecordedClearRect::RecordedClearRect(S& aStream) + : RecordedDrawingEvent(CLEARRECT, aStream) { + ReadElement(aStream, mRect); +} + +inline void RecordedClearRect::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] ClearRect (" << mRect.X() << ", " + << mRect.Y() << " - " << mRect.Width() << " x " + << mRect.Height() << ") "; +} + +inline bool RecordedCopySurface::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* surface = aTranslator->LookupSourceSurface(mSourceSurface); + if (!surface) { + return false; + } + + dt->CopySurface(surface, mSourceRect, mDest); + return true; +} + +template <class S> +void RecordedCopySurface::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mSourceSurface); + WriteElement(aStream, mSourceRect); + WriteElement(aStream, mDest); +} + +template <class S> +RecordedCopySurface::RecordedCopySurface(S& aStream) + : RecordedDrawingEvent(COPYSURFACE, aStream) { + ReadElement(aStream, mSourceSurface); + ReadElement(aStream, mSourceRect); + ReadElement(aStream, mDest); +} + +inline void RecordedCopySurface::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] CopySurface (" << mSourceSurface << ")"; +} + +inline bool RecordedPushClip::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + Path* path = aTranslator->LookupPath(mPath); + if (!path) { + return false; + } + + dt->PushClip(path); + return true; +} + +template <class S> +void RecordedPushClip::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mPath); +} + +template <class S> +RecordedPushClip::RecordedPushClip(S& aStream) + : RecordedDrawingEvent(PUSHCLIP, aStream) { + ReadElement(aStream, mPath); +} + +inline void RecordedPushClip::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PushClip (" << mPath << ") "; +} + +inline bool RecordedPushClipRect::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->PushClipRect(mRect); + return true; +} + +template <class S> +void RecordedPushClipRect::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRect); +} + +template <class S> +RecordedPushClipRect::RecordedPushClipRect(S& aStream) + : RecordedDrawingEvent(PUSHCLIPRECT, aStream) { + ReadElement(aStream, mRect); +} + +inline void RecordedPushClipRect::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PushClipRect (" << mRect.X() << ", " + << mRect.Y() << " - " << mRect.Width() << " x " + << mRect.Height() << ") "; +} + +inline bool RecordedPopClip::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->PopClip(); + return true; +} + +template <class S> +void RecordedPopClip::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template <class S> +RecordedPopClip::RecordedPopClip(S& aStream) + : RecordedDrawingEvent(POPCLIP, aStream) {} + +inline void RecordedPopClip::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PopClip"; +} + +inline bool RecordedPushLayer::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* mask = + mMask ? aTranslator->LookupSourceSurface(mMask) : nullptr; + dt->PushLayer(mOpaque, mOpacity, mask, mMaskTransform, mBounds, + mCopyBackground); + return true; +} + +template <class S> +void RecordedPushLayer::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mOpaque); + WriteElement(aStream, mOpacity); + WriteElement(aStream, mMask); + WriteElement(aStream, mMaskTransform); + WriteElement(aStream, mBounds); + WriteElement(aStream, mCopyBackground); +} + +template <class S> +RecordedPushLayer::RecordedPushLayer(S& aStream) + : RecordedDrawingEvent(PUSHLAYER, aStream) { + ReadElement(aStream, mOpaque); + ReadElement(aStream, mOpacity); + ReadElement(aStream, mMask); + ReadElement(aStream, mMaskTransform); + ReadElement(aStream, mBounds); + ReadElement(aStream, mCopyBackground); +} + +inline void RecordedPushLayer::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PushPLayer (Opaque=" << mOpaque + << ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") "; +} + +inline bool RecordedPushLayerWithBlend::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* mask = + mMask ? aTranslator->LookupSourceSurface(mMask) : nullptr; + dt->PushLayerWithBlend(mOpaque, mOpacity, mask, mMaskTransform, mBounds, + mCopyBackground, mCompositionOp); + return true; +} + +template <class S> +void RecordedPushLayerWithBlend::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mOpaque); + WriteElement(aStream, mOpacity); + WriteElement(aStream, mMask); + WriteElement(aStream, mMaskTransform); + WriteElement(aStream, mBounds); + WriteElement(aStream, mCopyBackground); + WriteElement(aStream, mCompositionOp); +} + +template <class S> +RecordedPushLayerWithBlend::RecordedPushLayerWithBlend(S& aStream) + : RecordedDrawingEvent(PUSHLAYERWITHBLEND, aStream) { + ReadElement(aStream, mOpaque); + ReadElement(aStream, mOpacity); + ReadElement(aStream, mMask); + ReadElement(aStream, mMaskTransform); + ReadElement(aStream, mBounds); + ReadElement(aStream, mCopyBackground); + ReadElementConstrained(aStream, mCompositionOp, CompositionOp::OP_OVER, + CompositionOp::OP_COUNT); +} + +inline void RecordedPushLayerWithBlend::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PushLayerWithBlend (Opaque=" << mOpaque + << ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") "; +} + +inline bool RecordedPopLayer::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->PopLayer(); + return true; +} + +template <class S> +void RecordedPopLayer::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template <class S> +RecordedPopLayer::RecordedPopLayer(S& aStream) + : RecordedDrawingEvent(POPLAYER, aStream) {} + +inline void RecordedPopLayer::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] PopLayer"; +} + +inline bool RecordedSetTransform::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + // If we're drawing to the reference DT, then we need to manually apply + // its initial transform, otherwise we'll just clobber it with only the + // the transform that was visible to the code doing the recording. + if (dt == aTranslator->GetReferenceDrawTarget()) { + dt->SetTransform(mTransform * + aTranslator->GetReferenceDrawTargetTransform()); + } else { + dt->SetTransform(mTransform); + } + + return true; +} + +template <class S> +void RecordedSetTransform::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mTransform); +} + +template <class S> +RecordedSetTransform::RecordedSetTransform(S& aStream) + : RecordedDrawingEvent(SETTRANSFORM, aStream) { + ReadElement(aStream, mTransform); +} + +inline void RecordedSetTransform::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] SetTransform [ " << mTransform._11 << " " + << mTransform._12 << " ; " << mTransform._21 << " " + << mTransform._22 << " ; " << mTransform._31 << " " + << mTransform._32 << " ]"; +} + +inline bool RecordedDrawSurface::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* surface = aTranslator->LookupSourceSurface(mRefSource); + if (!surface) { + return false; + } + + dt->DrawSurface(surface, mDest, mSource, mDSOptions, mOptions); + return true; +} + +template <class S> +void RecordedDrawSurface::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRefSource); + WriteElement(aStream, mDest); + WriteElement(aStream, mSource); + WriteElement(aStream, mDSOptions); + WriteElement(aStream, mOptions); +} + +template <class S> +RecordedDrawSurface::RecordedDrawSurface(S& aStream) + : RecordedDrawingEvent(DRAWSURFACE, aStream) { + ReadElement(aStream, mRefSource); + ReadElement(aStream, mDest); + ReadElement(aStream, mSource); + ReadDrawSurfaceOptions(aStream, mDSOptions); + ReadDrawOptions(aStream, mOptions); +} + +inline void RecordedDrawSurface::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DrawSurface (" << mRefSource << ")"; +} + +inline bool RecordedDrawDependentSurface::PlayEvent( + Translator* aTranslator) const { + aTranslator->DrawDependentSurface(mDT, mId, mDest); + return true; +} + +template <class S> +void RecordedDrawDependentSurface::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mId); + WriteElement(aStream, mDest); +} + +template <class S> +RecordedDrawDependentSurface::RecordedDrawDependentSurface(S& aStream) + : RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aStream) { + ReadElement(aStream, mId); + ReadElement(aStream, mDest); +} + +inline void RecordedDrawDependentSurface::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DrawDependentSurface (" << mId << ")"; +} + +inline bool RecordedDrawFilter::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + FilterNode* filter = aTranslator->LookupFilterNode(mNode); + if (!filter) { + return false; + } + + dt->DrawFilter(filter, mSourceRect, mDestPoint, mOptions); + return true; +} + +template <class S> +void RecordedDrawFilter::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mNode); + WriteElement(aStream, mSourceRect); + WriteElement(aStream, mDestPoint); + WriteElement(aStream, mOptions); +} + +template <class S> +RecordedDrawFilter::RecordedDrawFilter(S& aStream) + : RecordedDrawingEvent(DRAWFILTER, aStream) { + ReadElement(aStream, mNode); + ReadElement(aStream, mSourceRect); + ReadElement(aStream, mDestPoint); + ReadDrawOptions(aStream, mOptions); +} + +inline void RecordedDrawFilter::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DrawFilter (" << mNode << ")"; +} + +inline bool RecordedDrawSurfaceWithShadow::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* surface = aTranslator->LookupSourceSurface(mRefSource); + if (!surface) { + return false; + } + + dt->DrawSurfaceWithShadow(surface, mDest, mShadow, mOp); + return true; +} + +template <class S> +void RecordedDrawSurfaceWithShadow::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRefSource); + WriteElement(aStream, mDest); + WriteElement(aStream, mShadow); + WriteElement(aStream, mOp); +} + +template <class S> +RecordedDrawSurfaceWithShadow::RecordedDrawSurfaceWithShadow(S& aStream) + : RecordedDrawingEvent(DRAWSURFACEWITHSHADOW, aStream) { + ReadElement(aStream, mRefSource); + ReadElement(aStream, mDest); + ReadElement(aStream, mShadow); + ReadElementConstrained(aStream, mOp, CompositionOp::OP_OVER, + CompositionOp::OP_COUNT); +} + +inline void RecordedDrawSurfaceWithShadow::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DrawSurfaceWithShadow (" << mRefSource + << ") DeviceColor: (" << mShadow.mColor.r << ", " + << mShadow.mColor.g << ", " << mShadow.mColor.b << ", " + << mShadow.mColor.a << ")"; +} + +inline RecordedPathCreation::RecordedPathCreation(DrawTarget* aDT, + PathRecording* aPath) + : RecordedEventDerived(PATHCREATION), + mDT(aDT), + mRefPtr(aPath), + mFillRule(aPath->mFillRule), + mPath(aPath) {} + +inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const { + DrawTarget* drawTarget = aTranslator->LookupDrawTarget(mDT); + if (!drawTarget) { + return false; + } + + RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(mFillRule); + if (!mPathOps->CheckedStreamToSink(*builder)) { + return false; + } + + RefPtr<Path> path = builder->Finish(); + aTranslator->AddPath(mRefPtr, path); + return true; +} + +template <class S> +void RecordedPathCreation::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mFillRule); + mPath->mPathOps.Record(aStream); +} + +template <class S> +RecordedPathCreation::RecordedPathCreation(S& aStream) + : RecordedEventDerived(PATHCREATION) { + ReadElement(aStream, mDT); + ReadElement(aStream, mRefPtr); + ReadElementConstrained(aStream, mFillRule, FillRule::FILL_WINDING, + FillRule::FILL_EVEN_ODD); + mPathOps = MakeUnique<PathOps>(aStream); +} + +inline void RecordedPathCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + size_t numberOfOps = + mPath ? mPath->mPathOps.NumberOfOps() : mPathOps->NumberOfOps(); + aStringStream << "[" << mDT << "] [" << mRefPtr + << "] Path created (OpCount: " << numberOfOps << ")"; +} +inline bool RecordedPathDestruction::PlayEvent(Translator* aTranslator) const { + aTranslator->RemovePath(mRefPtr); + return true; +} + +template <class S> +void RecordedPathDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedPathDestruction::RecordedPathDestruction(S& aStream) + : RecordedEventDerived(PATHDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedPathDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] Path Destroyed"; +} + +inline RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation() { + if (mDataOwned) { + delete[] mData; + } +} + +inline bool RecordedSourceSurfaceCreation::PlayEvent( + Translator* aTranslator) const { + if (!mData) { + return false; + } + + RefPtr<SourceSurface> src = Factory::CreateWrappingDataSourceSurface( + mData, mSize.width * BytesPerPixel(mFormat), mSize, mFormat, + [](void* aClosure) { delete[] static_cast<uint8_t*>(aClosure); }, mData); + if (src) { + mDataOwned = false; + } + + aTranslator->AddSourceSurface(mRefPtr, src); + return true; +} + +template <class S> +void RecordedSourceSurfaceCreation::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mSize); + WriteElement(aStream, mFormat); + MOZ_ASSERT(mData); + size_t dataFormatWidth = BytesPerPixel(mFormat) * mSize.width; + const char* endSrc = (const char*)(mData + (mSize.height * mStride)); + for (const char* src = (const char*)mData; src < endSrc; src += mStride) { + aStream.write(src, dataFormatWidth); + } +} + +template <class S> +RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(S& aStream) + : RecordedEventDerived(SOURCESURFACECREATION), mDataOwned(true) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mSize); + ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, + SurfaceFormat::UNKNOWN); + + if (!Factory::AllowedSurfaceSize(mSize)) { + gfxCriticalNote << "RecordedSourceSurfaceCreation read invalid size " + << mSize; + aStream.SetIsBad(); + } + + if (!aStream.good()) { + return; + } + + size_t size = 0; + if (mSize.width >= 0 && mSize.height >= 0) { + size = size_t(mSize.width) * size_t(mSize.height) * BytesPerPixel(mFormat); + mData = new (fallible) uint8_t[size]; + } + if (!mData) { + gfxCriticalNote + << "RecordedSourceSurfaceCreation failed to allocate data of size " + << size; + aStream.SetIsBad(); + } else { + aStream.read((char*)mData, size); + } +} + +inline void RecordedSourceSurfaceCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr + << "] SourceSurface created (Size: " << mSize.width << "x" + << mSize.height << ")"; +} + +inline bool RecordedSourceSurfaceDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveSourceSurface(mRefPtr); + return true; +} + +template <class S> +void RecordedSourceSurfaceDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedSourceSurfaceDestruction::RecordedSourceSurfaceDestruction(S& aStream) + : RecordedEventDerived(SOURCESURFACEDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedSourceSurfaceDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] SourceSurface Destroyed"; +} + +inline bool RecordedOptimizeSourceSurface::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* surface = aTranslator->LookupSourceSurface(mSurface); + if (!surface) { + return false; + } + + RefPtr<SourceSurface> optimizedSurface = dt->OptimizeSourceSurface(surface); + aTranslator->AddSourceSurface(mOptimizedSurface, optimizedSurface); + return true; +} + +template <class S> +void RecordedOptimizeSourceSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); + WriteElement(aStream, mDT); + WriteElement(aStream, mOptimizedSurface); +} + +template <class S> +RecordedOptimizeSourceSurface::RecordedOptimizeSourceSurface(S& aStream) + : RecordedEventDerived(OPTIMIZESOURCESURFACE) { + ReadElement(aStream, mSurface); + ReadElement(aStream, mDT); + ReadElement(aStream, mOptimizedSurface); +} + +inline void RecordedOptimizeSourceSurface::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mSurface << "] Surface Optimized (DT: " << mDT << ")"; +} + +inline bool RecordedExternalSurfaceCreation::PlayEvent( + Translator* aTranslator) const { + RefPtr<SourceSurface> surface = aTranslator->LookupExternalSurface(mKey); + if (!surface) { + return false; + } + + aTranslator->AddSourceSurface(mRefPtr, surface); + return true; +} + +template <class S> +void RecordedExternalSurfaceCreation::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mKey); +} + +template <class S> +RecordedExternalSurfaceCreation::RecordedExternalSurfaceCreation(S& aStream) + : RecordedEventDerived(EXTERNALSURFACECREATION) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mKey); +} + +inline void RecordedExternalSurfaceCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr + << "] SourceSurfaceSharedData created (Key: " << mKey << ")"; +} + +inline RecordedFilterNodeCreation::~RecordedFilterNodeCreation() = default; + +inline bool RecordedFilterNodeCreation::PlayEvent( + Translator* aTranslator) const { + DrawTarget* drawTarget = aTranslator->LookupDrawTarget(mDT); + if (!drawTarget) { + return false; + } + + RefPtr<FilterNode> node = drawTarget->CreateFilter(mType); + aTranslator->AddFilterNode(mRefPtr, node); + return true; +} + +template <class S> +void RecordedFilterNodeCreation::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mType); +} + +template <class S> +RecordedFilterNodeCreation::RecordedFilterNodeCreation(S& aStream) + : RecordedEventDerived(FILTERNODECREATION) { + ReadElement(aStream, mDT); + ReadElement(aStream, mRefPtr); + ReadElementConstrained(aStream, mType, FilterType::BLEND, + FilterType::OPACITY); +} + +inline void RecordedFilterNodeCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] CreateFilter [" << mRefPtr + << "] FilterNode created (Type: " << int(mType) << ")"; +} + +inline bool RecordedFilterNodeDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveFilterNode(mRefPtr); + return true; +} + +template <class S> +void RecordedFilterNodeDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedFilterNodeDestruction::RecordedFilterNodeDestruction(S& aStream) + : RecordedEventDerived(FILTERNODEDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedFilterNodeDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] FilterNode Destroyed"; +} + +inline RecordedGradientStopsCreation::~RecordedGradientStopsCreation() { + if (mDataOwned) { + delete[] mStops; + } +} + +inline bool RecordedGradientStopsCreation::PlayEvent( + Translator* aTranslator) const { + if (mNumStops > 0 && !mStops) { + // Stops allocation failed + return false; + } + + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + RefPtr<GradientStops> src = + aTranslator->GetOrCreateGradientStops(dt, mStops, mNumStops, mExtendMode); + aTranslator->AddGradientStops(mRefPtr, src); + return true; +} + +template <class S> +void RecordedGradientStopsCreation::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mExtendMode); + WriteElement(aStream, mNumStops); + aStream.write((const char*)mStops, mNumStops * sizeof(GradientStop)); +} + +template <class S> +RecordedGradientStopsCreation::RecordedGradientStopsCreation(S& aStream) + : RecordedEventDerived(GRADIENTSTOPSCREATION), mDataOwned(true) { + ReadElement(aStream, mDT); + ReadElement(aStream, mRefPtr); + ReadElementConstrained(aStream, mExtendMode, ExtendMode::CLAMP, + ExtendMode::REFLECT); + ReadElement(aStream, mNumStops); + if (!aStream.good() || mNumStops <= 0) { + return; + } + + mStops = new (fallible) GradientStop[mNumStops]; + if (!mStops) { + gfxCriticalNote + << "RecordedGradientStopsCreation failed to allocate stops of size " + << mNumStops; + aStream.SetIsBad(); + } else { + aStream.read((char*)mStops, mNumStops * sizeof(GradientStop)); + } +} + +inline void RecordedGradientStopsCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] [" << mRefPtr + << "] GradientStops created (Stops: " << mNumStops << ")"; +} + +inline bool RecordedGradientStopsDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveGradientStops(mRefPtr); + return true; +} + +template <class S> +void RecordedGradientStopsDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedGradientStopsDestruction::RecordedGradientStopsDestruction(S& aStream) + : RecordedEventDerived(GRADIENTSTOPSDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedGradientStopsDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] GradientStops Destroyed"; +} + +inline bool RecordedIntoLuminanceSource::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + RefPtr<SourceSurface> src = dt->IntoLuminanceSource(mLuminanceType, mOpacity); + aTranslator->AddSourceSurface(mRefPtr, src); + return true; +} + +template <class S> +void RecordedIntoLuminanceSource::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mDT); + WriteElement(aStream, mLuminanceType); + WriteElement(aStream, mOpacity); +} + +template <class S> +RecordedIntoLuminanceSource::RecordedIntoLuminanceSource(S& aStream) + : RecordedEventDerived(INTOLUMINANCE) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mDT); + ReadElementConstrained(aStream, mLuminanceType, LuminanceType::LUMINANCE, + LuminanceType::LINEARRGB); + ReadElement(aStream, mOpacity); +} + +inline void RecordedIntoLuminanceSource::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] Into Luminance Source (DT: " << mDT + << ")"; +} + +inline bool RecordedFlush::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->Flush(); + return true; +} + +template <class S> +void RecordedFlush::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template <class S> +RecordedFlush::RecordedFlush(S& aStream) + : RecordedDrawingEvent(FLUSH, aStream) {} + +inline void RecordedFlush::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] Flush"; +} + +inline bool RecordedDetachAllSnapshots::PlayEvent( + Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + dt->DetachAllSnapshots(); + return true; +} + +template <class S> +void RecordedDetachAllSnapshots::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template <class S> +RecordedDetachAllSnapshots::RecordedDetachAllSnapshots(S& aStream) + : RecordedDrawingEvent(DETACHALLSNAPSHOTS, aStream) {} + +inline void RecordedDetachAllSnapshots::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DetachAllSnapshots"; +} + +inline bool RecordedSnapshot::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + RefPtr<SourceSurface> src = aTranslator->LookupDrawTarget(mDT)->Snapshot(); + aTranslator->AddSourceSurface(mRefPtr, src); + return true; +} + +template <class S> +void RecordedSnapshot::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mDT); +} + +template <class S> +RecordedSnapshot::RecordedSnapshot(S& aStream) + : RecordedEventDerived(SNAPSHOT) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mDT); +} + +inline void RecordedSnapshot::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] Snapshot Created (DT: " << mDT << ")"; +} + +inline RecordedFontData::~RecordedFontData() { delete[] mData; } + +inline bool RecordedFontData::PlayEvent(Translator* aTranslator) const { + if (!mData) { + return false; + } + + RefPtr<NativeFontResource> fontResource = Factory::CreateNativeFontResource( + mData, mFontDetails.size, mType, aTranslator->GetFontContext()); + if (!fontResource) { + return false; + } + + aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource); + return true; +} + +template <class S> +void RecordedFontData::Record(S& aStream) const { + MOZ_ASSERT(mGetFontFileDataSucceeded); + + WriteElement(aStream, mType); + WriteElement(aStream, mFontDetails.fontDataKey); + if (!mData) { + WriteElement(aStream, 0); + } else { + WriteElement(aStream, mFontDetails.size); + aStream.write((const char*)mData, mFontDetails.size); + } +} + +inline void RecordedFontData::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "Font Data of size " << mFontDetails.size; +} + +inline void RecordedFontData::SetFontData(const uint8_t* aData, uint32_t aSize, + uint32_t aIndex) { + mData = new (fallible) uint8_t[aSize]; + if (!mData) { + gfxCriticalNote + << "RecordedFontData failed to allocate data for recording of size " + << aSize; + } else { + memcpy(mData, aData, aSize); + } + mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize, 0, nullptr); + mFontDetails.size = aSize; + mFontDetails.index = aIndex; +} + +inline bool RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails) { + if (!mGetFontFileDataSucceeded) { + return false; + } + + fontDetails.fontDataKey = mFontDetails.fontDataKey; + fontDetails.size = mFontDetails.size; + fontDetails.index = mFontDetails.index; + return true; +} + +template <class S> +RecordedFontData::RecordedFontData(S& aStream) + : RecordedEventDerived(FONTDATA), mType(FontType::UNKNOWN) { + ReadElementConstrained(aStream, mType, FontType::DWRITE, FontType::UNKNOWN); + ReadElement(aStream, mFontDetails.fontDataKey); + ReadElement(aStream, mFontDetails.size); + if (!mFontDetails.size || !aStream.good()) { + return; + } + + mData = new (fallible) uint8_t[mFontDetails.size]; + if (!mData) { + gfxCriticalNote + << "RecordedFontData failed to allocate data for playback of size " + << mFontDetails.size; + aStream.SetIsBad(); + } else { + aStream.read((char*)mData, mFontDetails.size); + } +} + +inline RecordedFontDescriptor::~RecordedFontDescriptor() = default; + +inline bool RecordedFontDescriptor::PlayEvent(Translator* aTranslator) const { + RefPtr<UnscaledFont> font = Factory::CreateUnscaledFontFromFontDescriptor( + mType, mData.data(), mData.size(), mIndex); + if (!font) { + gfxDevCrash(LogReason::InvalidFont) + << "Failed creating UnscaledFont of type " << int(mType) + << " from font descriptor"; + return false; + } + + aTranslator->AddUnscaledFont(mRefPtr, font); + return true; +} + +template <class S> +void RecordedFontDescriptor::Record(S& aStream) const { + MOZ_ASSERT(mHasDesc); + WriteElement(aStream, mType); + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mIndex); + WriteElement(aStream, (size_t)mData.size()); + if (mData.size()) { + aStream.write((char*)mData.data(), mData.size()); + } +} + +inline void RecordedFontDescriptor::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] Font Descriptor"; +} + +inline void RecordedFontDescriptor::SetFontDescriptor(const uint8_t* aData, + uint32_t aSize, + uint32_t aIndex) { + mData.assign(aData, aData + aSize); + mIndex = aIndex; +} + +template <class S> +RecordedFontDescriptor::RecordedFontDescriptor(S& aStream) + : RecordedEventDerived(FONTDESC) { + ReadElementConstrained(aStream, mType, FontType::DWRITE, FontType::UNKNOWN); + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mIndex); + + size_t size; + ReadElement(aStream, size); + if (!aStream.good()) { + return; + } + if (size) { + mData.resize(size); + aStream.read((char*)mData.data(), size); + } +} + +inline bool RecordedUnscaledFontCreation::PlayEvent( + Translator* aTranslator) const { + NativeFontResource* fontResource = + aTranslator->LookupNativeFontResource(mFontDataKey); + if (!fontResource) { + gfxDevCrash(LogReason::NativeFontResourceNotFound) + << "NativeFontResource lookup failed for key |" << hexa(mFontDataKey) + << "|."; + return false; + } + + RefPtr<UnscaledFont> unscaledFont = fontResource->CreateUnscaledFont( + mIndex, mInstanceData.data(), mInstanceData.size()); + aTranslator->AddUnscaledFont(mRefPtr, unscaledFont); + return true; +} + +template <class S> +void RecordedUnscaledFontCreation::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mFontDataKey); + WriteElement(aStream, mIndex); + WriteElement(aStream, (size_t)mInstanceData.size()); + if (mInstanceData.size()) { + aStream.write((char*)mInstanceData.data(), mInstanceData.size()); + } +} + +inline void RecordedUnscaledFontCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] UnscaledFont Created"; +} + +inline void RecordedUnscaledFontCreation::SetFontInstanceData( + const uint8_t* aData, uint32_t aSize) { + if (aSize) { + mInstanceData.assign(aData, aData + aSize); + } +} + +template <class S> +RecordedUnscaledFontCreation::RecordedUnscaledFontCreation(S& aStream) + : RecordedEventDerived(UNSCALEDFONTCREATION) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mFontDataKey); + ReadElement(aStream, mIndex); + + size_t size; + ReadElement(aStream, size); + if (!aStream.good()) { + return; + } + if (size) { + mInstanceData.resize(size); + aStream.read((char*)mInstanceData.data(), size); + } +} + +inline bool RecordedUnscaledFontDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveUnscaledFont(mRefPtr); + return true; +} + +template <class S> +void RecordedUnscaledFontDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedUnscaledFontDestruction::RecordedUnscaledFontDestruction(S& aStream) + : RecordedEventDerived(UNSCALEDFONTDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedUnscaledFontDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] UnscaledFont Destroyed"; +} + +inline bool RecordedScaledFontCreation::PlayEvent( + Translator* aTranslator) const { + UnscaledFont* unscaledFont = aTranslator->LookupUnscaledFont(mUnscaledFont); + if (!unscaledFont) { + gfxDevCrash(LogReason::UnscaledFontNotFound) + << "UnscaledFont lookup failed for key |" << hexa(mUnscaledFont) + << "|."; + return false; + } + + RefPtr<ScaledFont> scaledFont = unscaledFont->CreateScaledFont( + mGlyphSize, mInstanceData.data(), mInstanceData.size(), + mVariations.data(), mVariations.size()); + + aTranslator->AddScaledFont(mRefPtr, scaledFont); + return true; +} + +template <class S> +void RecordedScaledFontCreation::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mUnscaledFont); + WriteElement(aStream, mGlyphSize); + WriteElement(aStream, (size_t)mInstanceData.size()); + if (mInstanceData.size()) { + aStream.write((char*)mInstanceData.data(), mInstanceData.size()); + } + WriteElement(aStream, (size_t)mVariations.size()); + if (mVariations.size()) { + aStream.write((char*)mVariations.data(), + sizeof(FontVariation) * mVariations.size()); + } +} + +inline void RecordedScaledFontCreation::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] ScaledFont Created"; +} + +inline void RecordedScaledFontCreation::SetFontInstanceData( + const uint8_t* aData, uint32_t aSize, const FontVariation* aVariations, + uint32_t aNumVariations) { + if (aSize) { + mInstanceData.assign(aData, aData + aSize); + } + if (aNumVariations) { + mVariations.assign(aVariations, aVariations + aNumVariations); + } +} + +template <class S> +RecordedScaledFontCreation::RecordedScaledFontCreation(S& aStream) + : RecordedEventDerived(SCALEDFONTCREATION) { + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mUnscaledFont); + ReadElement(aStream, mGlyphSize); + + size_t size; + ReadElement(aStream, size); + if (!aStream.good()) { + return; + } + if (size) { + mInstanceData.resize(size); + aStream.read((char*)mInstanceData.data(), size); + } + + size_t numVariations; + ReadElement(aStream, numVariations); + if (!aStream.good()) { + return; + } + if (numVariations) { + mVariations.resize(numVariations); + aStream.read((char*)mVariations.data(), + sizeof(FontVariation) * numVariations); + } +} + +inline bool RecordedScaledFontDestruction::PlayEvent( + Translator* aTranslator) const { + aTranslator->RemoveScaledFont(mRefPtr); + return true; +} + +template <class S> +void RecordedScaledFontDestruction::Record(S& aStream) const { + WriteElement(aStream, mRefPtr); +} + +template <class S> +RecordedScaledFontDestruction::RecordedScaledFontDestruction(S& aStream) + : RecordedEventDerived(SCALEDFONTDESTRUCTION) { + ReadElement(aStream, mRefPtr); +} + +inline void RecordedScaledFontDestruction::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mRefPtr << "] ScaledFont Destroyed"; +} + +inline bool RecordedMaskSurface::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + + SourceSurface* surface = aTranslator->LookupSourceSurface(mRefMask); + if (!surface) { + return false; + } + + dt->MaskSurface(*GenericPattern(mPattern, aTranslator), surface, mOffset, + mOptions); + return true; +} + +template <class S> +void RecordedMaskSurface::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + RecordPatternData(aStream, mPattern); + WriteElement(aStream, mRefMask); + WriteElement(aStream, mOffset); + WriteElement(aStream, mOptions); +} + +template <class S> +RecordedMaskSurface::RecordedMaskSurface(S& aStream) + : RecordedDrawingEvent(MASKSURFACE, aStream) { + ReadPatternData(aStream, mPattern); + ReadElement(aStream, mRefMask); + ReadElement(aStream, mOffset); + ReadDrawOptions(aStream, mOptions); +} + +inline void RecordedMaskSurface::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] MaskSurface (" << mRefMask << ") Offset: (" + << mOffset.x << "x" << mOffset.y << ") Pattern: "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +template <typename T> +void ReplaySetAttribute(FilterNode* aNode, uint32_t aIndex, T aValue) { + aNode->SetAttribute(aIndex, aValue); +} + +inline bool RecordedFilterNodeSetAttribute::PlayEvent( + Translator* aTranslator) const { + FilterNode* node = aTranslator->LookupFilterNode(mNode); + if (!node) { + return false; + } + +#define REPLAY_SET_ATTRIBUTE(type, argtype) \ + case ARGTYPE_##argtype: \ + ReplaySetAttribute(node, mIndex, *(type*)&mPayload.front()); \ + break + + switch (mArgType) { + REPLAY_SET_ATTRIBUTE(bool, BOOL); + REPLAY_SET_ATTRIBUTE(uint32_t, UINT32); + REPLAY_SET_ATTRIBUTE(Float, FLOAT); + REPLAY_SET_ATTRIBUTE(Size, SIZE); + REPLAY_SET_ATTRIBUTE(IntSize, INTSIZE); + REPLAY_SET_ATTRIBUTE(IntPoint, INTPOINT); + REPLAY_SET_ATTRIBUTE(Rect, RECT); + REPLAY_SET_ATTRIBUTE(IntRect, INTRECT); + REPLAY_SET_ATTRIBUTE(Point, POINT); + REPLAY_SET_ATTRIBUTE(Matrix, MATRIX); + REPLAY_SET_ATTRIBUTE(Matrix5x4, MATRIX5X4); + REPLAY_SET_ATTRIBUTE(Point3D, POINT3D); + REPLAY_SET_ATTRIBUTE(DeviceColor, COLOR); + case ARGTYPE_FLOAT_ARRAY: + node->SetAttribute(mIndex, + reinterpret_cast<const Float*>(&mPayload.front()), + mPayload.size() / sizeof(Float)); + break; + } + + return true; +} + +template <class S> +void RecordedFilterNodeSetAttribute::Record(S& aStream) const { + WriteElement(aStream, mNode); + WriteElement(aStream, mIndex); + WriteElement(aStream, mArgType); + WriteElement(aStream, uint64_t(mPayload.size())); + aStream.write((const char*)&mPayload.front(), mPayload.size()); +} + +template <class S> +RecordedFilterNodeSetAttribute::RecordedFilterNodeSetAttribute(S& aStream) + : RecordedEventDerived(FILTERNODESETATTRIBUTE) { + ReadElement(aStream, mNode); + ReadElement(aStream, mIndex); + ReadElementConstrained(aStream, mArgType, ArgType::ARGTYPE_UINT32, + ArgType::ARGTYPE_FLOAT_ARRAY); + uint64_t size; + ReadElement(aStream, size); + if (!aStream.good()) { + return; + } + + mPayload.resize(size_t(size)); + aStream.read((char*)&mPayload.front(), size); +} + +inline void RecordedFilterNodeSetAttribute::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ")"; +} + +inline bool RecordedFilterNodeSetInput::PlayEvent( + Translator* aTranslator) const { + FilterNode* node = aTranslator->LookupFilterNode(mNode); + if (!node) { + return false; + } + + if (mInputFilter) { + node->SetInput(mIndex, aTranslator->LookupFilterNode(mInputFilter)); + } else { + node->SetInput(mIndex, aTranslator->LookupSourceSurface(mInputSurface)); + } + + return true; +} + +template <class S> +void RecordedFilterNodeSetInput::Record(S& aStream) const { + WriteElement(aStream, mNode); + WriteElement(aStream, mIndex); + WriteElement(aStream, mInputFilter); + WriteElement(aStream, mInputSurface); +} + +template <class S> +RecordedFilterNodeSetInput::RecordedFilterNodeSetInput(S& aStream) + : RecordedEventDerived(FILTERNODESETINPUT) { + ReadElement(aStream, mNode); + ReadElement(aStream, mIndex); + ReadElement(aStream, mInputFilter); + ReadElement(aStream, mInputSurface); +} + +inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ", "; + + if (mInputFilter) { + aStringStream << "Filter: " << mInputFilter; + } else { + aStringStream << "Surface: " << mInputSurface; + } + + aStringStream << ")"; +} + +inline bool RecordedLink::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + dt->Link(mDestination.c_str(), mRect); + return true; +} + +template <class S> +void RecordedLink::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mRect); + uint32_t len = mDestination.length(); + WriteElement(aStream, len); + if (len) { + aStream.write(mDestination.data(), len); + } +} + +template <class S> +RecordedLink::RecordedLink(S& aStream) : RecordedDrawingEvent(LINK, aStream) { + ReadElement(aStream, mRect); + uint32_t len; + ReadElement(aStream, len); + mDestination.resize(size_t(len)); + if (len && aStream.good()) { + aStream.read(&mDestination.front(), len); + } +} + +inline void RecordedLink::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "Link [" << mDestination << " @ " << mRect << "]"; +} + +inline bool RecordedDestination::PlayEvent(Translator* aTranslator) const { + DrawTarget* dt = aTranslator->LookupDrawTarget(mDT); + if (!dt) { + return false; + } + dt->Destination(mDestination.c_str(), mPoint); + return true; +} + +template <class S> +void RecordedDestination::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); + WriteElement(aStream, mPoint); + uint32_t len = mDestination.length(); + WriteElement(aStream, len); + if (len) { + aStream.write(mDestination.data(), len); + } +} + +template <class S> +RecordedDestination::RecordedDestination(S& aStream) + : RecordedDrawingEvent(DESTINATION, aStream) { + ReadElement(aStream, mPoint); + uint32_t len; + ReadElement(aStream, len); + mDestination.resize(size_t(len)); + if (len && aStream.good()) { + aStream.read(&mDestination.front(), len); + } +} + +inline void RecordedDestination::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "Destination [" << mDestination << " @ " << mPoint << "]"; +} + +#define FOR_EACH_EVENT(f) \ + f(DRAWTARGETCREATION, RecordedDrawTargetCreation); \ + f(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction); \ + f(FILLRECT, RecordedFillRect); \ + f(STROKERECT, RecordedStrokeRect); \ + f(STROKELINE, RecordedStrokeLine); \ + f(CLEARRECT, RecordedClearRect); \ + f(COPYSURFACE, RecordedCopySurface); \ + f(SETTRANSFORM, RecordedSetTransform); \ + f(PUSHCLIPRECT, RecordedPushClipRect); \ + f(PUSHCLIP, RecordedPushClip); \ + f(POPCLIP, RecordedPopClip); \ + f(FILL, RecordedFill); \ + f(FILLGLYPHS, RecordedFillGlyphs); \ + f(MASK, RecordedMask); \ + f(STROKE, RecordedStroke); \ + f(DRAWSURFACE, RecordedDrawSurface); \ + f(DRAWDEPENDENTSURFACE, RecordedDrawDependentSurface); \ + f(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow); \ + f(DRAWFILTER, RecordedDrawFilter); \ + f(PATHCREATION, RecordedPathCreation); \ + f(PATHDESTRUCTION, RecordedPathDestruction); \ + f(SOURCESURFACECREATION, RecordedSourceSurfaceCreation); \ + f(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction); \ + f(FILTERNODECREATION, RecordedFilterNodeCreation); \ + f(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction); \ + f(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation); \ + f(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction); \ + f(SNAPSHOT, RecordedSnapshot); \ + f(SCALEDFONTCREATION, RecordedScaledFontCreation); \ + f(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction); \ + f(MASKSURFACE, RecordedMaskSurface); \ + f(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute); \ + f(FILTERNODESETINPUT, RecordedFilterNodeSetInput); \ + f(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget); \ + f(CREATECLIPPEDDRAWTARGET, RecordedCreateClippedDrawTarget); \ + f(CREATEDRAWTARGETFORFILTER, RecordedCreateDrawTargetForFilter); \ + f(FONTDATA, RecordedFontData); \ + f(FONTDESC, RecordedFontDescriptor); \ + f(PUSHLAYER, RecordedPushLayer); \ + f(PUSHLAYERWITHBLEND, RecordedPushLayerWithBlend); \ + f(POPLAYER, RecordedPopLayer); \ + f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \ + f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction); \ + f(INTOLUMINANCE, RecordedIntoLuminanceSource); \ + f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation); \ + f(FLUSH, RecordedFlush); \ + f(DETACHALLSNAPSHOTS, RecordedDetachAllSnapshots); \ + f(OPTIMIZESOURCESURFACE, RecordedOptimizeSourceSurface); \ + f(LINK, RecordedLink); \ + f(DESTINATION, RecordedDestination); + +#define DO_WITH_EVENT_TYPE(_typeenum, _class) \ + case _typeenum: { \ + auto e = _class(aStream); \ + return aAction(&e); \ + } + +template <class S> +bool RecordedEvent::DoWithEvent( + S& aStream, EventType aType, + const std::function<bool(RecordedEvent*)>& aAction) { + switch (aType) { + FOR_EACH_EVENT(DO_WITH_EVENT_TYPE) + default: + return false; + } +} + +} // namespace gfx +} // namespace mozilla + +#endif |