diff options
Diffstat (limited to 'gfx/2d/DrawTargetRecording.cpp')
-rw-r--r-- | gfx/2d/DrawTargetRecording.cpp | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/gfx/2d/DrawTargetRecording.cpp b/gfx/2d/DrawTargetRecording.cpp new file mode 100644 index 000000000..b8eda90fe --- /dev/null +++ b/gfx/2d/DrawTargetRecording.cpp @@ -0,0 +1,737 @@ +/* -*- Mode: C++; tab-width: 20; 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 "DrawTargetRecording.h" +#include "PathRecording.h" +#include <stdio.h> + +#include "Logging.h" +#include "Tools.h" +#include "Filters.h" +#include "mozilla/UniquePtr.h" +#include "RecordingTypes.h" + +namespace mozilla { +namespace gfx { + +struct RecordingSourceSurfaceUserData +{ + void *refPtr; + RefPtr<DrawEventRecorderPrivate> recorder; +}; + +void RecordingSourceSurfaceUserDataFunc(void *aUserData) +{ + RecordingSourceSurfaceUserData *userData = + static_cast<RecordingSourceSurfaceUserData*>(aUserData); + + userData->recorder->RemoveStoredObject(userData->refPtr); + userData->recorder->RecordEvent( + RecordedSourceSurfaceDestruction(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<uint8_t[]> 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<DataSourceSurface> dataSurf = aSurface->GetDataSurface(); + StoreSourceSurface(aRecorder, aSurface, dataSurf, reason); + aRecorder->AddStoredObject(aSurface); + + RecordingSourceSurfaceUserData *userData = new RecordingSourceSurfaceUserData; + userData->refPtr = aSurface; + userData->recorder = aRecorder; + aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder), + userData, &RecordingSourceSurfaceUserDataFunc); + return; +} + +class SourceSurfaceRecording : public SourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording) + SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder) + : mFinalSurface(aFinalSurface), mRecorder(aRecorder) + { + mRecorder->AddStoredObject(this); + } + + ~SourceSurfaceRecording() + { + mRecorder->RemoveStoredObject(this); + mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this)); + } + + virtual SurfaceType GetType() const { return SurfaceType::RECORDING; } + virtual IntSize GetSize() const { return mFinalSurface->GetSize(); } + virtual SurfaceFormat GetFormat() const { return mFinalSurface->GetFormat(); } + virtual already_AddRefed<DataSourceSurface> GetDataSurface() { return mFinalSurface->GetDataSurface(); } + + RefPtr<SourceSurface> mFinalSurface; + RefPtr<DrawEventRecorderPrivate> mRecorder; +}; + +class GradientStopsRecording : public GradientStops +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording) + GradientStopsRecording(GradientStops *aFinalGradientStops, DrawEventRecorderPrivate *aRecorder) + : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder) + { + mRecorder->AddStoredObject(this); + } + + ~GradientStopsRecording() + { + mRecorder->RemoveStoredObject(this); + mRecorder->RecordEvent(RecordedGradientStopsDestruction(this)); + } + + virtual BackendType GetBackendType() const { return BackendType::RECORDING; } + + RefPtr<GradientStops> mFinalGradientStops; + RefPtr<DrawEventRecorderPrivate> mRecorder; +}; + +static SourceSurface * +GetSourceSurface(SourceSurface *aSurface) +{ + if (aSurface->GetType() != SurfaceType::RECORDING) { + return aSurface; + } + + return static_cast<SourceSurfaceRecording*>(aSurface)->mFinalSurface; +} + +static GradientStops * +GetGradientStops(GradientStops *aStops) +{ + if (aStops->GetBackendType() != BackendType::RECORDING) { + return aStops; + } + + return static_cast<GradientStopsRecording*>(aStops)->mFinalGradientStops; +} + +class FilterNodeRecording : public FilterNode +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording, override) + using FilterNode::SetAttribute; + + FilterNodeRecording(FilterNode *aFinalFilterNode, DrawEventRecorderPrivate *aRecorder) + : mFinalFilterNode(aFinalFilterNode), mRecorder(aRecorder) + { + mRecorder->AddStoredObject(this); + } + + ~FilterNodeRecording() + { + mRecorder->RemoveStoredObject(this); + mRecorder->RecordEvent(RecordedFilterNodeDestruction(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<FilterNodeRecording*>(aNode)->mFinalFilterNode; + } + + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) override + { + EnsureSurfaceStored(mRecorder, aSurface, "SetInput"); + + mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface)); + mFinalFilterNode->SetInput(aIndex, GetSourceSurface(aSurface)); + } + virtual 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) \ + virtual 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); + } + + virtual FilterBackend GetBackendType() override { return FILTER_BACKEND_RECORDING; } + + RefPtr<FilterNode> mFinalFilterNode; + RefPtr<DrawEventRecorderPrivate> mRecorder; +}; + +struct AdjustedPattern +{ + explicit AdjustedPattern(const Pattern &aPattern) + : mPattern(nullptr) + { + mOrigPattern = const_cast<Pattern*>(&aPattern); + } + + ~AdjustedPattern() { + if (mPattern) { + mPattern->~Pattern(); + } + } + + operator Pattern*() + { + switch(mOrigPattern->GetType()) { + case PatternType::COLOR: + return mOrigPattern; + case PatternType::SURFACE: + { + SurfacePattern *surfPat = static_cast<SurfacePattern*>(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<LinearGradientPattern*>(mOrigPattern); + mPattern = + new (mLinGradPat) LinearGradientPattern(linGradPat->mBegin, linGradPat->mEnd, + GetGradientStops(linGradPat->mStops), + linGradPat->mMatrix); + return mPattern; + } + case PatternType::RADIAL_GRADIENT: + { + RadialGradientPattern *radGradPat = static_cast<RadialGradientPattern*>(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; +}; + +DrawTargetRecording::DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData) + : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder)) + , mFinalDT(aDT) +{ + RefPtr<SourceSurface> snapshot = aHasData ? mFinalDT->Snapshot() : nullptr; + mRecorder->RecordEvent(RecordedDrawTargetCreation(this, + mFinalDT->GetBackendType(), + mFinalDT->GetSize(), + mFinalDT->GetFormat(), + aHasData, snapshot)); + mFormat = mFinalDT->GetFormat(); +} + +DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording *aDT, + DrawTarget *aSimilarDT) + : mRecorder(aDT->mRecorder) + , mFinalDT(aSimilarDT) +{ + mRecorder->RecordEvent(RecordedCreateSimilarDrawTarget(this, + mFinalDT->GetSize(), + mFinalDT->GetFormat())); + mFormat = mFinalDT->GetFormat(); +} + +DrawTargetRecording::~DrawTargetRecording() +{ + mRecorder->RecordEvent(RecordedDrawTargetDestruction(this)); +} + +void +DrawTargetRecording::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 +DrawTargetRecording::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 +DrawTargetRecording::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 +DrawTargetRecording::Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); + EnsurePatternDependenciesStored(aPattern); + + mRecorder->RecordEvent(RecordedFill(this, pathRecording, aPattern, aOptions)); + mFinalDT->Fill(pathRecording->mPath, *AdjustedPattern(aPattern), aOptions); +} + +struct RecordingFontUserData +{ + void *refPtr; + RefPtr<DrawEventRecorderPrivate> recorder; +}; + +void RecordingFontUserDataDestroyFunc(void *aUserData) +{ + RecordingFontUserData *userData = + static_cast<RecordingFontUserData*>(aUserData); + + userData->recorder->RecordEvent(RecordedScaledFontDestruction(userData->refPtr)); + + delete userData; +} + +void +DrawTargetRecording::FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions, + const GlyphRenderingOptions *aRenderingOptions) +{ + EnsurePatternDependenciesStored(aPattern); + + if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) { + RecordedFontData fontData(aFont); + 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(RecordedScaledFontCreation(aFont, fontDetails)); + } else { + // If that fails, record just the font description and try to load it from + // the system on the other side. + RecordedFontDescriptor fontDesc(aFont); + if (fontDesc.IsValid()) { + mRecorder->RecordEvent(fontDesc); + } else { + gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise ScaledFont"; + } + } + RecordingFontUserData *userData = new RecordingFontUserData; + userData->refPtr = aFont; + userData->recorder = mRecorder; + aFont->AddUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()), userData, + &RecordingFontUserDataDestroyFunc); + } + + mRecorder->RecordEvent(RecordedFillGlyphs(this, aFont, aPattern, aOptions, aBuffer.mGlyphs, aBuffer.mNumGlyphs)); + mFinalDT->FillGlyphs(aFont, aBuffer, *AdjustedPattern(aPattern), aOptions, aRenderingOptions); +} + +void +DrawTargetRecording::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 +DrawTargetRecording::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 +DrawTargetRecording::Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); + EnsurePatternDependenciesStored(aPattern); + + mRecorder->RecordEvent(RecordedStroke(this, pathRecording, aPattern, aStrokeOptions, aOptions)); + mFinalDT->Stroke(pathRecording->mPath, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); +} + +already_AddRefed<SourceSurface> +DrawTargetRecording::Snapshot() +{ + RefPtr<SourceSurface> surf = mFinalDT->Snapshot(); + + RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(surf, mRecorder); + + mRecorder->RecordEvent(RecordedSnapshot(retSurf, this)); + + return retSurf.forget(); +} + +void +DrawTargetRecording::DetachAllSnapshots() +{ + mFinalDT->DetachAllSnapshots(); +} + +void +DrawTargetRecording::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 +DrawTargetRecording::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 +DrawTargetRecording::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(FilterNodeRecording::GetFilterNode(aNode), aSourceRect, aDestPoint, aOptions); +} + +already_AddRefed<FilterNode> +DrawTargetRecording::CreateFilter(FilterType aType) +{ + RefPtr<FilterNode> node = mFinalDT->CreateFilter(aType); + + RefPtr<FilterNode> retNode = new FilterNodeRecording(node, mRecorder); + + mRecorder->RecordEvent(RecordedFilterNodeCreation(retNode, aType)); + + return retNode.forget(); +} + +void +DrawTargetRecording::ClearRect(const Rect &aRect) +{ + mRecorder->RecordEvent(RecordedClearRect(this, aRect)); + mFinalDT->ClearRect(aRect); +} + +void +DrawTargetRecording::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 +DrawTargetRecording::PushClip(const Path *aPath) +{ + RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath); + + mRecorder->RecordEvent(RecordedPushClip(this, pathRecording)); + mFinalDT->PushClip(pathRecording->mPath); +} + +void +DrawTargetRecording::PushClipRect(const Rect &aRect) +{ + mRecorder->RecordEvent(RecordedPushClipRect(this, aRect)); + mFinalDT->PushClipRect(aRect); +} + +void +DrawTargetRecording::PopClip() +{ + mRecorder->RecordEvent(RecordedPopClip(this)); + mFinalDT->PopClip(); +} + +void +DrawTargetRecording::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 +DrawTargetRecording::PopLayer() +{ + mRecorder->RecordEvent(RecordedPopLayer(this)); + mFinalDT->PopLayer(); +} + +already_AddRefed<SourceSurface> +DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr<SourceSurface> surf = mFinalDT->CreateSourceSurfaceFromData(aData, aSize, aStride, aFormat); + + RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(surf, mRecorder); + + mRecorder->RecordEvent(RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat)); + + return retSurf.forget(); +} + +already_AddRefed<SourceSurface> +DrawTargetRecording::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + RefPtr<SourceSurface> surf = mFinalDT->OptimizeSourceSurface(aSurface); + + RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(surf, mRecorder); + + RefPtr<DataSourceSurface> 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<SourceSurface> +DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const +{ + RefPtr<SourceSurface> surf = mFinalDT->CreateSourceSurfaceFromNativeSurface(aSurface); + + RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(surf, mRecorder); + + RefPtr<DataSourceSurface> dataSurf = surf->GetDataSurface(); + StoreSourceSurface(mRecorder, retSurf, dataSurf, "CreateSourceSurfaceFromNativeSurface"); + + return retSurf.forget(); +} + +already_AddRefed<DrawTarget> +DrawTargetRecording::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + RefPtr<DrawTarget> similarDT = + mFinalDT->CreateSimilarDrawTarget(aSize, aFormat); + if (!similarDT) { + return nullptr; + } + + similarDT = new DrawTargetRecording(this, similarDT); + return similarDT.forget(); +} + +already_AddRefed<PathBuilder> +DrawTargetRecording::CreatePathBuilder(FillRule aFillRule) const +{ + RefPtr<PathBuilder> builder = mFinalDT->CreatePathBuilder(aFillRule); + return MakeAndAddRef<PathBuilderRecording>(builder, aFillRule); +} + +already_AddRefed<GradientStops> +DrawTargetRecording::CreateGradientStops(GradientStop *aStops, + uint32_t aNumStops, + ExtendMode aExtendMode) const +{ + RefPtr<GradientStops> stops = mFinalDT->CreateGradientStops(aStops, aNumStops, aExtendMode); + + RefPtr<GradientStops> retStops = new GradientStopsRecording(stops, mRecorder); + + mRecorder->RecordEvent(RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode)); + + return retStops.forget(); +} + +void +DrawTargetRecording::SetTransform(const Matrix &aTransform) +{ + mRecorder->RecordEvent(RecordedSetTransform(this, aTransform)); + DrawTarget::SetTransform(aTransform); + mFinalDT->SetTransform(aTransform); +} + +already_AddRefed<PathRecording> +DrawTargetRecording::EnsurePathStored(const Path *aPath) +{ + RefPtr<PathRecording> pathRecording; + if (aPath->GetBackendType() == BackendType::RECORDING) { + pathRecording = const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath)); + if (mRecorder->HasStoredObject(aPath)) { + return pathRecording.forget(); + } + } else { + MOZ_ASSERT(!mRecorder->HasStoredObject(aPath)); + FillRule fillRule = aPath->GetFillRule(); + RefPtr<PathBuilder> builder = mFinalDT->CreatePathBuilder(fillRule); + RefPtr<PathBuilderRecording> builderRecording = + new PathBuilderRecording(builder, fillRule); + aPath->StreamToSink(builderRecording); + pathRecording = builderRecording->Finish().downcast<PathRecording>(); + } + + mRecorder->RecordEvent(RecordedPathCreation(pathRecording)); + mRecorder->AddStoredObject(pathRecording); + pathRecording->mStoredRecorders.push_back(mRecorder); + + return pathRecording.forget(); +} + +void +DrawTargetRecording::EnsurePatternDependenciesStored(const Pattern &aPattern) +{ + switch (aPattern.GetType()) { + case PatternType::COLOR: + // No dependencies here. + return; + case PatternType::LINEAR_GRADIENT: + { + MOZ_ASSERT(mRecorder->HasStoredObject(static_cast<const LinearGradientPattern*>(&aPattern)->mStops)); + return; + } + case PatternType::RADIAL_GRADIENT: + { + MOZ_ASSERT(mRecorder->HasStoredObject(static_cast<const RadialGradientPattern*>(&aPattern)->mStops)); + return; + } + case PatternType::SURFACE: + { + const SurfacePattern *pat = static_cast<const SurfacePattern*>(&aPattern); + EnsureSurfaceStored(mRecorder, pat->mSurface, "EnsurePatternDependenciesStored"); + return; + } + } +} + +} // namespace gfx +} // namespace mozilla |