summaryrefslogtreecommitdiffstats
path: root/gfx/2d/RecordedEvent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/RecordedEvent.cpp')
-rw-r--r--gfx/2d/RecordedEvent.cpp1883
1 files changed, 1883 insertions, 0 deletions
diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp
new file mode 100644
index 000000000..3bfc5c8f6
--- /dev/null
+++ b/gfx/2d/RecordedEvent.cpp
@@ -0,0 +1,1883 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "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 {
+
+using namespace std;
+
+static std::string NameFromBackend(BackendType aType)
+{
+ switch (aType) {
+ case BackendType::NONE:
+ return "None";
+ case BackendType::DIRECT2D:
+ return "Direct2D";
+ default:
+ return "Unknown";
+ }
+}
+
+already_AddRefed<DrawTarget>
+Translator::CreateDrawTarget(ReferencePtr aRefPtr, const IntSize &aSize,
+ SurfaceFormat aFormat)
+{
+ RefPtr<DrawTarget> newDT =
+ GetReferenceDrawTarget()->CreateSimilarDrawTarget(aSize, aFormat);
+ AddDrawTarget(aRefPtr, newDT);
+ return newDT.forget();
+}
+
+#define LOAD_EVENT_TYPE(_typeenum, _class) \
+ case _typeenum: return new _class(aStream)
+
+RecordedEvent *
+RecordedEvent::LoadEventFromStream(std::istream &aStream, EventType aType)
+{
+ switch (aType) {
+ LOAD_EVENT_TYPE(DRAWTARGETCREATION, RecordedDrawTargetCreation);
+ LOAD_EVENT_TYPE(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction);
+ LOAD_EVENT_TYPE(FILLRECT, RecordedFillRect);
+ LOAD_EVENT_TYPE(STROKERECT, RecordedStrokeRect);
+ LOAD_EVENT_TYPE(STROKELINE, RecordedStrokeLine);
+ LOAD_EVENT_TYPE(CLEARRECT, RecordedClearRect);
+ LOAD_EVENT_TYPE(COPYSURFACE, RecordedCopySurface);
+ LOAD_EVENT_TYPE(SETTRANSFORM, RecordedSetTransform);
+ LOAD_EVENT_TYPE(PUSHCLIPRECT, RecordedPushClipRect);
+ LOAD_EVENT_TYPE(PUSHCLIP, RecordedPushClip);
+ LOAD_EVENT_TYPE(POPCLIP, RecordedPopClip);
+ LOAD_EVENT_TYPE(FILL, RecordedFill);
+ LOAD_EVENT_TYPE(FILLGLYPHS, RecordedFillGlyphs);
+ LOAD_EVENT_TYPE(MASK, RecordedMask);
+ LOAD_EVENT_TYPE(STROKE, RecordedStroke);
+ LOAD_EVENT_TYPE(DRAWSURFACE, RecordedDrawSurface);
+ LOAD_EVENT_TYPE(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow);
+ LOAD_EVENT_TYPE(DRAWFILTER, RecordedDrawFilter);
+ LOAD_EVENT_TYPE(PATHCREATION, RecordedPathCreation);
+ LOAD_EVENT_TYPE(PATHDESTRUCTION, RecordedPathDestruction);
+ LOAD_EVENT_TYPE(SOURCESURFACECREATION, RecordedSourceSurfaceCreation);
+ LOAD_EVENT_TYPE(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction);
+ LOAD_EVENT_TYPE(FILTERNODECREATION, RecordedFilterNodeCreation);
+ LOAD_EVENT_TYPE(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction);
+ LOAD_EVENT_TYPE(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation);
+ LOAD_EVENT_TYPE(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction);
+ LOAD_EVENT_TYPE(SNAPSHOT, RecordedSnapshot);
+ LOAD_EVENT_TYPE(SCALEDFONTCREATION, RecordedScaledFontCreation);
+ LOAD_EVENT_TYPE(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction);
+ LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface);
+ LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute);
+ LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput);
+ LOAD_EVENT_TYPE(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget);
+ LOAD_EVENT_TYPE(FONTDATA, RecordedFontData);
+ LOAD_EVENT_TYPE(FONTDESC, RecordedFontDescriptor);
+ LOAD_EVENT_TYPE(PUSHLAYER, RecordedPushLayer);
+ LOAD_EVENT_TYPE(POPLAYER, RecordedPopLayer);
+ default:
+ return nullptr;
+ }
+}
+
+string
+RecordedEvent::GetEventName(EventType aType)
+{
+ switch (aType) {
+ case DRAWTARGETCREATION:
+ return "DrawTarget Creation";
+ case DRAWTARGETDESTRUCTION:
+ return "DrawTarget Destruction";
+ case FILLRECT:
+ return "FillRect";
+ case STROKERECT:
+ return "StrokeRect";
+ case STROKELINE:
+ return "StrokeLine";
+ case CLEARRECT:
+ return "ClearRect";
+ case COPYSURFACE:
+ return "CopySurface";
+ case SETTRANSFORM:
+ return "SetTransform";
+ case PUSHCLIP:
+ return "PushClip";
+ case PUSHCLIPRECT:
+ return "PushClipRect";
+ case POPCLIP:
+ return "PopClip";
+ case FILL:
+ return "Fill";
+ case FILLGLYPHS:
+ return "FillGlyphs";
+ case MASK:
+ return "Mask";
+ case STROKE:
+ return "Stroke";
+ case DRAWSURFACE:
+ return "DrawSurface";
+ case DRAWSURFACEWITHSHADOW:
+ return "DrawSurfaceWithShadow";
+ case DRAWFILTER:
+ return "DrawFilter";
+ case PATHCREATION:
+ return "PathCreation";
+ case PATHDESTRUCTION:
+ return "PathDestruction";
+ case SOURCESURFACECREATION:
+ return "SourceSurfaceCreation";
+ case SOURCESURFACEDESTRUCTION:
+ return "SourceSurfaceDestruction";
+ case FILTERNODECREATION:
+ return "FilterNodeCreation";
+ case FILTERNODEDESTRUCTION:
+ return "FilterNodeDestruction";
+ case GRADIENTSTOPSCREATION:
+ return "GradientStopsCreation";
+ case GRADIENTSTOPSDESTRUCTION:
+ return "GradientStopsDestruction";
+ case SNAPSHOT:
+ return "Snapshot";
+ case SCALEDFONTCREATION:
+ return "ScaledFontCreation";
+ case SCALEDFONTDESTRUCTION:
+ return "ScaledFontDestruction";
+ case MASKSURFACE:
+ return "MaskSurface";
+ case FILTERNODESETATTRIBUTE:
+ return "SetAttribute";
+ case FILTERNODESETINPUT:
+ return "SetInput";
+ case CREATESIMILARDRAWTARGET:
+ return "CreateSimilarDrawTarget";
+ case FONTDATA:
+ return "FontData";
+ case FONTDESC:
+ return "FontDescriptor";
+ case PUSHLAYER:
+ return "PushLayer";
+ case POPLAYER:
+ return "PopLayer";
+ default:
+ return "Unknown";
+ }
+}
+
+void
+RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
+{
+ WriteElement(aStream, aPattern.mType);
+
+ switch (aPattern.mType) {
+ case PatternType::COLOR:
+ {
+ WriteElement(aStream, *reinterpret_cast<const ColorPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ {
+ WriteElement(aStream, *reinterpret_cast<const LinearGradientPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::RADIAL_GRADIENT:
+ {
+ WriteElement(aStream, *reinterpret_cast<const RadialGradientPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::SURFACE:
+ {
+ WriteElement(aStream, *reinterpret_cast<const SurfacePatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ default:
+ return;
+ }
+}
+
+void
+RecordedEvent::ReadPatternData(std::istream &aStream, PatternStorage &aPattern) const
+{
+ ReadElement(aStream, aPattern.mType);
+
+ switch (aPattern.mType) {
+ case PatternType::COLOR:
+ {
+ ReadElement(aStream, *reinterpret_cast<ColorPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ {
+ ReadElement(aStream, *reinterpret_cast<LinearGradientPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::RADIAL_GRADIENT:
+ {
+ ReadElement(aStream, *reinterpret_cast<RadialGradientPatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ case PatternType::SURFACE:
+ {
+ ReadElement(aStream, *reinterpret_cast<SurfacePatternStorage*>(&aPattern.mStorage));
+ return;
+ }
+ default:
+ return;
+ }
+}
+
+void
+RecordedEvent::StorePattern(PatternStorage &aDestination, const Pattern &aSource) const
+{
+ aDestination.mType = aSource.GetType();
+
+ switch (aSource.GetType()) {
+ case PatternType::COLOR:
+ {
+ reinterpret_cast<ColorPatternStorage*>(&aDestination.mStorage)->mColor =
+ static_cast<const ColorPattern*>(&aSource)->mColor;
+ return;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ {
+ LinearGradientPatternStorage *store =
+ reinterpret_cast<LinearGradientPatternStorage*>(&aDestination.mStorage);
+ const LinearGradientPattern *pat =
+ static_cast<const LinearGradientPattern*>(&aSource);
+ store->mBegin = pat->mBegin;
+ store->mEnd = pat->mEnd;
+ store->mMatrix = pat->mMatrix;
+ store->mStops = pat->mStops.get();
+ return;
+ }
+ case PatternType::RADIAL_GRADIENT:
+ {
+ RadialGradientPatternStorage *store =
+ reinterpret_cast<RadialGradientPatternStorage*>(&aDestination.mStorage);
+ const RadialGradientPattern *pat =
+ static_cast<const RadialGradientPattern*>(&aSource);
+ store->mCenter1 = pat->mCenter1;
+ store->mCenter2 = pat->mCenter2;
+ store->mRadius1 = pat->mRadius1;
+ store->mRadius2 = pat->mRadius2;
+ store->mMatrix = pat->mMatrix;
+ store->mStops = pat->mStops.get();
+ return;
+ }
+ case PatternType::SURFACE:
+ {
+ SurfacePatternStorage *store =
+ reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage);
+ const SurfacePattern *pat =
+ static_cast<const SurfacePattern*>(&aSource);
+ store->mExtend = pat->mExtendMode;
+ store->mSamplingFilter = pat->mSamplingFilter;
+ store->mMatrix = pat->mMatrix;
+ store->mSurface = pat->mSurface;
+ store->mSamplingRect = pat->mSamplingRect;
+ return;
+ }
+ }
+}
+
+void
+RecordedEvent::RecordStrokeOptions(std::ostream &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);
+}
+
+void
+RecordedEvent::ReadStrokeOptions(std::istream &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);
+ ReadElement(aStream, joinStyle);
+ ReadElement(aStream, capStyle);
+ // 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) {
+ return;
+ }
+
+ mDashPatternStorage.resize(aStrokeOptions.mDashLength);
+ aStrokeOptions.mDashPattern = &mDashPatternStorage.front();
+ aStream.read((char*)aStrokeOptions.mDashPattern, sizeof(Float) * aStrokeOptions.mDashLength);
+}
+
+void
+RecordedEvent::OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const
+{
+ switch (aStorage.mType) {
+ case PatternType::COLOR:
+ {
+ const Color color = reinterpret_cast<const ColorPatternStorage*>(&aStorage.mStorage)->mColor;
+ aOutput << "Color: (" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")";
+ return;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ {
+ const LinearGradientPatternStorage *store =
+ reinterpret_cast<const LinearGradientPatternStorage*>(&aStorage.mStorage);
+
+ aOutput << "LinearGradient (" << store->mBegin.x << ", " << store->mBegin.y <<
+ ") - (" << store->mEnd.x << ", " << store->mEnd.y << ") Stops: " << store->mStops;
+ return;
+ }
+ case PatternType::RADIAL_GRADIENT:
+ {
+ const RadialGradientPatternStorage *store =
+ reinterpret_cast<const RadialGradientPatternStorage*>(&aStorage.mStorage);
+ aOutput << "RadialGradient (Center 1: (" << store->mCenter1.x << ", " <<
+ store->mCenter2.y << ") Radius 2: " << store->mRadius2;
+ return;
+ }
+ case PatternType::SURFACE:
+ {
+ const SurfacePatternStorage *store =
+ reinterpret_cast<const SurfacePatternStorage*>(&aStorage.mStorage);
+ aOutput << "Surface (0x" << store->mSurface << ")";
+ return;
+ }
+ }
+}
+
+RecordedDrawingEvent::RecordedDrawingEvent(EventType aType, std::istream &aStream)
+ : RecordedEvent(aType)
+{
+ ReadElement(aStream, mDT);
+}
+
+void
+RecordedDrawingEvent::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mDT);
+}
+
+ReferencePtr
+RecordedDrawingEvent::GetObjectRef() const
+{
+ return mDT;
+}
+
+bool
+RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<DrawTarget> newDT =
+ aTranslator->CreateDrawTarget(mRefPtr, 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;
+ }
+
+ if (mHasExistingData) {
+ Rect dataRect(0, 0, mExistingData->GetSize().width, mExistingData->GetSize().height);
+ newDT->DrawSurface(mExistingData, dataRect, dataRect);
+ }
+
+ return true;
+}
+
+void
+RecordedDrawTargetCreation::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mBackendType);
+ WriteElement(aStream, mSize);
+ WriteElement(aStream, mFormat);
+ WriteElement(aStream, mHasExistingData);
+
+ if (mHasExistingData) {
+ MOZ_ASSERT(mExistingData);
+ MOZ_ASSERT(mExistingData->GetSize() == mSize);
+ RefPtr<DataSourceSurface> dataSurf = mExistingData->GetDataSurface();
+ for (int y = 0; y < mSize.height; y++) {
+ aStream.write((const char*)dataSurf->GetData() + y * dataSurf->Stride(),
+ BytesPerPixel(mFormat) * mSize.width);
+ }
+ }
+}
+
+RecordedDrawTargetCreation::RecordedDrawTargetCreation(istream &aStream)
+ : RecordedEvent(DRAWTARGETCREATION)
+ , mExistingData(nullptr)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mBackendType);
+ ReadElement(aStream, mSize);
+ ReadElement(aStream, mFormat);
+ ReadElement(aStream, mHasExistingData);
+
+ if (mHasExistingData) {
+ RefPtr<DataSourceSurface> dataSurf = Factory::CreateDataSourceSurface(mSize, mFormat);
+ if (!dataSurf) {
+ gfxWarning() << "RecordedDrawTargetCreation had to reset mHasExistingData";
+ mHasExistingData = false;
+ return;
+ }
+
+ for (int y = 0; y < mSize.height; y++) {
+ aStream.read((char*)dataSurf->GetData() + y * dataSurf->Stride(),
+ BytesPerPixel(mFormat) * mSize.width);
+ }
+ mExistingData = dataSurf;
+ }
+}
+
+void
+RecordedDrawTargetCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] DrawTarget Creation (Type: " << NameFromBackend(mBackendType) << ", Size: " << mSize.width << "x" << mSize.height << ")";
+}
+
+
+bool
+RecordedDrawTargetDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemoveDrawTarget(mRefPtr);
+ return true;
+}
+
+void
+RecordedDrawTargetDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedDrawTargetDestruction::RecordedDrawTargetDestruction(istream &aStream)
+ : RecordedEvent(DRAWTARGETDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedDrawTargetDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] DrawTarget Destruction";
+}
+
+bool
+RecordedCreateSimilarDrawTarget::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<DrawTarget> newDT =
+ aTranslator->GetReferenceDrawTarget()->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;
+}
+
+void
+RecordedCreateSimilarDrawTarget::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mSize);
+ WriteElement(aStream, mFormat);
+}
+
+RecordedCreateSimilarDrawTarget::RecordedCreateSimilarDrawTarget(istream &aStream)
+ : RecordedEvent(CREATESIMILARDRAWTARGET)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mSize);
+ ReadElement(aStream, mFormat);
+}
+
+void
+RecordedCreateSimilarDrawTarget::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] CreateSimilarDrawTarget (Size: " << mSize.width << "x" << mSize.height << ")";
+}
+
+struct GenericPattern
+{
+ GenericPattern(const PatternStorage &aStorage, Translator *aTranslator)
+ : mPattern(nullptr), mTranslator(aTranslator)
+ {
+ mStorage = const_cast<PatternStorage*>(&aStorage);
+ }
+
+ ~GenericPattern() {
+ if (mPattern) {
+ mPattern->~Pattern();
+ }
+ }
+
+ operator Pattern*()
+ {
+ switch(mStorage->mType) {
+ case PatternType::COLOR:
+ return new (mColPat) ColorPattern(reinterpret_cast<ColorPatternStorage*>(&mStorage->mStorage)->mColor);
+ case PatternType::SURFACE:
+ {
+ SurfacePatternStorage *storage = reinterpret_cast<SurfacePatternStorage*>(&mStorage->mStorage);
+ mPattern =
+ new (mSurfPat) SurfacePattern(mTranslator->LookupSourceSurface(storage->mSurface),
+ storage->mExtend, storage->mMatrix,
+ storage->mSamplingFilter,
+ storage->mSamplingRect);
+ return mPattern;
+ }
+ case PatternType::LINEAR_GRADIENT:
+ {
+ LinearGradientPatternStorage *storage = reinterpret_cast<LinearGradientPatternStorage*>(&mStorage->mStorage);
+ mPattern =
+ new (mLinGradPat) LinearGradientPattern(storage->mBegin, storage->mEnd,
+ mTranslator->LookupGradientStops(storage->mStops),
+ storage->mMatrix);
+ return mPattern;
+ }
+ case PatternType::RADIAL_GRADIENT:
+ {
+ RadialGradientPatternStorage *storage = reinterpret_cast<RadialGradientPatternStorage*>(&mStorage->mStorage);
+ mPattern =
+ new (mRadGradPat) RadialGradientPattern(storage->mCenter1, storage->mCenter2,
+ storage->mRadius1, storage->mRadius2,
+ mTranslator->LookupGradientStops(storage->mStops),
+ storage->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)];
+ };
+
+ PatternStorage *mStorage;
+ Pattern *mPattern;
+ Translator *mTranslator;
+};
+
+bool
+RecordedFillRect::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->FillRect(mRect, *GenericPattern(mPattern, aTranslator), mOptions);
+ return true;
+}
+
+void
+RecordedFillRect::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRect);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+}
+
+RecordedFillRect::RecordedFillRect(istream &aStream)
+ : RecordedDrawingEvent(FILLRECT, aStream)
+{
+ ReadElement(aStream, mRect);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+}
+
+void
+RecordedFillRect::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] FillRect (" << mRect.x << ", " << mRect.y << " - " << mRect.width << " x " << mRect.height << ") ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+bool
+RecordedStrokeRect::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->StrokeRect(mRect, *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+ return true;
+}
+
+void
+RecordedStrokeRect::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRect);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+ RecordStrokeOptions(aStream, mStrokeOptions);
+}
+
+RecordedStrokeRect::RecordedStrokeRect(istream &aStream)
+ : RecordedDrawingEvent(STROKERECT, aStream)
+{
+ ReadElement(aStream, mRect);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+ ReadStrokeOptions(aStream, mStrokeOptions);
+}
+
+void
+RecordedStrokeRect::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] StrokeRect (" << mRect.x << ", " << mRect.y << " - " << mRect.width << " x " << mRect.height
+ << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+bool
+RecordedStrokeLine::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->StrokeLine(mBegin, mEnd, *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+ return true;
+}
+
+void
+RecordedStrokeLine::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mBegin);
+ WriteElement(aStream, mEnd);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+ RecordStrokeOptions(aStream, mStrokeOptions);
+}
+
+RecordedStrokeLine::RecordedStrokeLine(istream &aStream)
+ : RecordedDrawingEvent(STROKELINE, aStream)
+{
+ ReadElement(aStream, mBegin);
+ ReadElement(aStream, mEnd);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+ ReadStrokeOptions(aStream, mStrokeOptions);
+}
+
+void
+RecordedStrokeLine::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] StrokeLine (" << mBegin.x << ", " << mBegin.y << " - " << mEnd.x << ", " << mEnd.y
+ << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+bool
+RecordedFill::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->Fill(aTranslator->LookupPath(mPath), *GenericPattern(mPattern, aTranslator), mOptions);
+ return true;
+}
+
+RecordedFill::RecordedFill(istream &aStream)
+ : RecordedDrawingEvent(FILL, aStream)
+{
+ ReadElement(aStream, mPath);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+}
+
+void
+RecordedFill::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mPath);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+}
+
+void
+RecordedFill::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] Fill (" << mPath << ") ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+RecordedFillGlyphs::~RecordedFillGlyphs()
+{
+ delete [] mGlyphs;
+}
+
+bool
+RecordedFillGlyphs::PlayEvent(Translator *aTranslator) const
+{
+ GlyphBuffer buffer;
+ buffer.mGlyphs = mGlyphs;
+ buffer.mNumGlyphs = mNumGlyphs;
+ aTranslator->LookupDrawTarget(mDT)->FillGlyphs(aTranslator->LookupScaledFont(mScaledFont), buffer, *GenericPattern(mPattern, aTranslator), mOptions);
+ return true;
+}
+
+RecordedFillGlyphs::RecordedFillGlyphs(istream &aStream)
+ : RecordedDrawingEvent(FILLGLYPHS, aStream)
+{
+ ReadElement(aStream, mScaledFont);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+ ReadElement(aStream, mNumGlyphs);
+ mGlyphs = new Glyph[mNumGlyphs];
+ aStream.read((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs);
+}
+
+void
+RecordedFillGlyphs::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mScaledFont);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+ WriteElement(aStream, mNumGlyphs);
+ aStream.write((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs);
+}
+
+void
+RecordedFillGlyphs::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] FillGlyphs (" << mScaledFont << ") ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+bool
+RecordedMask::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->Mask(*GenericPattern(mSource, aTranslator), *GenericPattern(mMask, aTranslator), mOptions);
+ return true;
+}
+
+RecordedMask::RecordedMask(istream &aStream)
+ : RecordedDrawingEvent(MASK, aStream)
+{
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mSource);
+ ReadPatternData(aStream, mMask);
+}
+
+void
+RecordedMask::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mSource);
+ RecordPatternData(aStream, mMask);
+}
+
+void
+RecordedMask::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] Mask (Source: ";
+ OutputSimplePatternInfo(mSource, aStringStream);
+ aStringStream << " Mask: ";
+ OutputSimplePatternInfo(mMask, aStringStream);
+}
+
+bool
+RecordedStroke::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->Stroke(aTranslator->LookupPath(mPath), *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+ return true;
+}
+
+void
+RecordedStroke::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mPath);
+ WriteElement(aStream, mOptions);
+ RecordPatternData(aStream, mPattern);
+ RecordStrokeOptions(aStream, mStrokeOptions);
+}
+
+RecordedStroke::RecordedStroke(istream &aStream)
+ : RecordedDrawingEvent(STROKE, aStream)
+{
+ ReadElement(aStream, mPath);
+ ReadElement(aStream, mOptions);
+ ReadPatternData(aStream, mPattern);
+ ReadStrokeOptions(aStream, mStrokeOptions);
+}
+
+void
+RecordedStroke::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] Stroke ("<< mPath << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+bool
+RecordedClearRect::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->ClearRect(mRect);
+ return true;
+}
+
+void
+RecordedClearRect::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRect);
+}
+
+RecordedClearRect::RecordedClearRect(istream &aStream)
+ : RecordedDrawingEvent(CLEARRECT, aStream)
+{
+ ReadElement(aStream, mRect);
+}
+
+void
+RecordedClearRect::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT<< "] ClearRect (" << mRect.x << ", " << mRect.y << " - " << mRect.width << " x " << mRect.height << ") ";
+}
+
+bool
+RecordedCopySurface::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->CopySurface(aTranslator->LookupSourceSurface(mSourceSurface),
+ mSourceRect, mDest);
+ return true;
+}
+
+void
+RecordedCopySurface::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mSourceSurface);
+ WriteElement(aStream, mSourceRect);
+ WriteElement(aStream, mDest);
+}
+
+RecordedCopySurface::RecordedCopySurface(istream &aStream)
+ : RecordedDrawingEvent(COPYSURFACE, aStream)
+{
+ ReadElement(aStream, mSourceSurface);
+ ReadElement(aStream, mSourceRect);
+ ReadElement(aStream, mDest);
+}
+
+void
+RecordedCopySurface::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT<< "] CopySurface (" << mSourceSurface << ")";
+}
+
+bool
+RecordedPushClip::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->PushClip(aTranslator->LookupPath(mPath));
+ return true;
+}
+
+void
+RecordedPushClip::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mPath);
+}
+
+RecordedPushClip::RecordedPushClip(istream &aStream)
+ : RecordedDrawingEvent(PUSHCLIP, aStream)
+{
+ ReadElement(aStream, mPath);
+}
+
+void
+RecordedPushClip::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] PushClip (" << mPath << ") ";
+}
+
+bool
+RecordedPushClipRect::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->PushClipRect(mRect);
+ return true;
+}
+
+void
+RecordedPushClipRect::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRect);
+}
+
+RecordedPushClipRect::RecordedPushClipRect(istream &aStream)
+ : RecordedDrawingEvent(PUSHCLIPRECT, aStream)
+{
+ ReadElement(aStream, mRect);
+}
+
+void
+RecordedPushClipRect::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] PushClipRect (" << mRect.x << ", " << mRect.y << " - " << mRect.width << " x " << mRect.height << ") ";
+}
+
+bool
+RecordedPopClip::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->PopClip();
+ return true;
+}
+
+void
+RecordedPopClip::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+}
+
+RecordedPopClip::RecordedPopClip(istream &aStream)
+ : RecordedDrawingEvent(POPCLIP, aStream)
+{
+}
+
+void
+RecordedPopClip::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] PopClip";
+}
+
+bool
+RecordedPushLayer::PlayEvent(Translator *aTranslator) const
+{
+ SourceSurface* mask = mMask ? aTranslator->LookupSourceSurface(mMask)
+ : nullptr;
+ aTranslator->LookupDrawTarget(mDT)->
+ PushLayer(mOpaque, mOpacity, mask, mMaskTransform, mBounds, mCopyBackground);
+ return true;
+}
+
+void
+RecordedPushLayer::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mOpaque);
+ WriteElement(aStream, mOpacity);
+ WriteElement(aStream, mMask);
+ WriteElement(aStream, mMaskTransform);
+ WriteElement(aStream, mBounds);
+ WriteElement(aStream, mCopyBackground);
+}
+
+RecordedPushLayer::RecordedPushLayer(istream &aStream)
+ : RecordedDrawingEvent(PUSHLAYER, aStream)
+{
+ ReadElement(aStream, mOpaque);
+ ReadElement(aStream, mOpacity);
+ ReadElement(aStream, mMask);
+ ReadElement(aStream, mMaskTransform);
+ ReadElement(aStream, mBounds);
+ ReadElement(aStream, mCopyBackground);
+}
+
+void
+RecordedPushLayer::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] PushPLayer (Opaque=" << mOpaque <<
+ ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") ";
+}
+
+bool
+RecordedPopLayer::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->PopLayer();
+ return true;
+}
+
+void
+RecordedPopLayer::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+}
+
+RecordedPopLayer::RecordedPopLayer(istream &aStream)
+ : RecordedDrawingEvent(POPLAYER, aStream)
+{
+}
+
+void
+RecordedPopLayer::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] PopLayer";
+}
+
+bool
+RecordedSetTransform::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->SetTransform(mTransform);
+ return true;
+}
+
+void
+RecordedSetTransform::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mTransform);
+}
+
+RecordedSetTransform::RecordedSetTransform(istream &aStream)
+ : RecordedDrawingEvent(SETTRANSFORM, aStream)
+{
+ ReadElement(aStream, mTransform);
+}
+
+void
+RecordedSetTransform::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] SetTransform [ " << mTransform._11 << " " << mTransform._12 << " ; " <<
+ mTransform._21 << " " << mTransform._22 << " ; " << mTransform._31 << " " << mTransform._32 << " ]";
+}
+
+bool
+RecordedDrawSurface::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->
+ DrawSurface(aTranslator->LookupSourceSurface(mRefSource), mDest, mSource,
+ mDSOptions, mOptions);
+ return true;
+}
+
+void
+RecordedDrawSurface::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRefSource);
+ WriteElement(aStream, mDest);
+ WriteElement(aStream, mSource);
+ WriteElement(aStream, mDSOptions);
+ WriteElement(aStream, mOptions);
+}
+
+RecordedDrawSurface::RecordedDrawSurface(istream &aStream)
+ : RecordedDrawingEvent(DRAWSURFACE, aStream)
+{
+ ReadElement(aStream, mRefSource);
+ ReadElement(aStream, mDest);
+ ReadElement(aStream, mSource);
+ ReadElement(aStream, mDSOptions);
+ ReadElement(aStream, mOptions);
+}
+
+void
+RecordedDrawSurface::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] DrawSurface (" << mRefSource << ")";
+}
+
+bool
+RecordedDrawFilter::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->
+ DrawFilter(aTranslator->LookupFilterNode(mNode), mSourceRect,
+ mDestPoint, mOptions);
+ return true;
+}
+
+void
+RecordedDrawFilter::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mNode);
+ WriteElement(aStream, mSourceRect);
+ WriteElement(aStream, mDestPoint);
+ WriteElement(aStream, mOptions);
+}
+
+RecordedDrawFilter::RecordedDrawFilter(istream &aStream)
+ : RecordedDrawingEvent(DRAWFILTER, aStream)
+{
+ ReadElement(aStream, mNode);
+ ReadElement(aStream, mSourceRect);
+ ReadElement(aStream, mDestPoint);
+ ReadElement(aStream, mOptions);
+}
+
+void
+RecordedDrawFilter::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] DrawFilter (" << mNode << ")";
+}
+
+bool
+RecordedDrawSurfaceWithShadow::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->
+ DrawSurfaceWithShadow(aTranslator->LookupSourceSurface(mRefSource),
+ mDest, mColor, mOffset, mSigma, mOp);
+ return true;
+}
+
+void
+RecordedDrawSurfaceWithShadow::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ WriteElement(aStream, mRefSource);
+ WriteElement(aStream, mDest);
+ WriteElement(aStream, mColor);
+ WriteElement(aStream, mOffset);
+ WriteElement(aStream, mSigma);
+ WriteElement(aStream, mOp);
+}
+
+RecordedDrawSurfaceWithShadow::RecordedDrawSurfaceWithShadow(istream &aStream)
+ : RecordedDrawingEvent(DRAWSURFACEWITHSHADOW, aStream)
+{
+ ReadElement(aStream, mRefSource);
+ ReadElement(aStream, mDest);
+ ReadElement(aStream, mColor);
+ ReadElement(aStream, mOffset);
+ ReadElement(aStream, mSigma);
+ ReadElement(aStream, mOp);
+}
+
+void
+RecordedDrawSurfaceWithShadow::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] DrawSurfaceWithShadow (" << mRefSource << ") Color: (" <<
+ mColor.r << ", " << mColor.g << ", " << mColor.b << ", " << mColor.a << ")";
+}
+
+RecordedPathCreation::RecordedPathCreation(PathRecording *aPath)
+ : RecordedEvent(PATHCREATION), mRefPtr(aPath), mFillRule(aPath->mFillRule), mPathOps(aPath->mPathOps)
+{
+}
+
+RecordedPathCreation::~RecordedPathCreation()
+{
+}
+
+bool
+RecordedPathCreation::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<PathBuilder> builder =
+ aTranslator->GetReferenceDrawTarget()->CreatePathBuilder(mFillRule);
+
+ for (size_t i = 0; i < mPathOps.size(); i++) {
+ const PathOp &op = mPathOps[i];
+ switch (op.mType) {
+ case PathOp::OP_MOVETO:
+ builder->MoveTo(op.mP1);
+ break;
+ case PathOp::OP_LINETO:
+ builder->LineTo(op.mP1);
+ break;
+ case PathOp::OP_BEZIERTO:
+ builder->BezierTo(op.mP1, op.mP2, op.mP3);
+ break;
+ case PathOp::OP_QUADRATICBEZIERTO:
+ builder->QuadraticBezierTo(op.mP1, op.mP2);
+ break;
+ case PathOp::OP_CLOSE:
+ builder->Close();
+ break;
+ }
+ }
+
+ RefPtr<Path> path = builder->Finish();
+ aTranslator->AddPath(mRefPtr, path);
+ return true;
+}
+
+void
+RecordedPathCreation::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, uint64_t(mPathOps.size()));
+ WriteElement(aStream, mFillRule);
+ typedef std::vector<PathOp> pathOpVec;
+ for (pathOpVec::const_iterator iter = mPathOps.begin(); iter != mPathOps.end(); iter++) {
+ WriteElement(aStream, iter->mType);
+ if (sPointCount[iter->mType] >= 1) {
+ WriteElement(aStream, iter->mP1);
+ }
+ if (sPointCount[iter->mType] >= 2) {
+ WriteElement(aStream, iter->mP2);
+ }
+ if (sPointCount[iter->mType] >= 3) {
+ WriteElement(aStream, iter->mP3);
+ }
+ }
+
+}
+
+RecordedPathCreation::RecordedPathCreation(istream &aStream)
+ : RecordedEvent(PATHCREATION)
+{
+ uint64_t size;
+
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, size);
+ ReadElement(aStream, mFillRule);
+
+ for (uint64_t i = 0; i < size; i++) {
+ PathOp newPathOp;
+ ReadElement(aStream, newPathOp.mType);
+ if (sPointCount[newPathOp.mType] >= 1) {
+ ReadElement(aStream, newPathOp.mP1);
+ }
+ if (sPointCount[newPathOp.mType] >= 2) {
+ ReadElement(aStream, newPathOp.mP2);
+ }
+ if (sPointCount[newPathOp.mType] >= 3) {
+ ReadElement(aStream, newPathOp.mP3);
+ }
+
+ mPathOps.push_back(newPathOp);
+ }
+
+}
+
+void
+RecordedPathCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] Path created (OpCount: " << mPathOps.size() << ")";
+}
+bool
+RecordedPathDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemovePath(mRefPtr);
+ return true;
+}
+
+void
+RecordedPathDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedPathDestruction::RecordedPathDestruction(istream &aStream)
+ : RecordedEvent(PATHDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedPathDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] Path Destroyed";
+}
+
+RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation()
+{
+ if (mDataOwned) {
+ delete [] mData;
+ }
+}
+
+bool
+RecordedSourceSurfaceCreation::PlayEvent(Translator *aTranslator) const
+{
+ if (!mData) {
+ return false;
+ }
+
+ RefPtr<SourceSurface> src = aTranslator->GetReferenceDrawTarget()->
+ CreateSourceSurfaceFromData(mData, mSize, mSize.width * BytesPerPixel(mFormat), mFormat);
+ aTranslator->AddSourceSurface(mRefPtr, src);
+ return true;
+}
+
+void
+RecordedSourceSurfaceCreation::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mSize);
+ WriteElement(aStream, mFormat);
+ MOZ_ASSERT(mData);
+ for (int y = 0; y < mSize.height; y++) {
+ aStream.write((const char*)mData + y * mStride, BytesPerPixel(mFormat) * mSize.width);
+ }
+}
+
+RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(istream &aStream)
+ : RecordedEvent(SOURCESURFACECREATION), mDataOwned(true)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mSize);
+ ReadElement(aStream, mFormat);
+ mData = (uint8_t*)new (fallible) char[mSize.width * mSize.height * BytesPerPixel(mFormat)];
+ if (!mData) {
+ gfxWarning() << "RecordedSourceSurfaceCreation failed to allocate data";
+ } else {
+ aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat));
+ }
+}
+
+void
+RecordedSourceSurfaceCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] SourceSurface created (Size: " << mSize.width << "x" << mSize.height << ")";
+}
+
+bool
+RecordedSourceSurfaceDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemoveSourceSurface(mRefPtr);
+ return true;
+}
+
+void
+RecordedSourceSurfaceDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedSourceSurfaceDestruction::RecordedSourceSurfaceDestruction(istream &aStream)
+ : RecordedEvent(SOURCESURFACEDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedSourceSurfaceDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] SourceSurface Destroyed";
+}
+
+RecordedFilterNodeCreation::~RecordedFilterNodeCreation()
+{
+}
+
+bool
+RecordedFilterNodeCreation::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<FilterNode> node = aTranslator->GetReferenceDrawTarget()->
+ CreateFilter(mType);
+ aTranslator->AddFilterNode(mRefPtr, node);
+ return true;
+}
+
+void
+RecordedFilterNodeCreation::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mType);
+}
+
+RecordedFilterNodeCreation::RecordedFilterNodeCreation(istream &aStream)
+ : RecordedEvent(FILTERNODECREATION)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mType);
+}
+
+void
+RecordedFilterNodeCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] FilterNode created (Type: " << int(mType) << ")";
+}
+
+bool
+RecordedFilterNodeDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemoveFilterNode(mRefPtr);
+ return true;
+}
+
+void
+RecordedFilterNodeDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedFilterNodeDestruction::RecordedFilterNodeDestruction(istream &aStream)
+ : RecordedEvent(FILTERNODEDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedFilterNodeDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] FilterNode Destroyed";
+}
+
+RecordedGradientStopsCreation::~RecordedGradientStopsCreation()
+{
+ if (mDataOwned) {
+ delete [] mStops;
+ }
+}
+
+bool
+RecordedGradientStopsCreation::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<GradientStops> src = aTranslator->GetReferenceDrawTarget()->
+ CreateGradientStops(mStops, mNumStops, mExtendMode);
+ aTranslator->AddGradientStops(mRefPtr, src);
+ return true;
+}
+
+void
+RecordedGradientStopsCreation::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mExtendMode);
+ WriteElement(aStream, mNumStops);
+ aStream.write((const char*)mStops, mNumStops * sizeof(GradientStop));
+}
+
+RecordedGradientStopsCreation::RecordedGradientStopsCreation(istream &aStream)
+ : RecordedEvent(GRADIENTSTOPSCREATION), mDataOwned(true)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mExtendMode);
+ ReadElement(aStream, mNumStops);
+ mStops = new GradientStop[mNumStops];
+
+ aStream.read((char*)mStops, mNumStops * sizeof(GradientStop));
+}
+
+void
+RecordedGradientStopsCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] GradientStops created (Stops: " << mNumStops << ")";
+}
+
+bool
+RecordedGradientStopsDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemoveGradientStops(mRefPtr);
+ return true;
+}
+
+void
+RecordedGradientStopsDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedGradientStopsDestruction::RecordedGradientStopsDestruction(istream &aStream)
+ : RecordedEvent(GRADIENTSTOPSDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedGradientStopsDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] GradientStops Destroyed";
+}
+
+bool
+RecordedSnapshot::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<SourceSurface> src = aTranslator->LookupDrawTarget(mDT)->Snapshot();
+ aTranslator->AddSourceSurface(mRefPtr, src);
+ return true;
+}
+
+void
+RecordedSnapshot::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mDT);
+}
+
+RecordedSnapshot::RecordedSnapshot(istream &aStream)
+ : RecordedEvent(SNAPSHOT)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mDT);
+}
+
+void
+RecordedSnapshot::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] Snapshot Created (DT: " << mDT << ")";
+}
+
+RecordedFontData::~RecordedFontData()
+{
+ delete[] mData;
+}
+
+bool
+RecordedFontData::PlayEvent(Translator *aTranslator) const
+{
+ RefPtr<NativeFontResource> fontResource =
+ Factory::CreateNativeFontResource(mData, mFontDetails.size,
+ aTranslator->GetDesiredFontType());
+ if (!fontResource) {
+ return false;
+ }
+
+ aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource);
+ return true;
+}
+
+void
+RecordedFontData::RecordToStream(std::ostream &aStream) const
+{
+ MOZ_ASSERT(mGetFontFileDataSucceeded);
+
+ WriteElement(aStream, mFontDetails.fontDataKey);
+ WriteElement(aStream, mFontDetails.size);
+ aStream.write((const char*)mData, mFontDetails.size);
+}
+
+void
+RecordedFontData::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "Font Data of size " << mFontDetails.size;
+}
+
+void
+RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize)
+{
+ mData = new uint8_t[aSize];
+ memcpy(mData, aData, aSize);
+ mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize);
+ mFontDetails.size = aSize;
+ mFontDetails.index = aIndex;
+ mFontDetails.glyphSize = aGlyphSize;
+}
+
+bool
+RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails)
+{
+ if (!mGetFontFileDataSucceeded) {
+ return false;
+ }
+
+ fontDetails.fontDataKey = mFontDetails.fontDataKey;
+ fontDetails.size = mFontDetails.size;
+ fontDetails.glyphSize = mFontDetails.glyphSize;
+ fontDetails.index = mFontDetails.index;
+ return true;
+}
+
+RecordedFontData::RecordedFontData(istream &aStream)
+ : RecordedEvent(FONTDATA)
+{
+ ReadElement(aStream, mFontDetails.fontDataKey);
+ ReadElement(aStream, mFontDetails.size);
+ mData = new uint8_t[mFontDetails.size];
+ aStream.read((char*)mData, mFontDetails.size);
+}
+
+RecordedFontDescriptor::~RecordedFontDescriptor()
+{
+}
+
+bool
+RecordedFontDescriptor::PlayEvent(Translator *aTranslator) const
+{
+ MOZ_ASSERT(mType == FontType::GDI);
+
+ NativeFont nativeFont;
+ nativeFont.mType = (NativeFontType)mType;
+ nativeFont.mFont = (void*)&mData[0];
+
+ RefPtr<ScaledFont> font =
+ Factory::CreateScaledFontForNativeFont(nativeFont, mFontSize);
+
+#ifdef USE_CAIRO_SCALED_FONT
+ static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
+#endif
+
+ aTranslator->AddScaledFont(mRefPtr, font);
+ return true;
+}
+
+void
+RecordedFontDescriptor::RecordToStream(std::ostream &aStream) const
+{
+ MOZ_ASSERT(mHasDesc);
+ WriteElement(aStream, mType);
+ WriteElement(aStream, mFontSize);
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, (size_t)mData.size());
+ aStream.write((char*)&mData[0], mData.size());
+}
+
+void
+RecordedFontDescriptor::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] Font Descriptor";
+}
+
+void
+RecordedFontDescriptor::SetFontDescriptor(const uint8_t* aData, uint32_t aSize, Float aFontSize)
+{
+ mData.assign(aData, aData + aSize);
+ mFontSize = aFontSize;
+}
+
+RecordedFontDescriptor::RecordedFontDescriptor(istream &aStream)
+ : RecordedEvent(FONTDATA)
+{
+ ReadElement(aStream, mType);
+ ReadElement(aStream, mFontSize);
+ ReadElement(aStream, mRefPtr);
+
+ size_t size;
+ ReadElement(aStream, size);
+ mData.resize(size);
+ aStream.read((char*)&mData[0], size);
+}
+
+bool
+RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
+{
+ NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey);
+ if (!fontResource) {
+ gfxDevCrash(LogReason::NativeFontResourceNotFound) <<
+ "NativeFontResource lookup failed for key |" << hexa(mFontDataKey) << "|.";
+ return false;
+ }
+
+ RefPtr<ScaledFont> scaledFont =
+ fontResource->CreateScaledFont(mIndex, mGlyphSize, mInstanceData.data(), mInstanceData.size());
+ aTranslator->AddScaledFont(mRefPtr, scaledFont);
+ return true;
+}
+
+void
+RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+ WriteElement(aStream, mFontDataKey);
+ WriteElement(aStream, mIndex);
+ WriteElement(aStream, mGlyphSize);
+ WriteElement(aStream, (size_t)mInstanceData.size());
+ aStream.write((char*)mInstanceData.data(), mInstanceData.size());
+}
+
+void
+RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] ScaledFont Created";
+}
+
+void
+RecordedScaledFontCreation::SetFontInstanceData(const uint8_t *aData, uint32_t aSize)
+{
+ mInstanceData.assign(aData, aData + aSize);
+}
+
+RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream)
+ : RecordedEvent(SCALEDFONTCREATION)
+{
+ ReadElement(aStream, mRefPtr);
+ ReadElement(aStream, mFontDataKey);
+ ReadElement(aStream, mIndex);
+ ReadElement(aStream, mGlyphSize);
+
+ size_t size;
+ ReadElement(aStream, size);
+ mInstanceData.resize(size);
+ aStream.read((char*)mInstanceData.data(), size);
+}
+
+bool
+RecordedScaledFontDestruction::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->RemoveScaledFont(mRefPtr);
+ return true;
+}
+
+void
+RecordedScaledFontDestruction::RecordToStream(ostream &aStream) const
+{
+ WriteElement(aStream, mRefPtr);
+}
+
+RecordedScaledFontDestruction::RecordedScaledFontDestruction(istream &aStream)
+ : RecordedEvent(SCALEDFONTDESTRUCTION)
+{
+ ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedScaledFontDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mRefPtr << "] ScaledFont Destroyed";
+}
+
+bool
+RecordedMaskSurface::PlayEvent(Translator *aTranslator) const
+{
+ aTranslator->LookupDrawTarget(mDT)->
+ MaskSurface(*GenericPattern(mPattern, aTranslator),
+ aTranslator->LookupSourceSurface(mRefMask),
+ mOffset, mOptions);
+ return true;
+}
+
+void
+RecordedMaskSurface::RecordToStream(ostream &aStream) const
+{
+ RecordedDrawingEvent::RecordToStream(aStream);
+ RecordPatternData(aStream, mPattern);
+ WriteElement(aStream, mRefMask);
+ WriteElement(aStream, mOffset);
+ WriteElement(aStream, mOptions);
+}
+
+RecordedMaskSurface::RecordedMaskSurface(istream &aStream)
+ : RecordedDrawingEvent(MASKSURFACE, aStream)
+{
+ ReadPatternData(aStream, mPattern);
+ ReadElement(aStream, mRefMask);
+ ReadElement(aStream, mOffset);
+ ReadElement(aStream, mOptions);
+}
+
+void
+RecordedMaskSurface::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mDT << "] MaskSurface (" << mRefMask << ") Offset: (" << mOffset.x << "x" << mOffset.y << ") Pattern: ";
+ OutputSimplePatternInfo(mPattern, aStringStream);
+}
+
+template<typename T>
+void
+ReplaySetAttribute(FilterNode *aNode, uint32_t aIndex, T aValue)
+{
+ aNode->SetAttribute(aIndex, aValue);
+}
+
+bool
+RecordedFilterNodeSetAttribute::PlayEvent(Translator *aTranslator) const
+{
+#define REPLAY_SET_ATTRIBUTE(type, argtype) \
+ case ARGTYPE_##argtype: \
+ ReplaySetAttribute(aTranslator->LookupFilterNode(mNode), 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(Color, COLOR);
+ case ARGTYPE_FLOAT_ARRAY:
+ aTranslator->LookupFilterNode(mNode)->SetAttribute(
+ mIndex,
+ reinterpret_cast<const Float*>(&mPayload.front()),
+ mPayload.size() / sizeof(Float));
+ break;
+ }
+
+ return true;
+}
+
+void
+RecordedFilterNodeSetAttribute::RecordToStream(ostream &aStream) const
+{
+ RecordedEvent::RecordToStream(aStream);
+ WriteElement(aStream, mNode);
+ WriteElement(aStream, mIndex);
+ WriteElement(aStream, mArgType);
+ WriteElement(aStream, uint64_t(mPayload.size()));
+ aStream.write((const char*)&mPayload.front(), mPayload.size());
+}
+
+RecordedFilterNodeSetAttribute::RecordedFilterNodeSetAttribute(istream &aStream)
+ : RecordedEvent(FILTERNODESETATTRIBUTE)
+{
+ ReadElement(aStream, mNode);
+ ReadElement(aStream, mIndex);
+ ReadElement(aStream, mArgType);
+ uint64_t size;
+ ReadElement(aStream, size);
+ mPayload.resize(size_t(size));
+ aStream.read((char*)&mPayload.front(), size);
+}
+
+void
+RecordedFilterNodeSetAttribute::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ")";
+}
+
+bool
+RecordedFilterNodeSetInput::PlayEvent(Translator *aTranslator) const
+{
+ if (mInputFilter) {
+ aTranslator->LookupFilterNode(mNode)->SetInput(
+ mIndex, aTranslator->LookupFilterNode(mInputFilter));
+ } else {
+ aTranslator->LookupFilterNode(mNode)->SetInput(
+ mIndex, aTranslator->LookupSourceSurface(mInputSurface));
+ }
+
+ return true;
+}
+
+void
+RecordedFilterNodeSetInput::RecordToStream(ostream &aStream) const
+{
+ RecordedEvent::RecordToStream(aStream);
+ WriteElement(aStream, mNode);
+ WriteElement(aStream, mIndex);
+ WriteElement(aStream, mInputFilter);
+ WriteElement(aStream, mInputSurface);
+}
+
+RecordedFilterNodeSetInput::RecordedFilterNodeSetInput(istream &aStream)
+ : RecordedEvent(FILTERNODESETINPUT)
+{
+ ReadElement(aStream, mNode);
+ ReadElement(aStream, mIndex);
+ ReadElement(aStream, mInputFilter);
+ ReadElement(aStream, mInputSurface);
+}
+
+void
+RecordedFilterNodeSetInput::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+ aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ", ";
+
+ if (mInputFilter) {
+ aStringStream << "Filter: " << mInputFilter;
+ } else {
+ aStringStream << "Surface: " << mInputSurface;
+ }
+
+ aStringStream << ")";
+}
+
+} // namespace gfx
+} // namespace mozilla