/* -*- 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/. */ #include "DrawTargetWrapAndRecord.h" #include "PathRecording.h" #include #include "Logging.h" #include "Tools.h" #include "Filters.h" #include "mozilla/UniquePtr.h" #include "RecordingTypes.h" #include "RecordedEventImpl.h" namespace mozilla { namespace gfx { struct WrapAndRecordSourceSurfaceUserData { void* refPtr; RefPtr recorder; }; static void WrapAndRecordSourceSurfaceUserDataFunc(void* aUserData) { WrapAndRecordSourceSurfaceUserData* userData = static_cast(aUserData); userData->recorder->RemoveSourceSurface((SourceSurface*)userData->refPtr); userData->recorder->RemoveStoredObject(userData->refPtr); userData->recorder->RecordEvent( RecordedSourceSurfaceDestruction(ReferencePtr(userData->refPtr))); delete userData; } static void StoreSourceSurface(DrawEventRecorderPrivate* aRecorder, SourceSurface* aSurface, DataSourceSurface* aDataSurf, const char* reason) { if (!aDataSurf) { gfxWarning() << "Recording failed to record SourceSurface for " << reason; // Insert a bogus source surface. int32_t stride = aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()); UniquePtr sourceData( new uint8_t[stride * aSurface->GetSize().height]()); aRecorder->RecordEvent(RecordedSourceSurfaceCreation( aSurface, sourceData.get(), stride, aSurface->GetSize(), aSurface->GetFormat())); } else { DataSourceSurface::ScopedMap map(aDataSurf, DataSourceSurface::READ); aRecorder->RecordEvent(RecordedSourceSurfaceCreation( aSurface, map.GetData(), map.GetStride(), aDataSurf->GetSize(), aDataSurf->GetFormat())); } } static void EnsureSurfaceStored(DrawEventRecorderPrivate* aRecorder, SourceSurface* aSurface, const char* reason) { if (aRecorder->HasStoredObject(aSurface)) { return; } RefPtr dataSurf = aSurface->GetDataSurface(); StoreSourceSurface(aRecorder, aSurface, dataSurf, reason); aRecorder->AddStoredObject(aSurface); aRecorder->AddSourceSurface(aSurface); WrapAndRecordSourceSurfaceUserData* userData = new WrapAndRecordSourceSurfaceUserData; userData->refPtr = aSurface; userData->recorder = aRecorder; aSurface->AddUserData(reinterpret_cast(aRecorder), userData, &WrapAndRecordSourceSurfaceUserDataFunc); } class SourceSurfaceWrapAndRecord : public SourceSurface { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceWrapAndRecord, override) SourceSurfaceWrapAndRecord(SourceSurface* aFinalSurface, DrawEventRecorderPrivate* aRecorder) : mFinalSurface(aFinalSurface), mRecorder(aRecorder) { mRecorder->AddStoredObject(this); } ~SourceSurfaceWrapAndRecord() { mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent( RecordedSourceSurfaceDestruction(ReferencePtr(this))); } SurfaceType GetType() const override { return SurfaceType::RECORDING; } IntSize GetSize() const override { return mFinalSurface->GetSize(); } SurfaceFormat GetFormat() const override { return mFinalSurface->GetFormat(); } already_AddRefed GetDataSurface() override { return mFinalSurface->GetDataSurface(); } RefPtr mFinalSurface; RefPtr mRecorder; }; class GradientStopsWrapAndRecord : public GradientStops { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsWrapAndRecord, override) GradientStopsWrapAndRecord(GradientStops* aFinalGradientStops, DrawEventRecorderPrivate* aRecorder) : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder) { mRecorder->AddStoredObject(this); } ~GradientStopsWrapAndRecord() { mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent( RecordedGradientStopsDestruction(ReferencePtr(this))); } BackendType GetBackendType() const override { return BackendType::RECORDING; } RefPtr mFinalGradientStops; RefPtr mRecorder; }; static SourceSurface* GetSourceSurface(SourceSurface* aSurface) { if (aSurface->GetType() != SurfaceType::RECORDING) { return aSurface; } return static_cast(aSurface)->mFinalSurface; } static GradientStops* GetGradientStops(GradientStops* aStops) { if (aStops->GetBackendType() != BackendType::RECORDING) { return aStops; } return static_cast(aStops)->mFinalGradientStops; } class FilterNodeWrapAndRecord : public FilterNode { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeWrapAndRecord, override) using FilterNode::SetAttribute; FilterNodeWrapAndRecord(FilterNode* aFinalFilterNode, DrawEventRecorderPrivate* aRecorder) : mFinalFilterNode(aFinalFilterNode), mRecorder(aRecorder) { mRecorder->AddStoredObject(this); } ~FilterNodeWrapAndRecord() { mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent(RecordedFilterNodeDestruction(ReferencePtr(this))); } static FilterNode* GetFilterNode(FilterNode* aNode) { if (aNode->GetBackendType() != FILTER_BACKEND_RECORDING) { gfxWarning() << "Non recording filter node used with recording DrawTarget!"; return aNode; } return static_cast(aNode)->mFinalFilterNode; } void SetInput(uint32_t aIndex, SourceSurface* aSurface) override { EnsureSurfaceStored(mRecorder, aSurface, "SetInput"); mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface)); mFinalFilterNode->SetInput(aIndex, GetSourceSurface(aSurface)); } void SetInput(uint32_t aIndex, FilterNode* aFilter) override { MOZ_ASSERT(mRecorder->HasStoredObject(aFilter)); mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter)); mFinalFilterNode->SetInput(aIndex, GetFilterNode(aFilter)); } #define FORWARD_SET_ATTRIBUTE(type, argtype) \ void SetAttribute(uint32_t aIndex, type aValue) override { \ mRecorder->RecordEvent(RecordedFilterNodeSetAttribute( \ this, aIndex, aValue, \ RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \ mFinalFilterNode->SetAttribute(aIndex, aValue); \ } FORWARD_SET_ATTRIBUTE(bool, BOOL); FORWARD_SET_ATTRIBUTE(uint32_t, UINT32); FORWARD_SET_ATTRIBUTE(Float, FLOAT); FORWARD_SET_ATTRIBUTE(const Size&, SIZE); FORWARD_SET_ATTRIBUTE(const IntSize&, INTSIZE); FORWARD_SET_ATTRIBUTE(const IntPoint&, INTPOINT); FORWARD_SET_ATTRIBUTE(const Rect&, RECT); FORWARD_SET_ATTRIBUTE(const IntRect&, INTRECT); FORWARD_SET_ATTRIBUTE(const Point&, POINT); FORWARD_SET_ATTRIBUTE(const Matrix&, MATRIX); FORWARD_SET_ATTRIBUTE(const Matrix5x4&, MATRIX5X4); FORWARD_SET_ATTRIBUTE(const Point3D&, POINT3D); FORWARD_SET_ATTRIBUTE(const Color&, COLOR); #undef FORWARD_SET_ATTRIBUTE virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) override { mRecorder->RecordEvent( RecordedFilterNodeSetAttribute(this, aIndex, aFloat, aSize)); mFinalFilterNode->SetAttribute(aIndex, aFloat, aSize); } FilterBackend GetBackendType() override { return FILTER_BACKEND_RECORDING; } RefPtr mFinalFilterNode; RefPtr mRecorder; }; struct AdjustedPattern final { explicit AdjustedPattern(const Pattern& aPattern) : mPattern(nullptr) { mOrigPattern = const_cast(&aPattern); } ~AdjustedPattern() { if (mPattern) { mPattern->~Pattern(); } } operator Pattern*() { switch (mOrigPattern->GetType()) { case PatternType::COLOR: return mOrigPattern; case PatternType::SURFACE: { SurfacePattern* surfPat = static_cast(mOrigPattern); mPattern = new (mSurfPat) SurfacePattern( GetSourceSurface(surfPat->mSurface), surfPat->mExtendMode, surfPat->mMatrix, surfPat->mSamplingFilter, surfPat->mSamplingRect); return mPattern; } case PatternType::LINEAR_GRADIENT: { LinearGradientPattern* linGradPat = static_cast(mOrigPattern); mPattern = new (mLinGradPat) LinearGradientPattern( linGradPat->mBegin, linGradPat->mEnd, GetGradientStops(linGradPat->mStops), linGradPat->mMatrix); return mPattern; } case PatternType::RADIAL_GRADIENT: { RadialGradientPattern* radGradPat = static_cast(mOrigPattern); mPattern = new (mRadGradPat) RadialGradientPattern( radGradPat->mCenter1, radGradPat->mCenter2, radGradPat->mRadius1, radGradPat->mRadius2, GetGradientStops(radGradPat->mStops), radGradPat->mMatrix); return mPattern; } default: return new (mColPat) ColorPattern(Color()); } return mPattern; } union { char mColPat[sizeof(ColorPattern)]; char mLinGradPat[sizeof(LinearGradientPattern)]; char mRadGradPat[sizeof(RadialGradientPattern)]; char mSurfPat[sizeof(SurfacePattern)]; }; Pattern* mOrigPattern; Pattern* mPattern; }; DrawTargetWrapAndRecord::DrawTargetWrapAndRecord(DrawEventRecorder* aRecorder, DrawTarget* aDT, bool aHasData) : mRecorder(static_cast(aRecorder)), mFinalDT(aDT) { RefPtr snapshot = aHasData ? mFinalDT->Snapshot() : nullptr; mRecorder->RecordEvent(RecordedDrawTargetCreation( this, mFinalDT->GetBackendType(), mFinalDT->GetSize(), mFinalDT->GetFormat(), aHasData, snapshot)); mFormat = mFinalDT->GetFormat(); } DrawTargetWrapAndRecord::DrawTargetWrapAndRecord( const DrawTargetWrapAndRecord* aDT, DrawTarget* aSimilarDT) : mRecorder(aDT->mRecorder), mFinalDT(aSimilarDT) { mRecorder->RecordEvent(RecordedCreateSimilarDrawTarget( this, mFinalDT->GetSize(), mFinalDT->GetFormat())); mFormat = mFinalDT->GetFormat(); } DrawTargetWrapAndRecord::~DrawTargetWrapAndRecord() { mRecorder->RecordEvent( RecordedDrawTargetDestruction(static_cast(this))); } void DrawTargetWrapAndRecord::FillRect(const Rect& aRect, const Pattern& aPattern, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aPattern); mRecorder->RecordEvent(RecordedFillRect(this, aRect, aPattern, aOptions)); mFinalDT->FillRect(aRect, *AdjustedPattern(aPattern), aOptions); } void DrawTargetWrapAndRecord::StrokeRect(const Rect& aRect, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aPattern); mRecorder->RecordEvent( RecordedStrokeRect(this, aRect, aPattern, aStrokeOptions, aOptions)); mFinalDT->StrokeRect(aRect, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } void DrawTargetWrapAndRecord::StrokeLine(const Point& aBegin, const Point& aEnd, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aPattern); mRecorder->RecordEvent(RecordedStrokeLine(this, aBegin, aEnd, aPattern, aStrokeOptions, aOptions)); mFinalDT->StrokeLine(aBegin, aEnd, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } void DrawTargetWrapAndRecord::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aOptions) { RefPtr pathWrapAndRecord = EnsurePathStored(aPath); EnsurePatternDependenciesStored(aPattern); mRecorder->RecordEvent( RecordedFill(this, pathWrapAndRecord, aPattern, aOptions)); mFinalDT->Fill(pathWrapAndRecord->mPath, *AdjustedPattern(aPattern), aOptions); } struct WrapAndRecordFontUserData { void* refPtr; RefPtr recorder; }; static void WrapAndRecordFontUserDataDestroyFunc(void* aUserData) { WrapAndRecordFontUserData* userData = static_cast(aUserData); userData->recorder->RecordEvent( RecordedScaledFontDestruction(ReferencePtr(userData->refPtr))); userData->recorder->RemoveScaledFont((ScaledFont*)userData->refPtr); delete userData; } void DrawTargetWrapAndRecord::FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aPattern); UserDataKey* userDataKey = reinterpret_cast(mRecorder.get()); if (!aFont->GetUserData(userDataKey)) { UnscaledFont* unscaledFont = aFont->GetUnscaledFont(); if (!mRecorder->HasStoredObject(unscaledFont)) { RecordedFontData fontData(unscaledFont); RecordedFontDetails fontDetails; if (fontData.GetFontDetails(fontDetails)) { // Try to serialise the whole font, just in case this is a web font that // is not present on the system. if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) { mRecorder->RecordEvent(fontData); mRecorder->AddStoredFontData(fontDetails.fontDataKey); } mRecorder->RecordEvent( RecordedUnscaledFontCreation(unscaledFont, fontDetails)); } else { // If that fails, record just the font description and try to load it // from the system on the other side. RecordedFontDescriptor fontDesc(unscaledFont); if (fontDesc.IsValid()) { mRecorder->RecordEvent(fontDesc); } else { gfxWarning() << "DrawTargetWrapAndRecord::FillGlyphs failed to " "serialise UnscaledFont"; } } mRecorder->AddStoredObject(unscaledFont); } mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, unscaledFont)); WrapAndRecordFontUserData* userData = new WrapAndRecordFontUserData; userData->refPtr = aFont; userData->recorder = mRecorder; aFont->AddUserData(userDataKey, userData, &WrapAndRecordFontUserDataDestroyFunc); userData->recorder->AddScaledFont(aFont); } mRecorder->RecordEvent(RecordedFillGlyphs( this, aFont, aPattern, aOptions, aBuffer.mGlyphs, aBuffer.mNumGlyphs)); mFinalDT->FillGlyphs(aFont, aBuffer, *AdjustedPattern(aPattern), aOptions); } void DrawTargetWrapAndRecord::Mask(const Pattern& aSource, const Pattern& aMask, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aSource); EnsurePatternDependenciesStored(aMask); mRecorder->RecordEvent(RecordedMask(this, aSource, aMask, aOptions)); mFinalDT->Mask(*AdjustedPattern(aSource), *AdjustedPattern(aMask), aOptions); } void DrawTargetWrapAndRecord::MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset, const DrawOptions& aOptions) { EnsurePatternDependenciesStored(aSource); EnsureSurfaceStored(mRecorder, aMask, "MaskSurface"); mRecorder->RecordEvent( RecordedMaskSurface(this, aSource, aMask, aOffset, aOptions)); mFinalDT->MaskSurface(*AdjustedPattern(aSource), GetSourceSurface(aMask), aOffset, aOptions); } void DrawTargetWrapAndRecord::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aOptions) { RefPtr pathWrapAndRecord = EnsurePathStored(aPath); EnsurePatternDependenciesStored(aPattern); mRecorder->RecordEvent(RecordedStroke(this, pathWrapAndRecord, aPattern, aStrokeOptions, aOptions)); mFinalDT->Stroke(pathWrapAndRecord->mPath, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } already_AddRefed DrawTargetWrapAndRecord::Snapshot() { RefPtr surf = mFinalDT->Snapshot(); RefPtr retSurf = new SourceSurfaceWrapAndRecord(surf, mRecorder); mRecorder->RecordEvent(RecordedSnapshot(retSurf, this)); return retSurf.forget(); } already_AddRefed DrawTargetWrapAndRecord::IntoLuminanceSource( LuminanceType aLuminanceType, float aOpacity) { RefPtr surf = mFinalDT->IntoLuminanceSource(aLuminanceType, aOpacity); RefPtr retSurf = new SourceSurfaceWrapAndRecord(surf, mRecorder); mRecorder->RecordEvent( RecordedIntoLuminanceSource(retSurf, this, aLuminanceType, aOpacity)); return retSurf.forget(); } void DrawTargetWrapAndRecord::DetachAllSnapshots() { mFinalDT->DetachAllSnapshots(); } void DrawTargetWrapAndRecord::DrawSurface( SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, const DrawSurfaceOptions& aSurfOptions, const DrawOptions& aOptions) { EnsureSurfaceStored(mRecorder, aSurface, "DrawSurface"); mRecorder->RecordEvent(RecordedDrawSurface(this, aSurface, aDest, aSource, aSurfOptions, aOptions)); mFinalDT->DrawSurface(GetSourceSurface(aSurface), aDest, aSource, aSurfOptions, aOptions); } void DrawTargetWrapAndRecord::DrawSurfaceWithShadow( SourceSurface* aSurface, const Point& aDest, const Color& aColor, const Point& aOffset, Float aSigma, CompositionOp aOp) { EnsureSurfaceStored(mRecorder, aSurface, "DrawSurfaceWithShadow"); mRecorder->RecordEvent(RecordedDrawSurfaceWithShadow( this, aSurface, aDest, aColor, aOffset, aSigma, aOp)); mFinalDT->DrawSurfaceWithShadow(GetSourceSurface(aSurface), aDest, aColor, aOffset, aSigma, aOp); } void DrawTargetWrapAndRecord::DrawFilter(FilterNode* aNode, const Rect& aSourceRect, const Point& aDestPoint, const DrawOptions& aOptions) { MOZ_ASSERT(mRecorder->HasStoredObject(aNode)); mRecorder->RecordEvent( RecordedDrawFilter(this, aNode, aSourceRect, aDestPoint, aOptions)); mFinalDT->DrawFilter(FilterNodeWrapAndRecord::GetFilterNode(aNode), aSourceRect, aDestPoint, aOptions); } already_AddRefed DrawTargetWrapAndRecord::CreateFilter( FilterType aType) { RefPtr node = mFinalDT->CreateFilter(aType); RefPtr retNode = new FilterNodeWrapAndRecord(node, mRecorder); mRecorder->RecordEvent(RecordedFilterNodeCreation(retNode, aType)); return retNode.forget(); } void DrawTargetWrapAndRecord::ClearRect(const Rect& aRect) { mRecorder->RecordEvent(RecordedClearRect(this, aRect)); mFinalDT->ClearRect(aRect); } void DrawTargetWrapAndRecord::CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect, const IntPoint& aDestination) { EnsureSurfaceStored(mRecorder, aSurface, "CopySurface"); mRecorder->RecordEvent( RecordedCopySurface(this, aSurface, aSourceRect, aDestination)); mFinalDT->CopySurface(GetSourceSurface(aSurface), aSourceRect, aDestination); } void DrawTargetWrapAndRecord::PushClip(const Path* aPath) { RefPtr pathWrapAndRecord = EnsurePathStored(aPath); mRecorder->RecordEvent(RecordedPushClip(this, pathWrapAndRecord)); mFinalDT->PushClip(pathWrapAndRecord->mPath); } void DrawTargetWrapAndRecord::PushClipRect(const Rect& aRect) { mRecorder->RecordEvent(RecordedPushClipRect(this, aRect)); mFinalDT->PushClipRect(aRect); } void DrawTargetWrapAndRecord::PopClip() { mRecorder->RecordEvent(RecordedPopClip(static_cast(this))); mFinalDT->PopClip(); } void DrawTargetWrapAndRecord::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask, const Matrix& aMaskTransform, const IntRect& aBounds, bool aCopyBackground) { if (aMask) { EnsureSurfaceStored(mRecorder, aMask, "PushLayer"); } mRecorder->RecordEvent(RecordedPushLayer(this, aOpaque, aOpacity, aMask, aMaskTransform, aBounds, aCopyBackground)); mFinalDT->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, aBounds, aCopyBackground); } void DrawTargetWrapAndRecord::PopLayer() { mRecorder->RecordEvent(RecordedPopLayer(static_cast(this))); mFinalDT->PopLayer(); } already_AddRefed DrawTargetWrapAndRecord::CreateSourceSurfaceFromData( unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) const { RefPtr surf = mFinalDT->CreateSourceSurfaceFromData(aData, aSize, aStride, aFormat); RefPtr retSurf = new SourceSurfaceWrapAndRecord(surf, mRecorder); mRecorder->RecordEvent( RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat)); return retSurf.forget(); } already_AddRefed DrawTargetWrapAndRecord::OptimizeSourceSurface( SourceSurface* aSurface) const { RefPtr surf = mFinalDT->OptimizeSourceSurface(aSurface); RefPtr retSurf = new SourceSurfaceWrapAndRecord(surf, mRecorder); RefPtr dataSurf = surf->GetDataSurface(); if (!dataSurf) { // Let's try get it off the original surface. dataSurf = aSurface->GetDataSurface(); } StoreSourceSurface(mRecorder, retSurf, dataSurf, "OptimizeSourceSurface"); return retSurf.forget(); } already_AddRefed DrawTargetWrapAndRecord::CreateSourceSurfaceFromNativeSurface( const NativeSurface& aSurface) const { RefPtr surf = mFinalDT->CreateSourceSurfaceFromNativeSurface(aSurface); RefPtr retSurf = new SourceSurfaceWrapAndRecord(surf, mRecorder); RefPtr dataSurf = surf->GetDataSurface(); StoreSourceSurface(mRecorder, retSurf, dataSurf, "CreateSourceSurfaceFromNativeSurface"); return retSurf.forget(); } already_AddRefed DrawTargetWrapAndRecord::CreateSimilarDrawTarget( const IntSize& aSize, SurfaceFormat aFormat) const { RefPtr similarDT = mFinalDT->CreateSimilarDrawTarget(aSize, aFormat); if (!similarDT) { return nullptr; } similarDT = new DrawTargetWrapAndRecord(this, similarDT); return similarDT.forget(); } bool DrawTargetWrapAndRecord::CanCreateSimilarDrawTarget( const IntSize& aSize, SurfaceFormat aFormat) const { return mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat); } already_AddRefed DrawTargetWrapAndRecord::CreatePathBuilder( FillRule aFillRule) const { RefPtr builder = mFinalDT->CreatePathBuilder(aFillRule); return MakeAndAddRef(builder, aFillRule); } already_AddRefed DrawTargetWrapAndRecord::CreateGradientStops( GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) const { RefPtr stops = mFinalDT->CreateGradientStops(aStops, aNumStops, aExtendMode); RefPtr retStops = new GradientStopsWrapAndRecord(stops, mRecorder); mRecorder->RecordEvent( RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode)); return retStops.forget(); } void DrawTargetWrapAndRecord::SetTransform(const Matrix& aTransform) { mRecorder->RecordEvent(RecordedSetTransform(this, aTransform)); DrawTarget::SetTransform(aTransform); mFinalDT->SetTransform(aTransform); } already_AddRefed DrawTargetWrapAndRecord::EnsurePathStored( const Path* aPath) { RefPtr pathWrapAndRecord; if (aPath->GetBackendType() == BackendType::RECORDING) { pathWrapAndRecord = const_cast(static_cast(aPath)); if (mRecorder->HasStoredObject(aPath)) { return pathWrapAndRecord.forget(); } } else { MOZ_ASSERT(!mRecorder->HasStoredObject(aPath)); FillRule fillRule = aPath->GetFillRule(); RefPtr builder = mFinalDT->CreatePathBuilder(fillRule); RefPtr builderWrapAndRecord = new PathBuilderRecording(builder, fillRule); aPath->StreamToSink(builderWrapAndRecord); pathWrapAndRecord = builderWrapAndRecord->Finish().downcast(); } mRecorder->RecordEvent(RecordedPathCreation(pathWrapAndRecord.get())); mRecorder->AddStoredObject(pathWrapAndRecord); pathWrapAndRecord->mStoredRecorders.push_back(mRecorder); return pathWrapAndRecord.forget(); } void DrawTargetWrapAndRecord::EnsurePatternDependenciesStored( const Pattern& aPattern) { switch (aPattern.GetType()) { case PatternType::COLOR: // No dependencies here. return; case PatternType::LINEAR_GRADIENT: { MOZ_ASSERT(mRecorder->HasStoredObject( static_cast(&aPattern)->mStops)); return; } case PatternType::RADIAL_GRADIENT: { MOZ_ASSERT(mRecorder->HasStoredObject( static_cast(&aPattern)->mStops)); return; } case PatternType::SURFACE: { const SurfacePattern* pat = static_cast(&aPattern); EnsureSurfaceStored(mRecorder, pat->mSurface, "EnsurePatternDependenciesStored"); return; } } } } // namespace gfx } // namespace mozilla