/* -*- 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 RecordedDrawingEvent : public RecordedEventDerived { public: ReferencePtr GetDestinedDT() override { return mDT; } protected: RecordedDrawingEvent(RecordedEvent::EventType aType, DrawTarget* aTarget) : RecordedEventDerived(aType), mDT(aTarget) {} template RecordedDrawingEvent(RecordedEvent::EventType aType, S& aStream); template void Record(S& aStream) const; ReferencePtr mDT; }; class RecordedDrawTargetCreation : public RecordedEventDerived { 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 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 mExistingData; private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedDrawTargetCreation(S& aStream); }; class RecordedDrawTargetDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedDrawTargetDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(DRAWTARGETDESTRUCTION), mRefPtr(aRefPtr), mBackendType(BackendType::NONE) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedDrawTargetDestruction(S& aStream); }; class RecordedCreateSimilarDrawTarget : public RecordedEventDerived { public: RecordedCreateSimilarDrawTarget(ReferencePtr aRefPtr, const IntSize& aSize, SurfaceFormat aFormat) : RecordedEventDerived(CREATESIMILARDRAWTARGET), mRefPtr(aRefPtr), mSize(aSize), mFormat(aFormat) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; virtual void OutputSimpleEventInfo( std::stringstream& aStringStream) const override; std::string GetName() const override { return "CreateSimilarDrawTarget"; } ReferencePtr mRefPtr; IntSize mSize; SurfaceFormat mFormat; private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedCreateSimilarDrawTarget(S& aStream); }; class RecordedCreateClippedDrawTarget : public RecordedDrawingEvent { 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 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 MOZ_IMPLICIT RecordedCreateClippedDrawTarget(S& aStream); }; class RecordedCreateDrawTargetForFilter : public RecordedDrawingEvent { 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 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 MOZ_IMPLICIT RecordedCreateDrawTargetForFilter(S& aStream); }; class RecordedFillRect : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "FillRect"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedFillRect(S& aStream); Rect mRect; PatternStorage mPattern; DrawOptions mOptions; }; class RecordedStrokeRect : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "StrokeRect"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedStrokeRect(S& aStream); Rect mRect; PatternStorage mPattern; StrokeOptions mStrokeOptions; DrawOptions mOptions; }; class RecordedStrokeLine : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "StrokeLine"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedStrokeLine(S& aStream); Point mBegin; Point mEnd; PatternStorage mPattern; StrokeOptions mStrokeOptions; DrawOptions mOptions; }; class RecordedFill : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Fill"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedFill(S& aStream); ReferencePtr mPath; PatternStorage mPattern; DrawOptions mOptions; }; class RecordedFillGlyphs : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "FillGlyphs"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedFillGlyphs(S& aStream); ReferencePtr mScaledFont; PatternStorage mPattern; DrawOptions mOptions; Glyph* mGlyphs = nullptr; uint32_t mNumGlyphs = 0; }; class RecordedMask : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Mask"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedMask(S& aStream); PatternStorage mSource; PatternStorage mMask; DrawOptions mOptions; }; class RecordedStroke : public RecordedDrawingEvent { 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 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 MOZ_IMPLICIT RecordedStroke(S& aStream); ReferencePtr mPath; PatternStorage mPattern; StrokeOptions mStrokeOptions; DrawOptions mOptions; }; class RecordedClearRect : public RecordedDrawingEvent { public: RecordedClearRect(DrawTarget* aDT, const Rect& aRect) : RecordedDrawingEvent(CLEARRECT, aDT), mRect(aRect) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "ClearRect"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedClearRect(S& aStream); Rect mRect; }; class RecordedCopySurface : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "CopySurface"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedCopySurface(S& aStream); ReferencePtr mSourceSurface; IntRect mSourceRect; IntPoint mDest; }; class RecordedPushClip : public RecordedDrawingEvent { public: RecordedPushClip(DrawTarget* aDT, ReferencePtr aPath) : RecordedDrawingEvent(PUSHCLIP, aDT), mPath(aPath) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "PushClip"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedPushClip(S& aStream); ReferencePtr mPath; }; class RecordedPushClipRect : public RecordedDrawingEvent { public: RecordedPushClipRect(DrawTarget* aDT, const Rect& aRect) : RecordedDrawingEvent(PUSHCLIPRECT, aDT), mRect(aRect) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "PushClipRect"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedPushClipRect(S& aStream); Rect mRect; }; class RecordedPopClip : public RecordedDrawingEvent { public: MOZ_IMPLICIT RecordedPopClip(DrawTarget* aDT) : RecordedDrawingEvent(POPCLIP, aDT) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "PopClip"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedPopClip(S& aStream); }; class RecordedPushLayer : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "PushLayer"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedPushLayer(S& aStream); bool mOpaque; Float mOpacity; ReferencePtr mMask; Matrix mMaskTransform; IntRect mBounds; bool mCopyBackground; }; class RecordedPushLayerWithBlend : public RecordedDrawingEvent { 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 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 MOZ_IMPLICIT RecordedPushLayerWithBlend(S& aStream); bool mOpaque; Float mOpacity; ReferencePtr mMask; Matrix mMaskTransform; IntRect mBounds; bool mCopyBackground; CompositionOp mCompositionOp; }; class RecordedPopLayer : public RecordedDrawingEvent { public: MOZ_IMPLICIT RecordedPopLayer(DrawTarget* aDT) : RecordedDrawingEvent(POPLAYER, aDT) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "PopLayer"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedPopLayer(S& aStream); }; class RecordedSetTransform : public RecordedDrawingEvent { public: RecordedSetTransform(DrawTarget* aDT, const Matrix& aTransform) : RecordedDrawingEvent(SETTRANSFORM, aDT), mTransform(aTransform) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedSetTransform(S& aStream); }; class RecordedDrawSurface : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawSurface"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedDrawSurface(S& aStream); ReferencePtr mRefSource; Rect mDest; Rect mSource; DrawSurfaceOptions mDSOptions; DrawOptions mOptions; }; class RecordedDrawDependentSurface : public RecordedDrawingEvent { public: RecordedDrawDependentSurface(DrawTarget* aDT, uint64_t aId, const Rect& aDest) : RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aDT), mId(aId), mDest(aDest) {} bool PlayEvent(Translator* aTranslator) const override; template void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawDependentSurface"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedDrawDependentSurface(S& aStream); uint64_t mId; Rect mDest; }; class RecordedDrawSurfaceWithShadow : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawSurfaceWithShadow"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedDrawSurfaceWithShadow(S& aStream); ReferencePtr mRefSource; Point mDest; ShadowOptions mShadow; CompositionOp mOp; }; class RecordedDrawFilter : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawFilter"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedDrawFilter(S& aStream); ReferencePtr mNode; Rect mSourceRect; Point mDestPoint; DrawOptions mOptions; }; class RecordedPathCreation : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedPathCreation(PathRecording* aPath); bool PlayEvent(Translator* aTranslator) const override; template 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 mRefPtr; FillRule mFillRule; RefPtr mPath; UniquePtr mPathOps; template MOZ_IMPLICIT RecordedPathCreation(S& aStream); }; class RecordedPathDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedPathDestruction(PathRecording* aPath) : RecordedEventDerived(PATHDESTRUCTION), mRefPtr(aPath) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedPathDestruction(S& aStream); }; class RecordedSourceSurfaceCreation : public RecordedEventDerived { 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 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 MOZ_IMPLICIT RecordedSourceSurfaceCreation(S& aStream); }; class RecordedSourceSurfaceDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(SOURCESURFACEDESTRUCTION), mRefPtr(aRefPtr) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedSourceSurfaceDestruction(S& aStream); }; class RecordedOptimizeSourceSurface : public RecordedEventDerived { public: RecordedOptimizeSourceSurface(ReferencePtr aSurface, ReferencePtr aDT, ReferencePtr aOptimizedSurface) : RecordedEventDerived(OPTIMIZESOURCESURFACE), mSurface(aSurface), mDT(aDT), mOptimizedSurface(aOptimizedSurface) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedOptimizeSourceSurface(S& aStream); }; class RecordedExternalSurfaceCreation : public RecordedEventDerived { public: RecordedExternalSurfaceCreation(ReferencePtr aRefPtr, const uint64_t aKey) : RecordedEventDerived(EXTERNALSURFACECREATION), mRefPtr(aRefPtr), mKey(aKey) {} ~RecordedExternalSurfaceCreation() = default; virtual bool PlayEvent(Translator* aTranslator) const; template 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 MOZ_IMPLICIT RecordedExternalSurfaceCreation(S& aStream); }; class RecordedFilterNodeCreation : public RecordedEventDerived { public: RecordedFilterNodeCreation(ReferencePtr aRefPtr, FilterType aType) : RecordedEventDerived(FILTERNODECREATION), mRefPtr(aRefPtr), mType(aType) {} ~RecordedFilterNodeCreation(); bool PlayEvent(Translator* aTranslator) const override; template 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 mRefPtr; FilterType mType; template MOZ_IMPLICIT RecordedFilterNodeCreation(S& aStream); }; class RecordedFilterNodeDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedFilterNodeDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(FILTERNODEDESTRUCTION), mRefPtr(aRefPtr) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedFilterNodeDestruction(S& aStream); }; class RecordedGradientStopsCreation : public RecordedEventDerived { public: RecordedGradientStopsCreation(ReferencePtr aRefPtr, GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) : RecordedEventDerived(GRADIENTSTOPSCREATION), mRefPtr(aRefPtr), mStops(aStops), mNumStops(aNumStops), mExtendMode(aExtendMode), mDataOwned(false) {} ~RecordedGradientStopsCreation(); bool PlayEvent(Translator* aTranslator) const override; template 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 mRefPtr; GradientStop* mStops = nullptr; uint32_t mNumStops = 0; ExtendMode mExtendMode; bool mDataOwned; template MOZ_IMPLICIT RecordedGradientStopsCreation(S& aStream); }; class RecordedGradientStopsDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedGradientStopsDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(GRADIENTSTOPSDESTRUCTION), mRefPtr(aRefPtr) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedGradientStopsDestruction(S& aStream); }; class RecordedFlush : public RecordedDrawingEvent { public: explicit RecordedFlush(DrawTarget* aDT) : RecordedDrawingEvent(FLUSH, aDT) {} bool PlayEvent(Translator* aTranslator) const final; template 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 MOZ_IMPLICIT RecordedFlush(S& aStream); }; class RecordedDetachAllSnapshots : public RecordedDrawingEvent { public: explicit RecordedDetachAllSnapshots(DrawTarget* aDT) : RecordedDrawingEvent(DETACHALLSNAPSHOTS, aDT) {} bool PlayEvent(Translator* aTranslator) const final; template 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 MOZ_IMPLICIT RecordedDetachAllSnapshots(S& aStream); }; class RecordedSnapshot : public RecordedEventDerived { public: RecordedSnapshot(ReferencePtr aRefPtr, DrawTarget* aDT) : RecordedEventDerived(SNAPSHOT), mRefPtr(aRefPtr), mDT(aDT) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedSnapshot(S& aStream); }; class RecordedIntoLuminanceSource : public RecordedEventDerived { 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 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 MOZ_IMPLICIT RecordedIntoLuminanceSource(S& aStream); }; class RecordedFontData : public RecordedEventDerived { public: static void FontDataProc(const uint8_t* aData, uint32_t aSize, uint32_t aIndex, void* aBaton) { auto recordedFontData = static_cast(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 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 MOZ_IMPLICIT RecordedFontData(S& aStream); }; class RecordedFontDescriptor : public RecordedEventDerived { public: static void FontDescCb(const uint8_t* aData, uint32_t aSize, uint32_t aIndex, void* aBaton) { auto recordedFontDesc = static_cast(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 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 mData; uint32_t mIndex; ReferencePtr mRefPtr; template MOZ_IMPLICIT RecordedFontDescriptor(S& aStream); }; class RecordedUnscaledFontCreation : public RecordedEventDerived { public: static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, void* aBaton) { auto recordedUnscaledFontCreation = static_cast(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 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 mInstanceData; template MOZ_IMPLICIT RecordedUnscaledFontCreation(S& aStream); }; class RecordedUnscaledFontDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedUnscaledFontDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(UNSCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedUnscaledFontDestruction(S& aStream); }; class RecordedScaledFontCreation : public RecordedEventDerived { public: static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, const FontVariation* aVariations, uint32_t aNumVariations, void* aBaton) { auto recordedScaledFontCreation = static_cast(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 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 mInstanceData; std::vector mVariations; template MOZ_IMPLICIT RecordedScaledFontCreation(S& aStream); }; class RecordedScaledFontDestruction : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr) : RecordedEventDerived(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedScaledFontDestruction(S& aStream); }; class RecordedMaskSurface : public RecordedDrawingEvent { 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 void Record(S& aStream) const; void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "MaskSurface"; } private: friend class RecordedEvent; template MOZ_IMPLICIT RecordedMaskSurface(S& aStream); PatternStorage mPattern; ReferencePtr mRefMask; Point mOffset; DrawOptions mOptions; }; class RecordedFilterNodeSetAttribute : public RecordedEventDerived { 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 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 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 mPayload; template MOZ_IMPLICIT RecordedFilterNodeSetAttribute(S& aStream); }; class RecordedFilterNodeSetInput : public RecordedEventDerived { 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 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 MOZ_IMPLICIT RecordedFilterNodeSetInput(S& aStream); }; class RecordedLink : public RecordedDrawingEvent { public: RecordedLink(DrawTarget* aDT, const char* aDestination, const Rect& aRect) : RecordedDrawingEvent(LINK, aDT), mDestination(aDestination), mRect(aRect) {} bool PlayEvent(Translator* aTranslator) const override; template 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 MOZ_IMPLICIT RecordedLink(S& aStream); }; class RecordedDestination : public RecordedDrawingEvent { public: RecordedDestination(DrawTarget* aDT, const char* aDestination, const Point& aPoint) : RecordedDrawingEvent(DESTINATION, aDT), mDestination(aDestination), mPoint(aPoint) {} bool PlayEvent(Translator* aTranslator) const override; template 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 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 void RecordedEvent::RecordPatternData(S& aStream, const PatternStorage& aPattern) const { WriteElement(aStream, aPattern.mType); switch (aPattern.mType) { case PatternType::COLOR: { WriteElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::LINEAR_GRADIENT: { WriteElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::RADIAL_GRADIENT: { WriteElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::CONIC_GRADIENT: { WriteElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::SURFACE: { WriteElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } default: return; } } template 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(&aPattern.mStorage)); return; } case PatternType::LINEAR_GRADIENT: { ReadElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::RADIAL_GRADIENT: { ReadElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::CONIC_GRADIENT: { ReadElement(aStream, *reinterpret_cast( &aPattern.mStorage)); return; } case PatternType::SURFACE: { SurfacePatternStorage* sps = reinterpret_cast(&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(&aDestination.mStorage)->mColor = static_cast(&aSource)->mColor; return; } case PatternType::LINEAR_GRADIENT: { LinearGradientPatternStorage* store = reinterpret_cast( &aDestination.mStorage); const LinearGradientPattern* pat = static_cast(&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( &aDestination.mStorage); const RadialGradientPattern* pat = static_cast(&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( &aDestination.mStorage); const ConicGradientPattern* pat = static_cast(&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(&aDestination.mStorage); const SurfacePattern* pat = static_cast(&aSource); store->mExtend = pat->mExtendMode; store->mSamplingFilter = pat->mSamplingFilter; store->mMatrix = pat->mMatrix; store->mSurface = pat->mSurface; store->mSamplingRect = pat->mSamplingRect; return; } } } template 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 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 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_OVER || aDrawOptions.mCompositionOp > CompositionOp::OP_COUNT) { aStream.SetIsBad(); } } template 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(&aStorage.mStorage) ->mColor; aOutput << "DeviceColor: (" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")"; return; } case PatternType::LINEAR_GRADIENT: { const LinearGradientPatternStorage* store = reinterpret_cast( &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( &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( &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(&aStorage.mStorage); aOutput << "Surface (0x" << store->mSurface << ")"; return; } } } template template RecordedDrawingEvent::RecordedDrawingEvent(RecordedEvent::EventType aType, S& aStream) : RecordedEventDerived(aType) { ReadElement(aStream, mDT); } template template void RecordedDrawingEvent::Record(S& aStream) const { WriteElement(aStream, mDT); } inline bool RecordedDrawTargetCreation::PlayEvent( Translator* aTranslator) const { RefPtr 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 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 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 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 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 void RecordedDrawTargetDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 { RefPtr drawTarget = aTranslator->GetReferenceDrawTarget(); if (!drawTarget) { // We might end up with a null reference draw target due to a device // failure, just return false so that we can recover. return false; } RefPtr 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 void RecordedCreateSimilarDrawTarget::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mSize); WriteElement(aStream, mFormat); } template RecordedCreateSimilarDrawTarget::RecordedCreateSimilarDrawTarget(S& aStream) : RecordedEventDerived(CREATESIMILARDRAWTARGET) { ReadElement(aStream, mRefPtr); ReadElement(aStream, mSize); ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, SurfaceFormat::UNKNOWN); } inline void RecordedCreateSimilarDrawTarget::OutputSimpleEventInfo( std::stringstream& aStringStream) const { aStringStream << "[" << 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 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 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 void RecordedCreateClippedDrawTarget::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRefPtr); WriteElement(aStream, mBounds); WriteElement(aStream, mFormat); } template 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 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 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(&aStorage); } ~GenericPattern() { if (mPattern) { mPattern->~Pattern(); } } operator Pattern*() { switch (mStorage->mType) { case PatternType::COLOR: return new (mColPat) ColorPattern( reinterpret_cast(&mStorage->mStorage) ->mColor); case PatternType::SURFACE: { SurfacePatternStorage* storage = reinterpret_cast(&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( &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( &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(&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 void RecordedFillRect::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRect); WriteElement(aStream, mOptions); RecordPatternData(aStream, mPattern); } template 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 void RecordedStrokeRect::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRect); WriteElement(aStream, mOptions); RecordPatternData(aStream, mPattern); RecordStrokeOptions(aStream, mStrokeOptions); } template 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 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 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 RecordedFill::RecordedFill(S& aStream) : RecordedDrawingEvent(FILL, aStream) { ReadElement(aStream, mPath); ReadDrawOptions(aStream, mOptions); ReadPatternData(aStream, mPattern); } template 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 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 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 RecordedMask::RecordedMask(S& aStream) : RecordedDrawingEvent(MASK, aStream) { ReadDrawOptions(aStream, mOptions); ReadPatternData(aStream, mSource); ReadPatternData(aStream, mMask); } template 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 void RecordedStroke::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mPath); WriteElement(aStream, mOptions); RecordPatternData(aStream, mPattern); RecordStrokeOptions(aStream, mStrokeOptions); } template 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 void RecordedClearRect::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRect); } template 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 void RecordedCopySurface::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mSourceSurface); WriteElement(aStream, mSourceRect); WriteElement(aStream, mDest); } template 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 void RecordedPushClip::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mPath); } template 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 void RecordedPushClipRect::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRect); } template 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 void RecordedPopClip::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); } template 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 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 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 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 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 void RecordedPopLayer::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); } template 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 void RecordedSetTransform::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mTransform); } template 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 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 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 void RecordedDrawDependentSurface::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mId); WriteElement(aStream, mDest); } template 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 void RecordedDrawFilter::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mNode); WriteElement(aStream, mSourceRect); WriteElement(aStream, mDestPoint); WriteElement(aStream, mOptions); } template 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 void RecordedDrawSurfaceWithShadow::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); WriteElement(aStream, mRefSource); WriteElement(aStream, mDest); WriteElement(aStream, mShadow); WriteElement(aStream, mOp); } template 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(PathRecording* aPath) : RecordedEventDerived(PATHCREATION), mRefPtr(aPath), mFillRule(aPath->mFillRule), mPath(aPath) {} inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const { RefPtr drawTarget = aTranslator->GetReferenceDrawTarget(); if (!drawTarget) { // We might end up with a null reference draw target due to a device // failure, just return false so that we can recover. return false; } RefPtr builder = drawTarget->CreatePathBuilder(mFillRule); if (!mPathOps->StreamToSink(*builder)) { return false; } RefPtr path = builder->Finish(); aTranslator->AddPath(mRefPtr, path); return true; } template void RecordedPathCreation::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mFillRule); mPath->mPathOps.Record(aStream); } template RecordedPathCreation::RecordedPathCreation(S& aStream) : RecordedEventDerived(PATHCREATION) { ReadElement(aStream, mRefPtr); ReadElementConstrained(aStream, mFillRule, FillRule::FILL_WINDING, FillRule::FILL_EVEN_ODD); mPathOps = MakeUnique(aStream); } inline void RecordedPathCreation::OutputSimpleEventInfo( std::stringstream& aStringStream) const { size_t numberOfOps = mPath ? mPath->mPathOps.NumberOfOps() : mPathOps->NumberOfOps(); aStringStream << "[" << mRefPtr << "] Path created (OpCount: " << numberOfOps << ")"; } inline bool RecordedPathDestruction::PlayEvent(Translator* aTranslator) const { aTranslator->RemovePath(mRefPtr); return true; } template void RecordedPathDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 src = Factory::CreateWrappingDataSourceSurface( mData, mSize.width * BytesPerPixel(mFormat), mSize, mFormat, [](void* aClosure) { delete[] static_cast(aClosure); }, mData); if (src) { mDataOwned = false; } aTranslator->AddSourceSurface(mRefPtr, src); return true; } template 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 RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(S& aStream) : RecordedEventDerived(SOURCESURFACECREATION), mDataOwned(true) { ReadElement(aStream, mRefPtr); ReadElement(aStream, mSize); ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32, SurfaceFormat::UNKNOWN); 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 void RecordedSourceSurfaceDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 optimizedSurface = dt->OptimizeSourceSurface(surface); aTranslator->AddSourceSurface(mOptimizedSurface, optimizedSurface); return true; } template void RecordedOptimizeSourceSurface::Record(S& aStream) const { WriteElement(aStream, mSurface); WriteElement(aStream, mDT); WriteElement(aStream, mOptimizedSurface); } template 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 surface = aTranslator->LookupExternalSurface(mKey); if (!surface) { return false; } aTranslator->AddSourceSurface(mRefPtr, surface); return true; } template void RecordedExternalSurfaceCreation::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mKey); } template 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 { RefPtr drawTarget = aTranslator->GetReferenceDrawTarget(); if (!drawTarget) { // We might end up with a null reference draw target due to a device // failure, just return false so that we can recover. return false; } RefPtr node = drawTarget->CreateFilter(mType); aTranslator->AddFilterNode(mRefPtr, node); return true; } template void RecordedFilterNodeCreation::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mType); } template RecordedFilterNodeCreation::RecordedFilterNodeCreation(S& aStream) : RecordedEventDerived(FILTERNODECREATION) { ReadElement(aStream, mRefPtr); ReadElementConstrained(aStream, mType, FilterType::BLEND, FilterType::OPACITY); } inline void RecordedFilterNodeCreation::OutputSimpleEventInfo( std::stringstream& aStringStream) const { aStringStream << "[" << mRefPtr << "] FilterNode created (Type: " << int(mType) << ")"; } inline bool RecordedFilterNodeDestruction::PlayEvent( Translator* aTranslator) const { aTranslator->RemoveFilterNode(mRefPtr); return true; } template void RecordedFilterNodeDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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; } RefPtr src = aTranslator->GetOrCreateGradientStops(mStops, mNumStops, mExtendMode); aTranslator->AddGradientStops(mRefPtr, src); return true; } template void RecordedGradientStopsCreation::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mExtendMode); WriteElement(aStream, mNumStops); aStream.write((const char*)mStops, mNumStops * sizeof(GradientStop)); } template RecordedGradientStopsCreation::RecordedGradientStopsCreation(S& aStream) : RecordedEventDerived(GRADIENTSTOPSCREATION), mDataOwned(true) { 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 << "[" << mRefPtr << "] GradientStops created (Stops: " << mNumStops << ")"; } inline bool RecordedGradientStopsDestruction::PlayEvent( Translator* aTranslator) const { aTranslator->RemoveGradientStops(mRefPtr); return true; } template void RecordedGradientStopsDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 src = dt->IntoLuminanceSource(mLuminanceType, mOpacity); aTranslator->AddSourceSurface(mRefPtr, src); return true; } template void RecordedIntoLuminanceSource::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mDT); WriteElement(aStream, mLuminanceType); WriteElement(aStream, mOpacity); } template 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 void RecordedFlush::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); } template 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 void RecordedDetachAllSnapshots::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); } template 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 src = aTranslator->LookupDrawTarget(mDT)->Snapshot(); aTranslator->AddSourceSurface(mRefPtr, src); return true; } template void RecordedSnapshot::Record(S& aStream) const { WriteElement(aStream, mRefPtr); WriteElement(aStream, mDT); } template 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 fontResource = Factory::CreateNativeFontResource( mData, mFontDetails.size, mType, aTranslator->GetFontContext()); if (!fontResource) { return false; } aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource); return true; } template 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 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 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 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 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 = fontResource->CreateUnscaledFont( mIndex, mInstanceData.data(), mInstanceData.size()); aTranslator->AddUnscaledFont(mRefPtr, unscaledFont); return true; } template 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 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 void RecordedUnscaledFontDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 = unscaledFont->CreateScaledFont( mGlyphSize, mInstanceData.data(), mInstanceData.size(), mVariations.data(), mVariations.size()); aTranslator->AddScaledFont(mRefPtr, scaledFont); return true; } template 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 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 void RecordedScaledFontDestruction::Record(S& aStream) const { WriteElement(aStream, mRefPtr); } template 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 void RecordedMaskSurface::Record(S& aStream) const { RecordedDrawingEvent::Record(aStream); RecordPatternData(aStream, mPattern); WriteElement(aStream, mRefMask); WriteElement(aStream, mOffset); WriteElement(aStream, mOptions); } template 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 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(&mPayload.front()), mPayload.size() / sizeof(Float)); break; } return true; } template 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 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 void RecordedFilterNodeSetInput::Record(S& aStream) const { WriteElement(aStream, mNode); WriteElement(aStream, mIndex); WriteElement(aStream, mInputFilter); WriteElement(aStream, mInputSurface); } template 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 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 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 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 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 bool RecordedEvent::DoWithEvent( S& aStream, EventType aType, const std::function& aAction) { switch (aType) { FOR_EACH_EVENT(DO_WITH_EVENT_TYPE) default: return false; } } } // namespace gfx } // namespace mozilla #endif